@@ -212,6 +212,7 @@ func (w *fakeWatcher) sendEventWaitNextCalled(ctx context.Context, event fsnotif
212
212
213
213
// fakeSubAgentClient implements SubAgentClient for testing purposes.
214
214
type fakeSubAgentClient struct {
215
+ logger slog.Logger
215
216
agents map [uuid.UUID ]agentcontainers.SubAgent
216
217
217
218
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
240
241
}
241
242
242
243
func (m * fakeSubAgentClient ) Create (ctx context.Context , agent agentcontainers.SubAgent ) (agentcontainers.SubAgent , error ) {
244
+ m .logger .Debug (ctx , "creating sub agent" , slog .F ("agent" , agent ))
243
245
if m .createErrC != nil {
244
246
select {
245
247
case <- ctx .Done ():
@@ -261,6 +263,7 @@ func (m *fakeSubAgentClient) Create(ctx context.Context, agent agentcontainers.S
261
263
}
262
264
263
265
func (m * fakeSubAgentClient ) Delete (ctx context.Context , id uuid.UUID ) error {
266
+ m .logger .Debug (ctx , "deleting sub agent" , slog .F ("id" , id .String ()))
264
267
if m .deleteErrC != nil {
265
268
select {
266
269
case <- ctx .Done ():
@@ -1245,6 +1248,7 @@ func TestAPI(t *testing.T) {
1245
1248
mClock = quartz .NewMock (t )
1246
1249
mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
1247
1250
fakeSAC = & fakeSubAgentClient {
1251
+ logger : logger .Named ("fakeSubAgentClient" ),
1248
1252
createErrC : make (chan error , 1 ),
1249
1253
deleteErrC : make (chan error , 1 ),
1250
1254
}
@@ -1270,7 +1274,7 @@ func TestAPI(t *testing.T) {
1270
1274
1271
1275
mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
1272
1276
Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1273
- }, nil ).Times (1 + 3 ) // 1 initial call + 3 updates.
1277
+ }, nil ).Times (3 ) // 1 initial call + 2 updates.
1274
1278
gomock .InOrder (
1275
1279
mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "test-container-id" ).Return (runtime .GOARCH , nil ),
1276
1280
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) {
1315
1319
tickerTrap .MustWait (ctx ).MustRelease (ctx )
1316
1320
tickerTrap .Close ()
1317
1321
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 ) )
1322
1326
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 ))
1324
1330
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 )
1331
1336
1332
1337
t .Log ("Agent injected successfully, now testing reinjection into the same container..." )
1333
1338
@@ -1349,32 +1354,23 @@ func TestAPI(t *testing.T) {
1349
1354
// Expect the agent to be reinjected.
1350
1355
mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
1351
1356
Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1352
- }, nil ).Times (3 ) // 3 updates .
1357
+ }, nil ).Times (1 ) // 1 update .
1353
1358
gomock .InOrder (
1354
1359
mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "test-container-id" ).Return (runtime .GOARCH , nil ),
1355
1360
mCCLI .EXPECT ().ExecAs (gomock .Any (), "test-container-id" , "root" , "mkdir" , "-p" , "/.coder-agent" ).Return (nil , nil ),
1356
1361
mCCLI .EXPECT ().Copy (gomock .Any (), "test-container-id" , coderBin , "/.coder-agent/coder" ).Return (nil ),
1357
1362
mCCLI .EXPECT ().ExecAs (gomock .Any (), "test-container-id" , "root" , "chmod" , "0755" , "/.coder-agent" , "/.coder-agent/coder" ).Return (nil , nil ),
1358
1363
)
1359
1364
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 ))
1371
1370
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 )
1378
1374
1379
1375
t .Log ("Agent reinjected successfully, now testing agent deletion and recreation..." )
1380
1376
@@ -1383,7 +1379,7 @@ func TestAPI(t *testing.T) {
1383
1379
// Expect the agent to be injected.
1384
1380
mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
1385
1381
Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1386
- }, nil ).Times (3 ) // 3 updates .
1382
+ }, nil ).Times (1 ) // 1 update .
1387
1383
gomock .InOrder (
1388
1384
mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), "new-test-container-id" ).Return (runtime .GOARCH , nil ),
1389
1385
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) {
1404
1400
})
1405
1401
<- terminated
1406
1402
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).
1408
1417
testutil .RequireSend (ctx , t , fakeSAC .deleteErrC , nil )
1409
1418
// Expect the agent to be recreated.
1410
1419
testutil .RequireSend (ctx , t , fakeSAC .createErrC , nil )
@@ -1414,13 +1423,9 @@ func TestAPI(t *testing.T) {
1414
1423
return nil
1415
1424
}) // Exec pwd.
1416
1425
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 ))
1424
1429
1425
1430
// Verify the agent was deleted and recreated.
1426
1431
require .Len (t , fakeSAC .deleted , 1 , "there should be one deleted agent after recreation" )
@@ -1453,6 +1458,7 @@ func TestAPI(t *testing.T) {
1453
1458
mClock = quartz .NewMock (t )
1454
1459
mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
1455
1460
fakeSAC = & fakeSubAgentClient {
1461
+ logger : logger .Named ("fakeSubAgentClient" ),
1456
1462
agents : map [uuid.UUID ]agentcontainers.SubAgent {
1457
1463
existingAgentID : existingAgent ,
1458
1464
},
@@ -1577,7 +1583,10 @@ func TestAPI(t *testing.T) {
1577
1583
logger = testutil .Logger (t )
1578
1584
mClock = quartz .NewMock (t )
1579
1585
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
+ }
1581
1590
fDCCLI = & fakeDevcontainerCLI {
1582
1591
readConfig : agentcontainers.DevcontainerConfig {
1583
1592
MergedConfiguration : agentcontainers.DevcontainerConfiguration {
0 commit comments