@@ -212,6 +212,7 @@ func (w *fakeWatcher) sendEventWaitNextCalled(ctx context.Context, event fsnotif
212212
213213// fakeSubAgentClient implements SubAgentClient for testing purposes.
214214type fakeSubAgentClient struct {
215+ logger slog.Logger
215216 agents map [uuid.UUID ]agentcontainers.SubAgent
216217
217218 listErrC chan error // If set, send to return error, close to return nil.
@@ -240,6 +241,7 @@ func (m *fakeSubAgentClient) List(ctx context.Context) ([]agentcontainers.SubAge
240241}
241242
242243func (m * fakeSubAgentClient ) Create (ctx context.Context , agent agentcontainers.SubAgent ) (agentcontainers.SubAgent , error ) {
244+ m .logger .Debug (ctx , "creating sub agent" , slog .F ("agent" , agent ))
243245 if m .createErrC != nil {
244246 select {
245247 case <- ctx .Done ():
@@ -261,6 +263,7 @@ func (m *fakeSubAgentClient) Create(ctx context.Context, agent agentcontainers.S
261263}
262264
263265func (m * fakeSubAgentClient ) Delete (ctx context.Context , id uuid.UUID ) error {
266+ m .logger .Debug (ctx , "deleting sub agent" , slog .F ("id" , id .String ()))
264267 if m .deleteErrC != nil {
265268 select {
266269 case <- ctx .Done ():
@@ -1245,6 +1248,7 @@ func TestAPI(t *testing.T) {
12451248 mClock = quartz .NewMock (t )
12461249 mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
12471250 fakeSAC = & fakeSubAgentClient {
1251+ logger : logger .Named ("fakeSubAgentClient" ),
12481252 createErrC : make (chan error , 1 ),
12491253 deleteErrC : make (chan error , 1 ),
12501254 }
@@ -1270,7 +1274,7 @@ func TestAPI(t *testing.T) {
12701274
12711275 mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
12721276 Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1273- }, nil ).Times (1 + 3 ) // 1 initial call + 3 updates.
1277+ }, nil ).Times (3 ) // 1 initial call + 2 updates.
12741278 gomock .InOrder (
12751279 mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "test-container-id" ).Return (runtime .GOARCH , nil ),
12761280 mCCLI .EXPECT ().ExecAs (gomock .Any (), "test-container-id" , "root" , "mkdir" , "-p" , "/.coder-agent" ).Return (nil , nil ),
@@ -1315,19 +1319,20 @@ func TestAPI(t *testing.T) {
13151319 tickerTrap .MustWait (ctx ).MustRelease (ctx )
13161320 tickerTrap .Close ()
13171321
1318- // Ensure we only inject the agent once .
1319- for i := range 3 {
1320- _ , aw := mClock . AdvanceNext ( )
1321- aw . MustWait ( ctx )
1322+ // Refresh twice to ensure idempotency of agent creation .
1323+ err = api . RefreshContainers ( ctx )
1324+ require . NoError ( t , err , "refresh containers should not fail" )
1325+ t . Logf ( "Agents created: %d, deleted: %d" , len ( fakeSAC . created ), len ( fakeSAC . deleted ) )
13221326
1323- t .Logf ("Iteration %d: agents created: %d" , i + 1 , len (fakeSAC .created ))
1327+ err = api .RefreshContainers (ctx )
1328+ require .NoError (t , err , "refresh containers should not fail" )
1329+ t .Logf ("Agents created: %d, deleted: %d" , len (fakeSAC .created ), len (fakeSAC .deleted ))
13241330
1325- // Verify agent was created.
1326- require .Len (t , fakeSAC .created , 1 )
1327- assert .Equal (t , "test-container" , fakeSAC .created [0 ].Name )
1328- assert .Equal (t , "/workspaces" , fakeSAC .created [0 ].Directory )
1329- assert .Len (t , fakeSAC .deleted , 0 )
1330- }
1331+ // Verify agent was created.
1332+ require .Len (t , fakeSAC .created , 1 )
1333+ assert .Equal (t , "test-container" , fakeSAC .created [0 ].Name )
1334+ assert .Equal (t , "/workspaces" , fakeSAC .created [0 ].Directory )
1335+ assert .Len (t , fakeSAC .deleted , 0 )
13311336
13321337 t .Log ("Agent injected successfully, now testing reinjection into the same container..." )
13331338
@@ -1349,32 +1354,23 @@ func TestAPI(t *testing.T) {
13491354 // Expect the agent to be reinjected.
13501355 mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
13511356 Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1352- }, nil ).Times (3 ) // 3 updates .
1357+ }, nil ).Times (1 ) // 1 update .
13531358 gomock .InOrder (
13541359 mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "test-container-id" ).Return (runtime .GOARCH , nil ),
13551360 mCCLI .EXPECT ().ExecAs (gomock .Any (), "test-container-id" , "root" , "mkdir" , "-p" , "/.coder-agent" ).Return (nil , nil ),
13561361 mCCLI .EXPECT ().Copy (gomock .Any (), "test-container-id" , coderBin , "/.coder-agent/coder" ).Return (nil ),
13571362 mCCLI .EXPECT ().ExecAs (gomock .Any (), "test-container-id" , "root" , "chmod" , "0755" , "/.coder-agent" , "/.coder-agent/coder" ).Return (nil , nil ),
13581363 )
13591364
1360- // Allow agent reinjection to succeed.
1361- testutil .RequireSend (ctx , t , fakeDCCLI .execErrC , func (cmd string , args ... string ) error {
1362- assert .Equal (t , "pwd" , cmd )
1363- assert .Empty (t , args )
1364- return nil
1365- }) // Exec pwd.
1366-
1367- // Ensure we only inject the agent once.
1368- for i := range 3 {
1369- _ , aw := mClock .AdvanceNext ()
1370- aw .MustWait (ctx )
1365+ // Agent reinjection will succeed and we will not re-create the
1366+ // agent, nor re-probe pwd.
1367+ err = api .RefreshContainers (ctx )
1368+ require .NoError (t , err , "refresh containers should not fail" )
1369+ t .Logf ("Agents created: %d, deleted: %d" , len (fakeSAC .created ), len (fakeSAC .deleted ))
13711370
1372- t .Logf ("Iteration %d: agents created: %d" , i + 1 , len (fakeSAC .created ))
1373-
1374- // Verify that the agent was reused.
1375- require .Len (t , fakeSAC .created , 1 )
1376- assert .Len (t , fakeSAC .deleted , 0 )
1377- }
1371+ // Verify that the agent was reused.
1372+ require .Len (t , fakeSAC .created , 1 )
1373+ assert .Len (t , fakeSAC .deleted , 0 )
13781374
13791375 t .Log ("Agent reinjected successfully, now testing agent deletion and recreation..." )
13801376
@@ -1383,7 +1379,7 @@ func TestAPI(t *testing.T) {
13831379 // Expect the agent to be injected.
13841380 mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
13851381 Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1386- }, nil ).Times (3 ) // 3 updates .
1382+ }, nil ).Times (1 ) // 1 update .
13871383 gomock .InOrder (
13881384 mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "new-test-container-id" ).Return (runtime .GOARCH , nil ),
13891385 mCCLI .EXPECT ().ExecAs (gomock .Any (), "new-test-container-id" , "root" , "mkdir" , "-p" , "/.coder-agent" ).Return (nil , nil ),
@@ -1404,7 +1400,20 @@ func TestAPI(t *testing.T) {
14041400 })
14051401 <- terminated
14061402
1407- // Simulate the agent deletion.
1403+ fakeDCCLI .readConfig .MergedConfiguration .Customizations .Coder = []agentcontainers.CoderCustomization {
1404+ {
1405+ DisplayApps : map [codersdk.DisplayApp ]bool {
1406+ codersdk .DisplayAppSSH : true ,
1407+ codersdk .DisplayAppWebTerminal : true ,
1408+ codersdk .DisplayAppVSCodeDesktop : true ,
1409+ codersdk .DisplayAppVSCodeInsiders : true ,
1410+ codersdk .DisplayAppPortForward : true ,
1411+ },
1412+ },
1413+ }
1414+
1415+ // Simulate the agent deletion (this happens because the
1416+ // devcontainer configuration changed).
14081417 testutil .RequireSend (ctx , t , fakeSAC .deleteErrC , nil )
14091418 // Expect the agent to be recreated.
14101419 testutil .RequireSend (ctx , t , fakeSAC .createErrC , nil )
@@ -1414,13 +1423,9 @@ func TestAPI(t *testing.T) {
14141423 return nil
14151424 }) // Exec pwd.
14161425
1417- // Advance the clock to run updaterLoop.
1418- for i := range 3 {
1419- _ , aw := mClock .AdvanceNext ()
1420- aw .MustWait (ctx )
1421-
1422- t .Logf ("Iteration %d: agents created: %d, deleted: %d" , i + 1 , len (fakeSAC .created ), len (fakeSAC .deleted ))
1423- }
1426+ err = api .RefreshContainers (ctx )
1427+ require .NoError (t , err , "refresh containers should not fail" )
1428+ t .Logf ("Agents created: %d, deleted: %d" , len (fakeSAC .created ), len (fakeSAC .deleted ))
14241429
14251430 // Verify the agent was deleted and recreated.
14261431 require .Len (t , fakeSAC .deleted , 1 , "there should be one deleted agent after recreation" )
@@ -1453,6 +1458,7 @@ func TestAPI(t *testing.T) {
14531458 mClock = quartz .NewMock (t )
14541459 mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
14551460 fakeSAC = & fakeSubAgentClient {
1461+ logger : logger .Named ("fakeSubAgentClient" ),
14561462 agents : map [uuid.UUID ]agentcontainers.SubAgent {
14571463 existingAgentID : existingAgent ,
14581464 },
@@ -1577,7 +1583,10 @@ func TestAPI(t *testing.T) {
15771583 logger = testutil .Logger (t )
15781584 mClock = quartz .NewMock (t )
15791585 mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
1580- fSAC = & fakeSubAgentClient {createErrC : make (chan error , 1 )}
1586+ fSAC = & fakeSubAgentClient {
1587+ logger : logger .Named ("fakeSubAgentClient" ),
1588+ createErrC : make (chan error , 1 ),
1589+ }
15811590 fDCCLI = & fakeDevcontainerCLI {
15821591 readConfig : agentcontainers.DevcontainerConfig {
15831592 MergedConfiguration : agentcontainers.DevcontainerConfiguration {
0 commit comments