Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c4057eb

Browse files
committed
Add CLI test for login
1 parent d6a1eb8 commit c4057eb

File tree

9 files changed

+150
-46
lines changed

9 files changed

+150
-46
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@
3535
"goleak",
3636
"hashicorp",
3737
"httpmw",
38+
"isatty",
3839
"Jobf",
40+
"kirsle",
3941
"manifoldco",
42+
"mattn",
4043
"moby",
4144
"nhooyr",
4245
"nolint",

cli/clitest/clitest.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package clitest
2+
3+
import (
4+
"bufio"
5+
"io"
6+
"testing"
7+
8+
"github.com/spf13/cobra"
9+
10+
"github.com/coder/coder/cli"
11+
"github.com/coder/coder/cli/config"
12+
)
13+
14+
func New(t *testing.T, args ...string) (*cobra.Command, config.Root) {
15+
cmd := cli.Root()
16+
dir := t.TempDir()
17+
root := config.Root(dir)
18+
cmd.SetArgs(append([]string{"--global-config", dir}, args...))
19+
return cmd, root
20+
}
21+
22+
func StdoutLogs(t *testing.T) io.Writer {
23+
reader, writer := io.Pipe()
24+
scanner := bufio.NewScanner(reader)
25+
t.Cleanup(func() {
26+
_ = reader.Close()
27+
_ = writer.Close()
28+
})
29+
go func() {
30+
for scanner.Scan() {
31+
if scanner.Err() != nil {
32+
return
33+
}
34+
t.Log(scanner.Text())
35+
}
36+
}()
37+
return writer
38+
}

cli/config/file_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func TestFile(t *testing.T) {
2424
require.NoError(t, err)
2525
data, err := root.Session().Read()
2626
require.NoError(t, err)
27-
require.Equal(t, "test", string(data))
27+
require.Equal(t, "test", data)
2828
})
2929

