Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 433da04

Browse files
authored
Merge pull request #80 from cdr/integration-tests
Framework for integration tests
2 parents 65fce15 + 692b219 commit 433da04

File tree

27 files changed

+738
-13
lines changed

27 files changed

+738
-13
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
name: build
2-
32
on: [push]
43

54
jobs:
@@ -9,7 +8,7 @@ jobs:
98
- name: Checkout
109
uses: actions/checkout@v1
1110
- name: Build
12-
run: ./ci/build.sh
11+
run: ./ci/steps/build.sh
1312
- name: Upload
1413
uses: actions/upload-artifact@v2
1514
with:

.github/workflows/integration.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: integration
2+
on:
3+
push:
4+
schedule:
5+
- cron: '*/180 * * * *'
6+
7+
jobs:
8+
integration:
9+
runs-on: ubuntu-latest
10+
env:
11+
CODER_URL: ${{ secrets.CODER_URL }}
12+
CODER_EMAIL: ${{ secrets.CODER_EMAIL }}
13+
CODER_PASSWORD: ${{ secrets.CODER_PASSWORD }}
14+
steps:
15+
- uses: actions/checkout@v1
16+
- uses: actions/cache@v1
17+
with:
18+
path: ~/go/pkg/mod
19+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
20+
restore-keys: |
21+
${{ runner.os }}-go-
22+
- uses: actions/setup-go@v2
23+
with:
24+
go-version: '^1.14'
25+
- name: go test
26+
run: go test -v ./ci/integration/...

.github/workflows/test.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: test
2+
on: [push]
3+
4+
jobs:
5+
fmt:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v1
9+
- uses: actions/cache@v1
10+
with:
11+
path: ~/go/pkg/mod
12+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
13+
restore-keys: |
14+
${{ runner.os }}-go-
15+
- name: fmt
16+
uses: ./ci/image
17+
with:
18+
args: ./ci/steps/fmt.sh
19+
lint:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v1
23+
- uses: actions/cache@v1
24+
with:
25+
path: ~/go/pkg/mod
26+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
27+
restore-keys: |
28+
${{ runner.os }}-go-
29+
- name: lint
30+
uses: ./ci/image
31+
with:
32+
args: ./ci/steps/lint.sh
33+
test:
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v1
37+
- uses: actions/cache@v1
38+
with:
39+
path: ~/go/pkg/mod
40+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
41+
restore-keys: |
42+
${{ runner.os }}-go-
43+
- name: test
44+
uses: ./ci/image
45+
with:
46+
args: go test ./internal/... ./cmd/...

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.idea
22
ci/bin
33
cmd/coder/coder
4+
ci/integration/bin
5+
ci/integration/env.sh

ci/image/Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM golang:1
2+
3+
ENV GOFLAGS="-mod=readonly"
4+
ENV CI=true
5+
6+
RUN go get golang.org/x/tools/cmd/goimports
7+
RUN go get golang.org/x/lint/golint
8+
RUN go get github.com/mattn/goveralls

ci/integration/integration_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"strings"
10+
"testing"
11+
"time"
12+
13+
"cdr.dev/coder-cli/ci/tcli"
14+
"cdr.dev/slog/sloggers/slogtest/assert"
15+
)
16+
17+
func build(path string) error {
18+
cmd := exec.Command(
19+
"sh", "-c",
20+
fmt.Sprintf("cd ../../ && go build -o %s ./cmd/coder", path),
21+
)
22+
cmd.Env = append(os.Environ(), "GOOS=linux", "CGO_ENABLED=0")
23+
24+
_, err := cmd.CombinedOutput()
25+
if err != nil {
26+
return err
27+
}
28+
return nil
29+
}
30+
31+
var binpath string
32+
33+
func init() {
34+
cwd, err := os.Getwd()
35+
if err != nil {
36+
panic(err)
37+
}
38+
39+
binpath = filepath.Join(cwd, "bin", "coder")
40+
err = build(binpath)
41+
if err != nil {
42+
panic(err)
43+
}
44+
}
45+
46+
// write session tokens to the given container runner
47+
func headlessLogin(ctx context.Context, t *testing.T, runner *tcli.ContainerRunner) {
48+
creds := login(ctx, t)
49+
cmd := exec.CommandContext(ctx, "sh", "-c", "mkdir -p ~/.config/coder && cat > ~/.config/coder/session")
50+
51+
// !IMPORTANT: be careful that this does not appear in logs
52+
cmd.Stdin = strings.NewReader(creds.token)
53+
runner.RunCmd(cmd).Assert(t,
54+
tcli.Success(),
55+
)
56+
runner.Run(ctx, fmt.Sprintf("echo -ne %s > ~/.config/coder/url", creds.url)).Assert(t,
57+
tcli.Success(),
58+
)
59+
}
60+
61+
func TestCoderCLI(t *testing.T) {
62+
t.Parallel()
63+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
64+
defer cancel()
65+
66+
c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{
67+
Image: "codercom/enterprise-dev",
68+
Name: "coder-cli-tests",
69+
BindMounts: map[string]string{
70+
binpath: "/bin/coder",
71+
},
72+
})
73+
assert.Success(t, "new run container", err)
74+
defer c.Close()
75+
76+
c.Run(ctx, "which coder").Assert(t,
77+
tcli.Success(),
78+
tcli.StdoutMatches("/usr/sbin/coder"),
79+
tcli.StderrEmpty(),
80+
)
81+
82+
c.Run(ctx, "coder version").Assert(t,
83+
tcli.StderrEmpty(),
84+
tcli.Success(),
85+
tcli.StdoutMatches("linux"),
86+
)
87+
88+
c.Run(ctx, "coder help").Assert(t,
89+
tcli.Success(),
90+
tcli.StderrMatches("Commands:"),
91+
tcli.StderrMatches("Usage: coder"),
92+
tcli.StdoutEmpty(),
93+
)
94+
95+
headlessLogin(ctx, t, c)
96+
97+
c.Run(ctx, "coder envs").Assert(t,
98+
tcli.Success(),
99+
)
100+
101+
c.Run(ctx, "coder urls").Assert(t,
102+
tcli.Error(),
103+
)
104+
105+
c.Run(ctx, "coder sync").Assert(t,
106+
tcli.Error(),
107+
)
108+
109+
c.Run(ctx, "coder sh").Assert(t,
110+
tcli.Error(),
111+
)
112+
113+
c.Run(ctx, "coder logout").Assert(t,
114+
tcli.Success(),
115+
)
116+
117+
c.Run(ctx, "coder envs").Assert(t,
118+
tcli.Error(),
119+
)
120+
}

