@@ -7,9 +7,11 @@ import (
77 "os"
88 "os/exec"
99 "testing"
10+ "time"
1011
1112 "github.com/stretchr/testify/assert"
1213 "github.com/stretchr/testify/require"
14+ "golang.org/x/xerrors"
1315
1416 "github.com/coder/coder/v2/cli/cliui"
1517 "github.com/coder/coder/v2/pty"
@@ -22,26 +24,29 @@ func TestPrompt(t *testing.T) {
2224 t .Parallel ()
2325 t .Run ("Success" , func (t * testing.T ) {
2426 t .Parallel ()
27+ ctx := testutil .Context (t , testutil .WaitShort )
2528 ptty := ptytest .New (t )
2629 msgChan := make (chan string )
2730 go func () {
28- resp , err := newPrompt (ptty , cliui.PromptOptions {
31+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
2932 Text : "Example" ,
3033 }, nil )
3134 assert .NoError (t , err )
3235 msgChan <- resp
3336 }()
3437 ptty .ExpectMatch ("Example" )
3538 ptty .WriteLine ("hello" )
36- require .Equal (t , "hello" , <- msgChan )
39+ resp := testutil .RequireRecvCtx (ctx , t , msgChan )
40+ require .Equal (t , "hello" , resp )
3741 })
3842
3943 t .Run ("Confirm" , func (t * testing.T ) {
4044 t .Parallel ()
45+ ctx := testutil .Context (t , testutil .WaitShort )
4146 ptty := ptytest .New (t )
4247 doneChan := make (chan string )
4348 go func () {
44- resp , err := newPrompt (ptty , cliui.PromptOptions {
49+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
4550 Text : "Example" ,
4651 IsConfirm : true ,
4752 }, nil )
@@ -50,18 +55,20 @@ func TestPrompt(t *testing.T) {
5055 }()
5156 ptty .ExpectMatch ("Example" )
5257 ptty .WriteLine ("yes" )
53- require .Equal (t , "yes" , <- doneChan )
58+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
59+ require .Equal (t , "yes" , resp )
5460 })
5561
5662 t .Run ("Skip" , func (t * testing.T ) {
5763 t .Parallel ()
64+ ctx := testutil .Context (t , testutil .WaitShort )
5865 ptty := ptytest .New (t )
5966 var buf bytes.Buffer
6067
6168 // Copy all data written out to a buffer. When we close the ptty, we can
6269 // no longer read from the ptty.Output(), but we can read what was
6370 // written to the buffer.
64- dataRead , doneReading := context .WithTimeout ( context . Background (), testutil . WaitShort )
71+ dataRead , doneReading := context .WithCancel ( ctx )
6572 go func () {
6673 // This will throw an error sometimes. The underlying ptty
6774 // has its own cleanup routines in t.Cleanup. Instead of
@@ -74,7 +81,7 @@ func TestPrompt(t *testing.T) {
7481
7582 doneChan := make (chan string )
7683 go func () {
77- resp , err := newPrompt (ptty , cliui.PromptOptions {
84+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
7885 Text : "ShouldNotSeeThis" ,
7986 IsConfirm : true ,
8087 }, func (inv * serpent.Invocation ) {
@@ -85,7 +92,8 @@ func TestPrompt(t *testing.T) {
8592 doneChan <- resp
8693 }()
8794
88- require .Equal (t , "yes" , <- doneChan )
95+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
96+ require .Equal (t , "yes" , resp )
8997 // Close the reader to end the io.Copy
9098 require .NoError (t , ptty .Close (), "close eof reader" )
9199 // Wait for the IO copy to finish
@@ -96,42 +104,47 @@ func TestPrompt(t *testing.T) {
96104 })
97105 t .Run ("JSON" , func (t * testing.T ) {
98106 t .Parallel ()
107+ ctx := testutil .Context (t , testutil .WaitShort )
99108 ptty := ptytest .New (t )
100109 doneChan := make (chan string )
101110 go func () {
102- resp , err := newPrompt (ptty , cliui.PromptOptions {
111+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
103112 Text : "Example" ,
104113 }, nil )
105114 assert .NoError (t , err )
106115 doneChan <- resp
107116 }()
108117 ptty .ExpectMatch ("Example" )
109118 ptty .WriteLine ("{}" )
110- require .Equal (t , "{}" , <- doneChan )
119+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
120+ require .Equal (t , "{}" , resp )
111121 })
112122
113123 t .Run ("BadJSON" , func (t * testing.T ) {
114124 t .Parallel ()
125+ ctx := testutil .Context (t , testutil .WaitShort )
115126 ptty := ptytest .New (t )
116127 doneChan := make (chan string )
117128 go func () {
118- resp , err := newPrompt (ptty , cliui.PromptOptions {
129+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
119130 Text : "Example" ,
120131 }, nil )
121132 assert .NoError (t , err )
122133 doneChan <- resp
123134 }()
124135 ptty .ExpectMatch ("Example" )
125136 ptty .WriteLine ("{a" )
126- require .Equal (t , "{a" , <- doneChan )
137+ resp := testutil .RequireRecvCtx (ctx , t , doneChan )
138+ require .Equal (t , "{a" , resp )
127139 })
128140
129141 t .Run ("MultilineJSON" , func (t * testing.T ) {
130142 t .Parallel ()
143+ ctx := testutil .Context (t , testutil .WaitShort )
131144 ptty := ptytest .New (t )
132145 doneChan := make (chan string )
133146 go func () {
134- resp , err := newPrompt (ptty , cliui.PromptOptions {
147+ resp , err := newPrompt (ctx , ptty , cliui.PromptOptions {
135148 Text : "Example" ,
136149 }, nil )
137150 assert .NoError (t , err )
@@ -141,11 +154,37 @@ func TestPrompt(t *testing.T) {
141154 ptty .WriteLine (`{
142155"test": "wow"
143156}` )
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 )
145184 })
146185}
147186
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 ) {
149188 value := ""
150189 cmd := & serpent.Command {
151190 Handler : func (inv * serpent.Invocation ) error {
@@ -163,7 +202,7 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions, invOpt func(inv *ser
163202 inv .Stdout = ptty .Output ()
164203 inv .Stderr = ptty .Output ()
165204 inv .Stdin = ptty .Input ()
166- return value , inv .WithContext (context . Background () ).Run ()
205+ return value , inv .WithContext (ctx ).Run ()
167206}
168207
169208func TestPasswordTerminalState (t * testing.T ) {
0 commit comments