3030
t.Run("Delete", func(t *testing.T) {

cli/login.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package cli
22

33
import (
4-
"errors"
54
"fmt"
65
"net/url"
6+
"os"
77
"strings"
88

9-
"github.com/coder/coder/coderd"
10-
"github.com/coder/coder/codersdk"
119
"github.com/fatih/color"
1210
"github.com/go-playground/validator/v10"
1311
"github.com/manifoldco/promptui"
1412
"github.com/spf13/cobra"
1513
"golang.org/x/xerrors"
14+
15+
"github.com/coder/coder/coderd"
16+
"github.com/coder/coder/codersdk"
1617
)
1718

1819
func login() *cobra.Command {
@@ -46,7 +47,7 @@ func login() *cobra.Command {
4647
if !isTTY(cmd.InOrStdin()) {
4748
return xerrors.New("the initial user cannot be created in non-interactive mode. use the API")
4849
}
49-
fmt.Fprintf(cmd.OutOrStdout(), "%s Your Coder deployment hasn't been setup!\n", color.HiBlackString(">"))
50+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s Your Coder deployment hasn't been setup!\n", color.HiBlackString(">"))
5051

5152
_, err := runPrompt(cmd, &promptui.Prompt{
5253
Label: "Would you like to create the first user?",
@@ -59,7 +60,7 @@ func login() *cobra.Command {
5960

6061
username, err := runPrompt(cmd, &promptui.Prompt{
6162
Label: "What username would you like?",
62-
Default: "kyle",
63+
Default: os.Getenv("USER"),
6364
})
6465
if err != nil {
6566
return err
@@ -78,7 +79,7 @@ func login() *cobra.Command {
7879
Validate: func(s string) error {
7980
err := validator.New().Var(s, "email")
8081
if err != nil {
81-
return errors.New("That's not a valid email address!")
82+
return xerrors.New("That's not a valid email address!")
8283
}
8384
return err
8485
},
@@ -121,7 +122,7 @@ func login() *cobra.Command {
121122
return xerrors.Errorf("write server url: %w", err)
122123
}
123124

124-
fmt.Fprintf(cmd.OutOrStdout(), "%s Welcome to Coder, %s! You're logged in.\n", color.HiBlackString(">"), color.HiCyanString(username))
125+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s Welcome to Coder, %s! You're logged in.\n", color.HiBlackString(">"), color.HiCyanString(username))
125126
return nil
126127
}
127128

cli/login_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cli_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/coder/coder/cli/clitest"
7+
"github.com/coder/coder/coderd/coderdtest"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/Netflix/go-expect"
11+
)
12+
13+
func TestLogin(t *testing.T) {
14+
t.Parallel()
15+
t.Run("InitialUserNoTTY", func(t *testing.T) {
16+
client := coderdtest.New(t)
17+
root, _ := clitest.New(t, "login", client.URL.String())
18+
err := root.Execute()
19+
require.Error(t, err)
20+
})
21+
22+
t.Run("InitialUserTTY", func(t *testing.T) {
23+
console, err := expect.NewConsole(expect.WithStdout(clitest.StdoutLogs(t)))
24+
require.NoError(t, err)
25+
client := coderdtest.New(t)
26+
root, _ := clitest.New(t, "login", client.URL.String())
27+
root.SetIn(console.Tty())
28+
root.SetOut(console.Tty())
29+
go func() {
30+
err = root.Execute()
31+
require.NoError(t, err)
32+
}()
33+
34+
matches := []string{
35+
"first user?", "y",
36+
"username", "testuser",
37+
"organization", "testorg",
38+
"email", "[email protected]",
39+
"password", "password",
40+
}
41+
for i := 0; i < len(matches); i += 2 {
42+
match := matches[i]
43+
value := matches[i+1]
44+
_, err = console.ExpectString(match)
45+
require.NoError(t, err)
46+
_, err = console.SendLine(value)
47+
require.NoError(t, err)
48+
}
49+
_, err = console.ExpectString("Welcome to Coder")
50+
require.NoError(t, err)
51+
})
52+
}

cli/projectcreate.go

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ import (
1111
"time"
1212

1313
"github.com/briandowns/spinner"
14-
"github.com/coder/coder/coderd"
15-
"github.com/coder/coder/codersdk"
16-
"github.com/coder/coder/database"
1714
"github.com/fatih/color"
1815
"github.com/manifoldco/promptui"
1916
"github.com/spf13/cobra"
2017
"golang.org/x/xerrors"
18+
19+
"github.com/coder/coder/coderd"
20+
"github.com/coder/coder/codersdk"
21+
"github.com/coder/coder/database"
2122
)
2223

2324
func projectCreate() *cobra.Command {
@@ -48,9 +49,8 @@ func projectCreate() *cobra.Command {
4849
return err
4950
}
5051

51-
name := filepath.Base(workingDir)
52-
name, err = runPrompt(cmd, &promptui.Prompt{
53-
Default: name,
52+
name, err := runPrompt(cmd, &promptui.Prompt{
53+
Default: filepath.Base(workingDir),
5454
Label: "What's your project's name?",
5555
Validate: func(s string) error {
5656
_, err = client.Project(cmd.Context(), organization.Name, s)
@@ -69,7 +69,7 @@ func projectCreate() *cobra.Command {
6969
spin.Start()
7070
defer spin.Stop()
7171

72-
bytes, err := tarDir(workingDir)
72+
bytes, err := tarDirectory(workingDir)
7373
if err != nil {
7474
return err
7575
}
@@ -102,54 +102,50 @@ func projectCreate() *cobra.Command {
102102
if !ok {
103103
break
104104
}
105-
fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[parse]"), log.Output)
105+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s\n", color.HiGreenString("[parse]"), log.Output)
106106
}
107107

108-
fmt.Printf("Projects %+v %+v\n", projects, organization)
108+
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Create project %q!\n", name)
109109
return nil
110110
},
111111
}
112112
}
113113

114-
func tarDir(directory string) ([]byte, error) {
114+
func tarDirectory(directory string) ([]byte, error) {
115115
var buffer bytes.Buffer
116-
tw := tar.NewWriter(&buffer)
117-
// walk through every file in the folder
118-
err := filepath.Walk(directory, func(file string, fi os.FileInfo, err error) error {
119-
// generate tar header
120-
header, err := tar.FileInfoHeader(fi, file)
116+
tarWriter := tar.NewWriter(&buffer)
117+
err := filepath.Walk(directory, func(file string, fileInfo os.FileInfo, err error) error {
118+
if err != nil {
119+
return err
120+
}
121+
header, err := tar.FileInfoHeader(fileInfo, file)
121122
if err != nil {
122123
return err
123124
}
124-
125-
// must provide real name
126-
// (see https://golang.org/src/archive/tar/common.go?#L626)
127125
rel, err := filepath.Rel(directory, file)
128126
if err != nil {
129127
return err
130128
}
131129
header.Name = rel
132-
133-
// write header
134-
if err := tw.WriteHeader(header); err != nil {
130+
if err := tarWriter.WriteHeader(header); err != nil {
135131
return err
136132
}
137-
// if not a dir, write file content
138-
if !fi.IsDir() {
139-
data, err := os.Open(file)
140-
if err != nil {
141-
return err
142-
}
143-
if _, err := io.Copy(tw, data); err != nil {
144-
return err
145-
}
133+
if fileInfo.IsDir() {
134+
return nil
135+
}
136+
data, err := os.Open(file)
137+
if err != nil {
138+
return err
139+
}
140+
if _, err := io.Copy(tarWriter, data); err != nil {
141+
return err
146142
}
147-
return nil
143+
return data.Close()
148144
})
149145
if err != nil {
150146
return nil, err
151147
}
152-
err = tw.Flush()
148+
err = tarWriter.Flush()
153149
if err != nil {
154150
return nil, err
155151
}

cli/root.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import (
77
"os"
88
"strings"
99

10-
"github.com/coder/coder/cli/config"
11-
"github.com/coder/coder/coderd"
12-
"github.com/coder/coder/codersdk"
1310
"github.com/fatih/color"
1411
"github.com/kirsle/configdir"
1512
"github.com/manifoldco/promptui"
1613
"github.com/mattn/go-isatty"
1714
"github.com/spf13/cobra"
15+
"golang.org/x/xerrors"
16+
17+
"github.com/coder/coder/cli/config"
18+
"github.com/coder/coder/coderd"
19+
"github.com/coder/coder/codersdk"
1820
)
1921

2022
const (
@@ -115,8 +117,15 @@ func isTTY(reader io.Reader) bool {
115117
}
116118

117119
func runPrompt(cmd *cobra.Command, prompt *promptui.Prompt) (string, error) {
118-
prompt.Stdin = cmd.InOrStdin().(io.ReadCloser)
119-
prompt.Stdout = cmd.OutOrStdout().(io.WriteCloser)
120+
var ok bool
121+
prompt.Stdin, ok = cmd.InOrStdin().(io.ReadCloser)
122+
if !ok {
123+
return "", xerrors.New("stdin must be a readcloser")
124+
}
125+
prompt.Stdout, ok = cmd.OutOrStdout().(io.WriteCloser)
126+
if !ok {
127+
return "", xerrors.New("stdout must be a readcloser")
128+
}
120129

121130
// The prompt library displays defaults in a jarring way for the user
122131
// by attempting to autocomplete it. This sets no default enabling us

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ replace github.com/hashicorp/terraform-config-inspect => github.com/kylecarbs/te
1010

1111
require (
1212
cdr.dev/slog v1.4.1
13+
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
1314
github.com/briandowns/spinner v1.18.1
1415
github.com/coder/retry v1.3.0
1516
github.com/fatih/color v1.13.0
@@ -58,6 +59,7 @@ require (
5859
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
5960
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
6061
github.com/containerd/continuity v0.2.2 // indirect
62+
github.com/creack/pty v1.1.17 // indirect
6163
github.com/davecgh/go-spew v1.1.1 // indirect
6264
github.com/dhui/dktest v0.3.9 // indirect
6365
github.com/dlclark/regexp2 v1.4.0 // indirect

go.sum

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01
103103
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
104104
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
105105
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
106+
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
107+
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
106108
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
107109
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
108110
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@@ -350,8 +352,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
350352
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
351353
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
352354
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
353-
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
354355
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
356+
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
357+
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
355358
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
356359
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
357360
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=

0 commit comments

Comments
 (0)