ci/integration/login_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package integration
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"net/http"
9+
"net/url"
10+
"os"
11+
"testing"
12+
13+
"cdr.dev/slog/sloggers/slogtest/assert"
14+
)
15+
16+
type credentials struct {
17+
url, token string
18+
}
19+
20+
func login(ctx context.Context, t *testing.T) credentials {
21+
var (
22+
email = requireEnv(t, "CODER_EMAIL")
23+
password = requireEnv(t, "CODER_PASSWORD")
24+
rawURL = requireEnv(t, "CODER_URL")
25+
)
26+
sessionToken := getSessionToken(ctx, t, email, password, rawURL)
27+
28+
return credentials{
29+
url: rawURL,
30+
token: sessionToken,
31+
}
32+
}
33+
34+
func requireEnv(t *testing.T, key string) string {
35+
value := os.Getenv(key)
36+
assert.True(t, fmt.Sprintf("%q is nonempty", key), value != "")
37+
return value
38+
}
39+
40+
type loginBuiltInAuthReq struct {
41+
Email string `json:"email"`
42+
Password string `json:"password"`
43+
}
44+
45+
type loginBuiltInAuthResp struct {
46+
SessionToken string `json:"session_token"`
47+
}
48+
49+
func getSessionToken(ctx context.Context, t *testing.T, email, password, rawURL string) string {
50+
reqbody := loginBuiltInAuthReq{
51+
Email: email,
52+
Password: password,
53+
}
54+
body, err := json.Marshal(reqbody)
55+
assert.Success(t, "marshal login req body", err)
56+
57+
u, err := url.Parse(rawURL)
58+
assert.Success(t, "parse raw url", err)
59+
u.Path = "/auth/basic/login"
60+
61+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), bytes.NewReader(body))
62+
assert.Success(t, "new request", err)
63+
64+
resp, err := http.DefaultClient.Do(req)
65+
assert.Success(t, "do request", err)
66+
assert.Equal(t, "request status 201", http.StatusCreated, resp.StatusCode)
67+
68+
var tokenResp loginBuiltInAuthResp
69+
err = json.NewDecoder(resp.Body).Decode(&tokenResp)
70+
assert.Success(t, "decode response", err)
71+
72+
defer resp.Body.Close()
73+
74+
return tokenResp.SessionToken
75+
}

ci/build.sh renamed to ci/steps/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ mkdir -p bin
1414

1515
build(){
1616
tmpdir=$(mktemp -d)
17-
go build -ldflags "-s -w -X main.version=${tag}" -o "$tmpdir/coder" ../cmd/coder
17+
go build -ldflags "-s -w -X main.version=${tag}" -o "$tmpdir/coder" ../../cmd/coder
1818

1919
pushd "$tmpdir"
2020
tarname="coder-cli-$GOOS-$GOARCH.tar.gz"
2121
tar -czf "$tarname" coder
2222
popd
2323

24-
cp "$tmpdir/$tarname" bin
24+
cp "$tmpdir/$tarname" ../bin
2525
rm -rf "$tmpdir"
2626
}
2727

ci/steps/fmt.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
echo "Formatting..."
3+
4+
go mod tidy
5+
gofmt -w -s .
6+
goimports -w "-local=$$(go list -m)" .
7+
8+
if [ "$CI" != "" ]; then
9+
if [[ $(git ls-files --other --modified --exclude-standard) != "" ]]; then
10+
echo "Files need generation or are formatted incorrectly:"
11+
git -c color.ui=always status | grep --color=no '\e\[31m'
12+
echo "Please run the following locally:"
13+
echo " ./ci/steps/fmt.sh"
14+
exit 1
15+
fi
16+
fi

ci/steps/lint.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
echo "Linting..."
4+
5+
go vet ./...
6+
golint -set_exit_status ./...

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy