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

Commit b7741f1

Browse files
committed
Add integration tests for Secrets commands
1 parent 01e9b77 commit b7741f1

File tree

16 files changed

+221
-139
lines changed

16 files changed

+221
-139
lines changed

ci/integration/integration_test.go

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"os"
8-
"os/exec"
9-
"path/filepath"
10-
"strings"
7+
"math/rand"
8+
"regexp"
119
"testing"
1210
"time"
1311

@@ -17,50 +15,6 @@ import (
1715
"cdr.dev/slog/sloggers/slogtest/assert"
1816
)
1917

20-
func build(path string) error {
21-
cmd := exec.Command(
22-
"sh", "-c",
23-
fmt.Sprintf("cd ../../ && go build -o %s ./cmd/coder", path),
24-
)
25-
cmd.Env = append(os.Environ(), "GOOS=linux", "CGO_ENABLED=0")
26-
27-
_, err := cmd.CombinedOutput()
28-
if err != nil {
29-
return err
30-
}
31-
return nil
32-
}
33-
34-
var binpath string
35-
36-
func init() {
37-
cwd, err := os.Getwd()
38-
if err != nil {
39-
panic(err)
40-
}
41-
42-
binpath = filepath.Join(cwd, "bin", "coder")
43-
err = build(binpath)
44-
if err != nil {
45-
panic(err)
46-
}
47-
}
48-
49-
// write session tokens to the given container runner
50-
func headlessLogin(ctx context.Context, t *testing.T, runner *tcli.ContainerRunner) {
51-
creds := login(ctx, t)
52-
cmd := exec.CommandContext(ctx, "sh", "-c", "mkdir -p ~/.config/coder && cat > ~/.config/coder/session")
53-
54-
// !IMPORTANT: be careful that this does not appear in logs
55-
cmd.Stdin = strings.NewReader(creds.token)
56-
runner.RunCmd(cmd).Assert(t,
57-
tcli.Success(),
58-
)
59-
runner.Run(ctx, fmt.Sprintf("echo -ne %s > ~/.config/coder/url", creds.url)).Assert(t,
60-
tcli.Success(),
61-
)
62-
}
63-
6418
func TestCoderCLI(t *testing.T) {
6519
t.Parallel()
6620
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
@@ -135,10 +89,80 @@ func TestCoderCLI(t *testing.T) {
13589
)
13690
}
13791

92+
func TestSecrets(t *testing.T) {
93+
t.Parallel()
94+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
95+
defer cancel()
96+
97+
c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{
98+
Image: "codercom/enterprise-dev",
99+
Name: "secrets-cli-tests",
100+
BindMounts: map[string]string{
101+
binpath: "/bin/coder",
102+
},
103+
})
104+
assert.Success(t, "new run container", err)
105+
defer c.Close()
106+
107+
headlessLogin(ctx, t, c)
108+
109+
c.Run(ctx, "coder secrets ls").Assert(t,
110+
tcli.Success(),
111+
)
112+
113+
name, value := randString(8), randString(8)
114+
115+
c.Run(ctx, "coder secrets add").Assert(t,
116+
tcli.Error(),
117+
tcli.StdoutEmpty(),
118+
tcli.StderrMatches("required flag"),
119+
)
120+
121+
c.Run(ctx, fmt.Sprintf("coder secrets add --name %s --value %s", name, value)).Assert(t,
122+
tcli.Success(),
123+
tcli.StderrEmpty(),
124+
)
125+
126+
c.Run(ctx, "coder secrets ls").Assert(t,
127+
tcli.Success(),
128+
tcli.StderrEmpty(),
129+
tcli.StdoutMatches("Value"),
130+
tcli.StdoutMatches(regexp.QuoteMeta(name)),
131+
)
132+
133+
c.Run(ctx, "coder secrets view "+name).Assert(t,
134+
tcli.Success(),
135+
tcli.StderrEmpty(),
136+
tcli.StdoutMatches(regexp.QuoteMeta(value)),
137+
)
138+
139+
c.Run(ctx, "coder secrets rm").Assert(t,
140+
tcli.Error(),
141+
)
142+
c.Run(ctx, "coder secrets rm "+name).Assert(t,
143+
tcli.Success(),
144+
)
145+
c.Run(ctx, "coder secrets view "+name).Assert(t,
146+
tcli.Error(),
147+
tcli.StdoutEmpty(),
148+
)
149+
}
150+
138151
func jsonUnmarshals(target interface{}) tcli.Assertion {
139152
return func(t *testing.T, r *tcli.CommandResult) {
140153
slog.Helper()
141154
err := json.Unmarshal(r.Stdout, target)
142155
assert.Success(t, "json unmarshals", err)
143156
}
144157
}
158+
159+
var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
160+
161+
func randString(length int) string {
162+
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
163+
b := make([]byte, length)
164+
for i := range b {
165+
b[i] = charset[seededRand.Intn(len(charset))]
166+
}
167+
return string(b)
168+
}

