Skip to content

Commit 9381e28

Browse files
test: add integration-style test
1 parent d744bd3 commit 9381e28

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

agent/agent_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,199 @@ func TestAgent_DevcontainersDisabledForSubAgent(t *testing.T) {
24582458
require.Contains(t, err.Error(), "Dev Container integration inside other Dev Containers is explicitly not supported.")
24592459
}
24602460

2461+
// TestAgent_DevcontainerPrebuildClaim tests that we correctly handle
2462+
// the claiming process for running devcontainers.
2463+
//
2464+
// You can run it manually as follows:
2465+
//
2466+
// CODER_TEST_USE_DOCKER=1 go test -count=1 ./agent -run TestAgent_DevcontainerPrebuildClaim
2467+
func TestAgent_DevcontainerPrebuildClaim(t *testing.T) {
2468+
if os.Getenv("CODER_TEST_USE_DOCKER") != "1" {
2469+
t.Skip("Set CODER_TEST_USE_DOCKER=1 to run this test")
2470+
}
2471+
if _, err := exec.LookPath("devcontainer"); err != nil {
2472+
t.Skip("This test requires the devcontainer CLI: npm install -g @devcontainers/cli")
2473+
}
2474+
2475+
pool, err := dockertest.NewPool("")
2476+
require.NoError(t, err, "Could not connect to docker")
2477+
2478+
var (
2479+
ctx = testutil.Context(t, testutil.WaitShort)
2480+
2481+
devcontainerID = uuid.New()
2482+
devcontainerLogSourceID = uuid.New()
2483+
2484+
workspaceFolder = filepath.Join(t.TempDir(), "project")
2485+
devcontainerPath = filepath.Join(workspaceFolder, ".devcontainer")
2486+
devcontainerConfig = filepath.Join(devcontainerPath, "devcontainer.json")
2487+
)
2488+
2489+
// Given: A devcontainer project.
2490+
t.Logf("Workspace folder: %s", workspaceFolder)
2491+
2492+
err = os.MkdirAll(devcontainerPath, 0o755)
2493+
require.NoError(t, err, "create dev container directory")
2494+
2495+
err = os.WriteFile(devcontainerConfig, []byte(`{
2496+
"name": "project",
2497+
"image": "busybox:latest",
2498+
"cmd": ["sleep", "infinity"],
2499+
"runArgs": ["--label=`+agentcontainers.DevcontainerIsTestRunLabel+`=true"],
2500+
"customizations": {
2501+
"coder": {
2502+
"apps": [{
2503+
"slug": "zed",
2504+
"url": "zed://ssh/${localEnv:CODER_WORKSPACE_AGENT_NAME}.${localEnv:CODER_WORKSPACE_NAME}.${localEnv:CODER_WORKSPACE_OWNER_NAME}.coder${containerWorkspaceFolder}"
2505+
}]
2506+
}
2507+
}
2508+
}`), 0o600)
2509+
require.NoError(t, err, "write devcontainer config")
2510+
2511+
// Given: A manifest with a devcontainer to be started.
2512+
manifest := agentsdk.Manifest{
2513+
OwnerName: "prebuilds",
2514+
WorkspaceName: "prebuilds-xyz-123",
2515+
2516+
Devcontainers: []codersdk.WorkspaceAgentDevcontainer{
2517+
{ID: devcontainerID, Name: "test", WorkspaceFolder: workspaceFolder},
2518+
},
2519+
Scripts: []codersdk.WorkspaceAgentScript{
2520+
{ID: devcontainerID, LogSourceID: devcontainerLogSourceID},
2521+
},
2522+
}
2523+
2524+
conn, client, _, _, _ := setupAgent(t, manifest, 0, func(_ *agenttest.Client, o *agent.Options) {
2525+
o.Devcontainers = true
2526+
o.DevcontainerAPIOptions = append(o.DevcontainerAPIOptions,
2527+
agentcontainers.WithContainerLabelIncludeFilter(agentcontainers.DevcontainerLocalFolderLabel, workspaceFolder),
2528+
agentcontainers.WithContainerLabelIncludeFilter(agentcontainers.DevcontainerIsTestRunLabel, "true"),
2529+
)
2530+
})
2531+
2532+
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
2533+
return slices.Contains(client.GetLifecycleStates(), codersdk.WorkspaceAgentLifecycleReady)
2534+
}, testutil.IntervalMedium, "agent not ready")
2535+
2536+
var dcPrebuild codersdk.WorkspaceAgentDevcontainer
2537+
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
2538+
resp, err := conn.ListContainers(ctx)
2539+
require.NoError(t, err)
2540+
2541+
for _, dc := range resp.Devcontainers {
2542+
if dc.Container == nil {
2543+
continue
2544+
}
2545+
2546+
v, ok := dc.Container.Labels[agentcontainers.DevcontainerLocalFolderLabel]
2547+
if ok && v == workspaceFolder {
2548+
dcPrebuild = dc
2549+
return true
2550+
}
2551+
}
2552+
2553+
return false
2554+
}, testutil.IntervalMedium, "devcontainer not found")
2555+
defer func() {
2556+
pool.Client.RemoveContainer(docker.RemoveContainerOptions{
2557+
ID: dcPrebuild.Container.ID,
2558+
RemoveVolumes: true,
2559+
Force: true,
2560+
})
2561+
}()
2562+
2563+
subAgents := client.GetSubAgents()
2564+
require.Len(t, subAgents, 1)
2565+
2566+
subAgent := subAgents[0]
2567+
subAgentID, err := uuid.FromBytes(subAgent.GetId())
2568+
require.NoError(t, err)
2569+
2570+
subAgentApps, err := client.GetSubAgentApps(subAgentID)
2571+
require.NoError(t, err)
2572+
require.Len(t, subAgentApps, 1)
2573+
2574+
subAgentApp := subAgentApps[0]
2575+
require.Equal(t, "zed://ssh/project.prebuilds-xyz-123.prebuilds.coder/workspaces/project", subAgentApp.GetUrl())
2576+
2577+
// Close the client and connection
2578+
client.Close()
2579+
conn.Close()
2580+
2581+
// Given: A manifest with a devcontainer to be started.
2582+
manifest = agentsdk.Manifest{
2583+
OwnerName: "user",
2584+
WorkspaceName: "user-workspace",
2585+
2586+
Devcontainers: []codersdk.WorkspaceAgentDevcontainer{
2587+
{ID: devcontainerID, Name: "test", WorkspaceFolder: workspaceFolder},
2588+
},
2589+
Scripts: []codersdk.WorkspaceAgentScript{
2590+
{ID: devcontainerID, LogSourceID: devcontainerLogSourceID},
2591+
},
2592+
}
2593+
2594+
conn, client, _, _, _ = setupAgent(t, manifest, 0, func(_ *agenttest.Client, o *agent.Options) {
2595+
o.Devcontainers = true
2596+
o.DevcontainerAPIOptions = append(o.DevcontainerAPIOptions,
2597+
agentcontainers.WithContainerLabelIncludeFilter(agentcontainers.DevcontainerLocalFolderLabel, workspaceFolder),
2598+
agentcontainers.WithContainerLabelIncludeFilter(agentcontainers.DevcontainerIsTestRunLabel, "true"),
2599+
)
2600+
})
2601+
2602+
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
2603+
return slices.Contains(client.GetLifecycleStates(), codersdk.WorkspaceAgentLifecycleReady)
2604+
}, testutil.IntervalMedium, "agent not ready")
2605+
2606+
var dcClaimed codersdk.WorkspaceAgentDevcontainer
2607+
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
2608+
resp, err := conn.ListContainers(ctx)
2609+
require.NoError(t, err)
2610+
2611+
for _, dc := range resp.Devcontainers {
2612+
if dc.Container == nil {
2613+
continue
2614+
}
2615+
2616+
v, ok := dc.Container.Labels[agentcontainers.DevcontainerLocalFolderLabel]
2617+
if ok && v == workspaceFolder {
2618+
dcClaimed = dc
2619+
return true
2620+
}
2621+
}
2622+
2623+
return false
2624+
}, testutil.IntervalMedium, "devcontainer not found")
2625+
defer func() {
2626+
if dcClaimed.Container.ID != dcPrebuild.Container.ID {
2627+
pool.Client.RemoveContainer(docker.RemoveContainerOptions{
2628+
ID: dcClaimed.Container.ID,
2629+
RemoveVolumes: true,
2630+
Force: true,
2631+
})
2632+
}
2633+
}()
2634+
2635+
// Then: We expect the claimed devcontainer and prebuild devcontainer
2636+
// to be using the same underlying container.
2637+
require.Equal(t, dcPrebuild.Container.ID, dcClaimed.Container.ID)
2638+
2639+
subAgents = client.GetSubAgents()
2640+
require.Len(t, subAgents, 1)
2641+
2642+
subAgent = subAgents[0]
2643+
subAgentID, err = uuid.FromBytes(subAgent.GetId())
2644+
require.NoError(t, err)
2645+
2646+
subAgentApps, err = client.GetSubAgentApps(subAgentID)
2647+
require.NoError(t, err)
2648+
require.Len(t, subAgentApps, 1)
2649+
2650+
subAgentApp = subAgentApps[0]
2651+
require.Equal(t, "zed://ssh/project.user-workspace.user.coder/workspaces/project", subAgentApp.GetUrl())
2652+
}
2653+
24612654
func TestAgent_Dial(t *testing.T) {
24622655
t.Parallel()
24632656

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy