@@ -7,9 +7,11 @@ import (
7
7
"os"
8
8
"os/exec"
9
9
"testing"
10
+ "time"
10
11
11
12
"github.com/stretchr/testify/assert"
12
13
"github.com/stretchr/testify/require"
14
+ "golang.org/x/xerrors"
13
15
14
16
"github.com/coder/coder/v2/cli/cliui"
15
17
"github.com/coder/coder/v2/pty"
@@ -22,26 +24,29 @@ func TestPrompt(t *testing.T) {
22
24
t .Parallel ()
23
25
t .Run ("Success" , func (t * testing.T ) {
24
26
t .Parallel ()
27
+ ctx := testutil .Context (t , testutil .WaitShort )
25
28
ptty := ptytest .New (t )
26
29
msgChan := make (chan string )
27
30
go func () {
28
- resp , err := newPrompt (ptty , cliui.PromptOptions {
31
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
29
32
Text : "Example" ,
30
33
}, nil )
31
34
assert .NoError (t , err )
32
35
msgChan <- resp
33
36
}()
34
37
ptty .ExpectMatch ("Example" )
35
38
ptty .WriteLine ("hello" )
36
- require .Equal (t , "hello" , <- msgChan )
39
+ resp := testutil .RequireRecvCtx (ctx , t , msgChan )
40
+ require .Equal (t , "hello" , resp )
37
41
})
38
42
39
43
t .Run ("Confirm" , func (t * testing.T ) {
40
44
t .Parallel ()
45
+ ctx := testutil .Context (t , testutil .WaitShort )
41
46
ptty := ptytest .New (t )
42
47
doneChan := make (chan string )
43
48
go func () {
44
- resp , err := newPrompt (ptty , cliui.PromptOptions {
49
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
45
50
Text : "Example" ,
46
51
IsConfirm : true ,
47
52
}, nil )
@@ -50,18 +55,20 @@ func TestPrompt(t *testing.T) {
50
55
}()
51
56
ptty .ExpectMatch ("Example" )
52
57
ptty .WriteLine ("yes" )
53
- require .Equal (t , "yes" , <- doneChan )
58
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
59
+ require .Equal (t , "yes" , resp )
54
60
})
55
61
56
62
t .Run ("Skip" , func (t * testing.T ) {
57
63
t .Parallel ()
64
+ ctx := testutil .Context (t , testutil .WaitShort )
58
65
ptty := ptytest .New (t )
59
66
var buf bytes.Buffer
60
67
61
68
// Copy all data written out to a buffer. When we close the ptty, we can
62
69
// no longer read from the ptty.Output(), but we can read what was
63
70
// written to the buffer.
64
- dataRead , doneReading := context .WithTimeout ( context . Background (), testutil . WaitShort )
71
+ dataRead , doneReading := context .WithCancel ( ctx )
65
72
go func () {
66
73
// This will throw an error sometimes. The underlying ptty
67
74
// has its own cleanup routines in t.Cleanup. Instead of
@@ -74,7 +81,7 @@ func TestPrompt(t *testing.T) {
74
81
75
82
doneChan := make (chan string )
76
83
go func () {
77
- resp , err := newPrompt (ptty , cliui.PromptOptions {
84
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
78
85
Text : "ShouldNotSeeThis" ,
79
86
IsConfirm : true ,
80
87
}, func (inv * serpent.Invocation ) {
@@ -85,7 +92,8 @@ func TestPrompt(t *testing.T) {
85
92
doneChan <- resp
86
93
}()
87
94
88
- require .Equal (t , "yes" , <- doneChan )
95
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
96
+ require .Equal (t , "yes" , resp )
89
97
// Close the reader to end the io.Copy
90
98
require .NoError (t , ptty .Close (), "close eof reader" )
91
99
// Wait for the IO copy to finish
@@ -96,42 +104,47 @@ func TestPrompt(t *testing.T) {
96
104
})
97
105
t .Run ("JSON" , func (t * testing.T ) {
98
106
t .Parallel ()
107
+ ctx := testutil .Context (t , testutil .WaitShort )
99
108
ptty := ptytest .New (t )
100
109
doneChan := make (chan string )
101
110
go func () {
102
- resp , err := newPrompt (ptty , cliui.PromptOptions {
111
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
103
112
Text : "Example" ,
104
113
}, nil )
105
114
assert .NoError (t , err )
106
115
doneChan <- resp
107
116
}()
108
117
ptty .ExpectMatch ("Example" )
109
118
ptty .WriteLine ("{}" )
110
- require .Equal (t , "{}" , <- doneChan )
119
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
120
+ require .Equal (t , "{}" , resp )
111
121
})
112
122
113
123
t .Run ("BadJSON" , func (t * testing.T ) {
114
124
t .Parallel ()
125
+ ctx := testutil .Context (t , testutil .WaitShort )
115
126
ptty := ptytest .New (t )
116
127
doneChan := make (chan string )
117
128
go func () {
118
- resp , err := newPrompt (ptty , cliui.PromptOptions {
129
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
119
130
Text : "Example" ,
120
131
}, nil )
121
132
assert .NoError (t , err )
122
133
doneChan <- resp
123
134
}()
124
135
ptty .ExpectMatch ("Example" )
125
136
ptty .WriteLine ("{a" )
126
- require .Equal (t , "{a" , <- doneChan )
137
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
138
+ require .Equal (t , "{a" , resp )
127
139
})
128
140
129
141
t .Run ("MultilineJSON" , func (t * testing.T ) {
130
142
t .Parallel ()
143
+ ctx := testutil .Context (t , testutil .WaitShort )
131
144
ptty := ptytest .New (t )
132
145
doneChan := make (chan string )
133
146
go func () {
134
- resp , err := newPrompt (ptty , cliui.PromptOptions {
147
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
135
148
Text : "Example" ,
136
149
}, nil )
137
150
assert .NoError (t , err )
@@ -141,11 +154,37 @@ func TestPrompt(t *testing.T) {
141
154
ptty .WriteLine (`{
142
155
"test": "wow"
143
156
}` )
144
- require .Equal (t , `{"test":"wow"}` , <- doneChan )
157
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
158
+ require .Equal (t , `{"test":"wow"}` , resp )
159
+ })
160
+
161
+ t .Run ("InvalidValid" , func (t * testing.T ) {
162
+ t .Parallel ()
163
+ ctx := testutil .Context (t , time .Minute * 5 )
164
+ ptty := ptytest .New (t )
165
+ doneChan := make (chan string )
166
+ go func () {
167
+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
168
+ Text : "Example" ,
169
+ Validate : func (s string ) error {
170
+ t .Logf ("validate: %q" , s )
171
+ if s != "valid" {
172
+ return xerrors .New ("invalid" )
173
+ }
174
+ return nil
175
+ },
176
+ }, nil )
177
+ assert .NoError (t , err )
178
+ doneChan <- resp
179
+ }()
180
+ ptty .ExpectMatch ("Example" )
181
+ ptty .WriteLine ("foo\n bar\n baz\n \n \n valid\n " )
182
+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
183
+ require .Equal (t , "valid" , resp )
145
184
})
146
185
}
147
186
148
- func newPrompt (ptty * ptytest.PTY , opts cliui.PromptOptions , invOpt func (inv * serpent.Invocation )) (string , error ) {
187
+ func newPrompt (ctx context. Context , ptty * ptytest.PTY , opts cliui.PromptOptions , invOpt func (inv * serpent.Invocation )) (string , error ) {
149
188
value := ""
150
189
cmd := & serpent.Command {
151
190
Handler : func (inv * serpent.Invocation ) error {
@@ -163,7 +202,7 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, invOpt func(inv *ser
163
202
inv .Stdout = ptty .Output ()
164
203
inv .Stderr = ptty .Output ()
165
204
inv .Stdin = ptty .Input ()
166
- return value , inv .WithContext (context . Background () ).Run ()
205
+ return value , inv .WithContext (ctx ).Run ()
167
206
}
168
207
169
208
func TestPasswordTerminalState (t * testing.T ) {
0 commit comments