ci/integration/setup_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"strings"
10+
"testing"
11+
12+
"cdr.dev/coder-cli/ci/tcli"
13+
"golang.org/x/xerrors"
14+
)
15+
16+
var binpath string
17+
18+
// initialize integration tests by building the coder-cli binary
19+
func init() {
20+
cwd, err := os.Getwd()
21+
if err != nil {
22+
panic(err)
23+
}
24+
25+
binpath = filepath.Join(cwd, "bin", "coder")
26+
err = build(binpath)
27+
if err != nil {
28+
panic(err)
29+
}
30+
}
31+
32+
// build the coder-cli binary and move to the integration testing bin directory
33+
func build(path string) error {
34+
cmd := exec.Command(
35+
"sh", "-c",
36+
fmt.Sprintf("cd ../../ && go build -o %s ./cmd/coder", path),
37+
)
38+
cmd.Env = append(os.Environ(), "GOOS=linux", "CGO_ENABLED=0")
39+
40+
out, err := cmd.CombinedOutput()
41+
if err != nil {
42+
return xerrors.Errorf("failed to build coder-cli (%v): %w", string(out), err)
43+
}
44+
return nil
45+
}
46+
47+
// write session tokens to the given container runner
48+
func headlessLogin(ctx context.Context, t *testing.T, runner *tcli.ContainerRunner) {
49+
creds := login(ctx, t)
50+
cmd := exec.CommandContext(ctx, "sh", "-c", "mkdir -p ~/.config/coder && cat > ~/.config/coder/session")
51+
52+
// !IMPORTANT: be careful that this does not appear in logs
53+
cmd.Stdin = strings.NewReader(creds.token)
54+
runner.RunCmd(cmd).Assert(t,
55+
tcli.Success(),
56+
)
57+
runner.Run(ctx, fmt.Sprintf("echo -ne %s > ~/.config/coder/url", creds.url)).Assert(t,
58+
tcli.Success(),
59+
)
60+
}

cmd/coder/auth.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@ package main
33
import (
44
"net/url"
55

6-
"cdr.dev/coder-cli/internal/xcli"
7-
86
"cdr.dev/coder-cli/internal/config"
97
"cdr.dev/coder-cli/internal/entclient"
108
)
119

1210
func requireAuth() *entclient.Client {
1311
sessionToken, err := config.Session.Read()
14-
xcli.RequireSuccess(err, "read session: %v (did you run coder login?)", err)
12+
requireSuccess(err, "read session: %v (did you run coder login?)", err)
1513

1614
rawURL, err := config.URL.Read()
17-
xcli.RequireSuccess(err, "read url: %v (did you run coder login?)", err)
15+
requireSuccess(err, "read url: %v (did you run coder login?)", err)
1816

1917
u, err := url.Parse(rawURL)
20-
xcli.RequireSuccess(err, "url misformatted: %v (try runing coder login)", err)
18+
requireSuccess(err, "url misformatted: %v (try runing coder login)", err)
2119

2220
return &entclient.Client{
2321
BaseURL: u,

cmd/coder/ceapi.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package main
22

33
import (
4-
"cdr.dev/coder-cli/internal/xcli"
5-
64
"go.coder.com/flog"
75

86
"cdr.dev/coder-cli/internal/entclient"
@@ -29,18 +27,18 @@ outer:
2927
// getEnvs returns all environments for the user.
3028
func getEnvs(client *entclient.Client) []entclient.Environment {
3129
me, err := client.Me()
32-
xcli.RequireSuccess(err, "get self: %+v", err)
30+
requireSuccess(err, "get self: %+v", err)
3331

3432
orgs, err := client.Orgs()
35-
xcli.RequireSuccess(err, "get orgs: %+v", err)
33+
requireSuccess(err, "get orgs: %+v", err)
3634

3735
orgs = userOrgs(me, orgs)
3836

3937
var allEnvs []entclient.Environment
4038

4139
for _, org := range orgs {
4240
envs, err := client.Envs(me, org)
43-
xcli.RequireSuccess(err, "get envs for %v: %+v", org.Name, err)
41+
requireSuccess(err, "get envs for %v: %+v", org.Name, err)
4442

4543
for _, env := range envs {
4644
allEnvs = append(allEnvs, env)

cmd/coder/main.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
_ "net/http/pprof"
77
"os"
88

9-
"cdr.dev/coder-cli/internal/xterminal"
9+
"cdr.dev/coder-cli/internal/x/xterminal"
1010
"github.com/spf13/pflag"
1111

1212
"go.coder.com/flog"
@@ -62,3 +62,10 @@ func main() {
6262

6363
cli.RunRoot(&rootCmd{})
6464
}
65+
66+
// requireSuccess prints the given message and format args as a fatal error if err != nil
67+
func requireSuccess(err error, msg string, args ...interface{}) {
68+
if err != nil {
69+
flog.Fatal(msg, args...)
70+
}
71+
}

0 commit comments

Comments
 (0)