@@ -36,6 +36,7 @@ import (
36
36
"github.com/coder/coder/v2/pty"
37
37
"github.com/coder/coder/v2/testutil"
38
38
"github.com/coder/quartz"
39
+ "github.com/coder/websocket"
39
40
)
40
41
41
42
// fakeContainerCLI implements the agentcontainers.ContainerCLI interface for
@@ -441,6 +442,73 @@ func TestAPI(t *testing.T) {
441
442
logbuf .Reset ()
442
443
})
443
444
445
+ t .Run ("Watch" , func (t * testing.T ) {
446
+ t .Parallel ()
447
+
448
+ fakeContainer1 := fakeContainer (t )
449
+ fakeContainer2 := fakeContainer (t )
450
+ fakeContainer3 := fakeContainer (t )
451
+
452
+ makeResponse := func (cts ... codersdk.WorkspaceAgentContainer ) codersdk.WorkspaceAgentListContainersResponse {
453
+ return codersdk.WorkspaceAgentListContainersResponse {Containers : cts }
454
+ }
455
+
456
+ var (
457
+ ctx = testutil .Context (t , testutil .WaitShort )
458
+ mClock = quartz .NewMock (t )
459
+ updaterTickerTrap = mClock .Trap ().TickerFunc ("updaterLoop" )
460
+ mCtrl = gomock .NewController (t )
461
+ mLister = acmock .NewMockContainerCLI (mCtrl )
462
+ logger = slogtest .Make (t , & slogtest.Options {IgnoreErrors : true }).Leveled (slog .LevelDebug )
463
+ )
464
+
465
+ mLister .EXPECT ().List (gomock .Any ()).Return (makeResponse (), nil )
466
+
467
+ api := agentcontainers .NewAPI (logger ,
468
+ agentcontainers .WithClock (mClock ),
469
+ agentcontainers .WithContainerCLI (mLister ),
470
+ agentcontainers .WithContainerLabelIncludeFilter ("this.label.does.not.exist.ignore.devcontainers" , "true" ),
471
+ )
472
+ api .Start ()
473
+ defer api .Close ()
474
+
475
+ srv := httptest .NewServer (api .Routes ())
476
+ defer srv .Close ()
477
+
478
+ updaterTickerTrap .MustWait (ctx ).MustRelease (ctx )
479
+ defer updaterTickerTrap .Close ()
480
+
481
+ client , _ , err := websocket .Dial (ctx , srv .URL + "/watch" , nil )
482
+ require .NoError (t , err )
483
+
484
+ for _ , mockResponse := range []codersdk.WorkspaceAgentListContainersResponse {
485
+ makeResponse (),
486
+ makeResponse (fakeContainer1 ),
487
+ makeResponse (fakeContainer1 , fakeContainer2 ),
488
+ makeResponse (fakeContainer1 , fakeContainer2 , fakeContainer3 ),
489
+ makeResponse (fakeContainer1 , fakeContainer2 ),
490
+ makeResponse (fakeContainer1 ),
491
+ makeResponse (),
492
+ } {
493
+ mLister .EXPECT ().List (gomock .Any ()).Return (mockResponse , nil )
494
+
495
+ // Given: We allow the update loop to progress
496
+ _ , aw := mClock .AdvanceNext ()
497
+ aw .MustWait (ctx )
498
+
499
+ // When: We attempt to read a message from the socket.
500
+ mt , msg , err := client .Read (ctx )
501
+ require .NoError (t , err )
502
+ require .Equal (t , websocket .MessageText , mt )
503
+
504
+ // Then: We expect the receieved message matches the mocked response.
505
+ var got codersdk.WorkspaceAgentListContainersResponse
506
+ err = json .Unmarshal (msg , & got )
507
+ require .NoError (t , err )
508
+ require .Equal (t , mockResponse , got )
509
+ }
510
+ })
511
+
444
512
// List tests the API.getContainers method using a mock
445
513
// implementation. It specifically tests caching behavior.
446
514
t .Run ("List" , func (t * testing.T ) {
0 commit comments