Skip to content

Commit 5deab9f

Browse files
test: wait for devcontainer readiness (#25567)
1 parent 3a2a976 commit 5deab9f

3 files changed

Lines changed: 84 additions & 12 deletions

File tree

cli/open_test.go

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,72 @@ func TestOpenVSCodeDevContainer(t *testing.T) {
433433
agentcontainers.WithContainerLabelIncludeFilter("coder.test", t.Name()),
434434
)
435435
})
436-
coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).AgentNames([]string{parentAgentName, devcontainerName}).Wait()
436+
resources := coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).AgentNames([]string{parentAgentName}).Wait()
437+
parentAgent := coderdtest.RequireWorkspaceAgentByName(t, resources, parentAgentName)
438+
parentAgentID := parentAgent.ID
439+
440+
// Agent connection does not guarantee the parent agent's container API
441+
// has completed its first devcontainer update. Wait for that endpoint so
442+
// parallel open commands do not race the initial cache population.
443+
ctx := testutil.Context(t, testutil.WaitSuperLong)
444+
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
445+
resp, err := client.WorkspaceAgentListContainers(ctx, parentAgentID, nil)
446+
if err != nil {
447+
t.Logf("list containers: %v", err)
448+
return false
449+
}
450+
var devcontainerAgentID uuid.UUID
451+
for _, dc := range resp.Devcontainers {
452+
if dc.ID != devcontainerID {
453+
continue
454+
}
455+
if dc.Status != codersdk.WorkspaceAgentDevcontainerStatusRunning {
456+
t.Logf("devcontainer %s status %q", devcontainerName, dc.Status)
457+
return false
458+
}
459+
if dc.Container == nil {
460+
t.Logf("devcontainer %s missing container", devcontainerName)
461+
return false
462+
}
463+
if dc.Container.ID != containerID {
464+
t.Logf("devcontainer %s has container %s, want %s", devcontainerName, dc.Container.ID, containerID)
465+
return false
466+
}
467+
if dc.Agent == nil {
468+
t.Logf("devcontainer %s missing subagent", devcontainerName)
469+
return false
470+
}
471+
if dc.Agent.Name != devcontainerName {
472+
t.Logf("devcontainer %s has subagent %s, want %s", devcontainerName, dc.Agent.Name, devcontainerName)
473+
return false
474+
}
475+
devcontainerAgentID = dc.Agent.ID
476+
}
477+
if devcontainerAgentID == uuid.Nil {
478+
t.Logf("devcontainer %s not found", devcontainerName)
479+
return false
480+
}
481+
482+
workspace, err := client.Workspace(ctx, workspace.ID)
483+
if err != nil {
484+
t.Logf("get workspace: %v", err)
485+
return false
486+
}
487+
for _, resource := range workspace.LatestBuild.Resources {
488+
for _, workspaceAgent := range resource.Agents {
489+
if workspaceAgent.ID != devcontainerAgentID {
490+
continue
491+
}
492+
if workspaceAgent.Status != codersdk.WorkspaceAgentConnected {
493+
t.Logf("devcontainer subagent %s status %q", devcontainerAgentID, workspaceAgent.Status)
494+
return false
495+
}
496+
return true
497+
}
498+
}
499+
t.Logf("devcontainer subagent %s not found in workspace", devcontainerAgentID)
500+
return false
501+
}, testutil.IntervalMedium, "devcontainer did not become ready")
437502

438503
insideWorkspaceEnv := map[string]string{
439504
"CODER": "true",

coderd/coderdtest/coderdtest.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,22 @@ func NewWorkspaceAgentWaiter(t testing.TB, client *codersdk.Client, workspaceID
12781278
}
12791279
}
12801280

1281+
// RequireWorkspaceAgentByName avoids weak nil UUID assertions when a fixture requires a specific agent.
1282+
func RequireWorkspaceAgentByName(t testing.TB, resources []codersdk.WorkspaceResource, name string) codersdk.WorkspaceAgent {
1283+
t.Helper()
1284+
1285+
for _, resource := range resources {
1286+
for _, agent := range resource.Agents {
1287+
if agent.Name == name {
1288+
return agent
1289+
}
1290+
}
1291+
}
1292+
1293+
require.FailNowf(t, "workspace agent not found", "workspace agent %q not found in resources", name)
1294+
return codersdk.WorkspaceAgent{}
1295+
}
1296+
12811297
// AgentNames instructs the waiter to wait for the given, named agents to be connected and will
12821298
// return even if other agents are not connected.
12831299
func (w WorkspaceAgentWaiter) AgentNames(names []string) WorkspaceAgentWaiter {

coderd/workspaceapps/db_test.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,8 @@ func Test_ResolveRequest(t *testing.T) {
218218

219219
_ = agenttest.New(t, client.URL, agentAuthToken)
220220
resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID, agentName)
221-
222-
agentID := uuid.Nil
223-
for _, resource := range resources {
224-
for _, agnt := range resource.Agents {
225-
if agnt.Name == agentName {
226-
agentID = agnt.ID
227-
break
228-
}
229-
}
230-
}
231-
require.NotEqual(t, uuid.Nil, agentID)
221+
agent := coderdtest.RequireWorkspaceAgentByName(t, resources, agentName)
222+
agentID := agent.ID
232223

233224
// Reset audit logs so cleanup check can pass.
234225
connLogger.Reset()

0 commit comments

Comments
 (0)