@@ -5,12 +5,14 @@ import (
5
5
"bytes"
6
6
"context"
7
7
"io"
8
+ "os"
8
9
"strings"
9
10
"sync/atomic"
10
11
"testing"
11
12
"time"
12
13
13
14
"github.com/google/uuid"
15
+ "github.com/stretchr/testify/assert"
14
16
"github.com/stretchr/testify/require"
15
17
"golang.org/x/xerrors"
16
18
@@ -25,9 +27,31 @@ import (
25
27
func TestAgent (t * testing.T ) {
26
28
t .Parallel ()
27
29
30
+ waitLines := func (t * testing.T , output <- chan string , lines ... string ) error {
31
+ t .Helper ()
32
+
33
+ var got []string
34
+ outerLoop:
35
+ for _ , want := range lines {
36
+ for {
37
+ select {
38
+ case line := <- output :
39
+ got = append (got , line )
40
+ if strings .Contains (line , want ) {
41
+ continue outerLoop
42
+ }
43
+ case <- time .After (testutil .WaitShort ):
44
+ assert .Failf (t , "timed out waiting for line" , "want: %q; got: %q" , want , got )
45
+ return xerrors .Errorf ("timed out waiting for line: %q; got: %q" , want , got )
46
+ }
47
+ }
48
+ }
49
+ return nil
50
+ }
51
+
28
52
for _ , tc := range []struct {
29
53
name string
30
- iter []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error
54
+ iter []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error
31
55
logs chan []codersdk.WorkspaceAgentLog
32
56
opts cliui.AgentOptions
33
57
want []string
@@ -38,12 +62,15 @@ func TestAgent(t *testing.T) {
38
62
opts : cliui.AgentOptions {
39
63
FetchInterval : time .Millisecond ,
40
64
},
41
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
42
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
65
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
66
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
43
67
agent .Status = codersdk .WorkspaceAgentConnecting
44
68
return nil
45
69
},
46
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
70
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
71
+ return waitLines (t , output , "⧗ Waiting for the workspace agent to connect" )
72
+ },
73
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
47
74
agent .Status = codersdk .WorkspaceAgentConnected
48
75
agent .FirstConnectedAt = ptr .Ref (time .Now ())
49
76
return nil
@@ -62,12 +89,15 @@ func TestAgent(t *testing.T) {
62
89
opts : cliui.AgentOptions {
63
90
FetchInterval : time .Millisecond ,
64
91
},
65
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
66
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
92
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
93
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
67
94
agent .Status = codersdk .WorkspaceAgentConnecting
68
95
return nil
69
96
},
70
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
97
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
98
+ return waitLines (t , output , "⧗ Waiting for the workspace agent to connect" )
99
+ },
100
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
71
101
agent .Status = codersdk .WorkspaceAgentConnected
72
102
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleStartTimeout
73
103
agent .FirstConnectedAt = ptr .Ref (time .Now ())
@@ -87,18 +117,24 @@ func TestAgent(t *testing.T) {
87
117
opts : cliui.AgentOptions {
88
118
FetchInterval : 1 * time .Millisecond ,
89
119
},
90
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
91
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
120
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
121
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
92
122
agent .Status = codersdk .WorkspaceAgentConnecting
93
123
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleStarting
94
124
agent .StartedAt = ptr .Ref (time .Now ())
95
125
return nil
96
126
},
97
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
127
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
128
+ return waitLines (t , output , "⧗ Waiting for the workspace agent to connect" )
129
+ },
130
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
98
131
agent .Status = codersdk .WorkspaceAgentTimeout
99
132
return nil
100
133
},
101
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
134
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
135
+ return waitLines (t , output , "The workspace agent is having trouble connecting, wait for it to connect or restart your workspace." )
136
+ },
137
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
102
138
agent .Status = codersdk .WorkspaceAgentConnected
103
139
agent .FirstConnectedAt = ptr .Ref (time .Now ())
104
140
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleReady
@@ -120,8 +156,8 @@ func TestAgent(t *testing.T) {
120
156
opts : cliui.AgentOptions {
121
157
FetchInterval : 1 * time .Millisecond ,
122
158
},
123
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
124
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
159
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
160
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
125
161
agent .Status = codersdk .WorkspaceAgentDisconnected
126
162
agent .FirstConnectedAt = ptr .Ref (time .Now ().Add (- 1 * time .Minute ))
127
163
agent .LastConnectedAt = ptr .Ref (time .Now ().Add (- 1 * time .Minute ))
@@ -131,7 +167,10 @@ func TestAgent(t *testing.T) {
131
167
agent .ReadyAt = ptr .Ref (time .Now ())
132
168
return nil
133
169
},
134
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
170
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
171
+ return waitLines (t , output , "⧗ The workspace agent lost connection" )
172
+ },
173
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
135
174
agent .Status = codersdk .WorkspaceAgentConnected
136
175
agent .DisconnectedAt = nil
137
176
agent .LastConnectedAt = ptr .Ref (time .Now ())
@@ -151,8 +190,8 @@ func TestAgent(t *testing.T) {
151
190
FetchInterval : time .Millisecond ,
152
191
Wait : true ,
153
192
},
154
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
155
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
193
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
194
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , logs chan []codersdk.WorkspaceAgentLog ) error {
156
195
agent .Status = codersdk .WorkspaceAgentConnected
157
196
agent .FirstConnectedAt = ptr .Ref (time .Now ())
158
197
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleStarting
@@ -170,7 +209,7 @@ func TestAgent(t *testing.T) {
170
209
}
171
210
return nil
172
211
},
173
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
212
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , logs chan []codersdk.WorkspaceAgentLog ) error {
174
213
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleReady
175
214
agent .ReadyAt = ptr .Ref (time .Now ())
176
215
logs <- []codersdk.WorkspaceAgentLog {
@@ -195,8 +234,8 @@ func TestAgent(t *testing.T) {
195
234
FetchInterval : time .Millisecond ,
196
235
Wait : true ,
197
236
},
198
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
199
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
237
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
238
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , output <- chan string , logs chan []codersdk.WorkspaceAgentLog ) error {
200
239
agent .Status = codersdk .WorkspaceAgentConnected
201
240
agent .FirstConnectedAt = ptr .Ref (time .Now ())
202
241
agent .StartedAt = ptr .Ref (time .Now ())
@@ -224,8 +263,8 @@ func TestAgent(t *testing.T) {
224
263
opts : cliui.AgentOptions {
225
264
FetchInterval : time .Millisecond ,
226
265
},
227
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
228
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
266
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
267
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , output <- chan string , logs chan []codersdk.WorkspaceAgentLog ) error {
229
268
agent .Status = codersdk .WorkspaceAgentDisconnected
230
269
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleOff
231
270
return nil
@@ -239,8 +278,8 @@ func TestAgent(t *testing.T) {
239
278
FetchInterval : time .Millisecond ,
240
279
Wait : true ,
241
280
},
242
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
243
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
281
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
282
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , output <- chan string , logs chan []codersdk.WorkspaceAgentLog ) error {
244
283
agent .Status = codersdk .WorkspaceAgentConnected
245
284
agent .FirstConnectedAt = ptr .Ref (time .Now ())
246
285
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleStarting
@@ -253,7 +292,10 @@ func TestAgent(t *testing.T) {
253
292
}
254
293
return nil
255
294
},
256
- func (_ context.Context , agent * codersdk.WorkspaceAgent , logs chan []codersdk.WorkspaceAgentLog ) error {
295
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
296
+ return waitLines (t , output , "Hello world" )
297
+ },
298
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
257
299
agent .ReadyAt = ptr .Ref (time .Now ())
258
300
agent .LifecycleState = codersdk .WorkspaceAgentLifecycleShuttingDown
259
301
return nil
@@ -272,12 +314,15 @@ func TestAgent(t *testing.T) {
272
314
FetchInterval : time .Millisecond ,
273
315
Wait : true ,
274
316
},
275
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
276
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
317
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
318
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
277
319
agent .Status = codersdk .WorkspaceAgentConnecting
278
320
return nil
279
321
},
280
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
322
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
323
+ return waitLines (t , output , "⧗ Waiting for the workspace agent to connect" )
324
+ },
325
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
281
326
return xerrors .New ("bad" )
282
327
},
283
328
},
@@ -292,13 +337,16 @@ func TestAgent(t *testing.T) {
292
337
FetchInterval : time .Millisecond ,
293
338
Wait : true ,
294
339
},
295
- iter : []func (context.Context , * codersdk.WorkspaceAgent , chan []codersdk.WorkspaceAgentLog ) error {
296
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
340
+ iter : []func (context.Context , * testing. T , * codersdk.WorkspaceAgent , <- chan string , chan []codersdk.WorkspaceAgentLog ) error {
341
+ func (_ context.Context , _ * testing. T , agent * codersdk.WorkspaceAgent , _ <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
297
342
agent .Status = codersdk .WorkspaceAgentTimeout
298
343
agent .TroubleshootingURL = "https://troubleshoot"
299
344
return nil
300
345
},
301
- func (_ context.Context , agent * codersdk.WorkspaceAgent , _ chan []codersdk.WorkspaceAgentLog ) error {
346
+ func (_ context.Context , t * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
347
+ return waitLines (t , output , "The workspace agent is having trouble connecting, wait for it to connect or restart your workspace." )
348
+ },
349
+ func (_ context.Context , _ * testing.T , agent * codersdk.WorkspaceAgent , output <- chan string , _ chan []codersdk.WorkspaceAgentLog ) error {
302
350
return xerrors .New ("bad" )
303
351
},
304
352
},
@@ -317,21 +365,27 @@ func TestAgent(t *testing.T) {
317
365
ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitShort )
318
366
defer cancel ()
319
367
320
- var buf bytes.Buffer
368
+ r , w , err := os .Pipe ()
369
+ require .NoError (t , err , "create pipe failed" )
370
+ defer r .Close ()
371
+ defer w .Close ()
372
+
321
373
agent := codersdk.WorkspaceAgent {
322
374
ID : uuid .New (),
323
375
Status : codersdk .WorkspaceAgentConnecting ,
324
376
CreatedAt : time .Now (),
325
377
LifecycleState : codersdk .WorkspaceAgentLifecycleCreated ,
326
378
}
379
+ output := make (chan string , 100 ) // Buffered to avoid blocking, overflow is discarded.
327
380
logs := make (chan []codersdk.WorkspaceAgentLog , 1 )
328
381
329
382
cmd := & clibase.Cmd {
330
383
Handler : func (inv * clibase.Invocation ) error {
331
384
tc .opts .Fetch = func (_ context.Context , _ uuid.UUID ) (codersdk.WorkspaceAgent , error ) {
385
+ t .Log ("iter" , len (tc .iter ))
332
386
var err error
333
387
if len (tc .iter ) > 0 {
334
- err = tc .iter [0 ](ctx , & agent , logs )
388
+ err = tc .iter [0 ](ctx , t , & agent , output , logs )
335
389
tc .iter = tc .iter [1 :]
336
390
}
337
391
return agent , err
@@ -352,27 +406,25 @@ func TestAgent(t *testing.T) {
352
406
close (fetchLogs )
353
407
return fetchLogs , closeFunc (func () error { return nil }), nil
354
408
}
355
- err := cliui .Agent (inv .Context (), & buf , uuid .Nil , tc .opts )
409
+ err := cliui .Agent (inv .Context (), w , uuid .Nil , tc .opts )
410
+ _ = w .Close ()
356
411
return err
357
412
},
358
413
}
359
414
inv := cmd .Invoke ()
360
415
361
- w := clitest .StartWithWaiter (t , inv )
362
- if tc .wantErr {
363
- w .RequireError ()
364
- } else {
365
- w .RequireSuccess ()
366
- }
416
+ waiter := clitest .StartWithWaiter (t , inv )
367
417
368
- s := bufio .NewScanner (& buf )
418
+ s := bufio .NewScanner (r )
369
419
for s .Scan () {
370
420
line := s .Text ()
371
421
t .Log (line )
422
+ select {
423
+ case output <- line :
424
+ default :
425
+ t .Logf ("output overflow: %s" , line )
426
+ }
372
427
if len (tc .want ) == 0 {
373
- for i := 0 ; i < 5 ; i ++ {
374
- t .Log (line )
375
- }
376
428
require .Fail (t , "unexpected line" , line )
377
429
}
378
430
require .Contains (t , line , tc .want [0 ])
@@ -382,6 +434,12 @@ func TestAgent(t *testing.T) {
382
434
if len (tc .want ) > 0 {
383
435
require .Fail (t , "missing lines: " + strings .Join (tc .want , ", " ))
384
436
}
437
+
438
+ if tc .wantErr {
439
+ waiter .RequireError ()
440
+ } else {
441
+ waiter .RequireSuccess ()
442
+ }
385
443
})
386
444
}
387
445
0 commit comments