Files
cleveragents-core/features/devcontainer_activation.feature

218 lines
12 KiB
Gherkin

Feature: Devcontainer Activation, Stop and Rebuild
As a CleverAgents developer
I want devcontainers to be lazily activated and manually stopped or rebuilt
So that containers start on demand and can be controlled explicitly
# Lazy activation
Scenario: Lazy activation succeeds on inactive container
Given a mock devcontainer CLI runner
And the runner configured for successful activation
When I activate container "01TESTLIFECYCLE0000000010" at "/workspace/project"
Then the container state should be "running"
And the container ID should be "aabbccddee0011223344"
And the workspace path should be "/workspaces/project"
And the runner should have received a devcontainer up call
Scenario: Lazy activation transitions to error on failure
Given a mock devcontainer CLI runner
And the runner configured for failed activation
When I attempt to activate container "01TESTLIFECYCLE0000000011" at "/workspace/project"
Then the activation should raise RuntimeError
And the container state for "01TESTLIFECYCLE0000000011" should be "failed"
# ── Manual stop ────────────────────────────────────────────
Scenario: Stop transitions active container to stopped
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000020" with container ID "ctr-123"
When I stop container "01TESTLIFECYCLE0000000020"
Then the container state for "01TESTLIFECYCLE0000000020" should be "stopped"
And the runner should have received a docker stop call
# ── Rebuild ────────────────────────────────────────────────
Scenario: Rebuild transitions stopped container to active
Given a mock devcontainer CLI runner
And the runner configured for successful activation
And a stopped container "01TESTLIFECYCLE0000000030"
When I rebuild container "01TESTLIFECYCLE0000000030" at "/workspace/project"
Then the container state for "01TESTLIFECYCLE0000000030" should be "running"
Scenario: Rebuild transitions error container to active
Given a mock devcontainer CLI runner
And the runner configured for successful activation
And an errored container "01TESTLIFECYCLE0000000031"
When I rebuild container "01TESTLIFECYCLE0000000031" at "/workspace/project"
Then the container state for "01TESTLIFECYCLE0000000031" should be "running"
# ── Argument validation ────────────────────────────────────
Scenario: Activate rejects empty resource_id
When I attempt to activate a container with empty resource_id
Then the activation should raise ValueError with "resource_id"
Scenario: Activate rejects empty workspace_folder
When I attempt to activate a container with empty workspace_folder
Then the activation should raise ValueError with "workspace_folder"
Scenario: Stop rejects empty resource_id
When I attempt to stop a container with empty resource_id
Then the stop should raise ValueError with "resource_id"
# ── Activate on already-running container ────────────────────
Scenario: Activate on already-running container raises ValueError
Given a mock devcontainer CLI runner
And the runner configured for successful activation
And an active container "01TESTLIFECYCLE0000000140" with container ID "ctr-dup"
When I attempt to activate container "01TESTLIFECYCLE0000000140" at "/workspace"
Then the activation should raise ValueError with "Invalid lifecycle transition"
# ── Stop container with no container_id ─────────────────────
Scenario: Stop container with no container_id skips docker stop
Given a mock devcontainer CLI runner
And an active container with no container_id "01TESTLIFECYCLE0000000150"
When I stop container "01TESTLIFECYCLE0000000150"
Then the container state for "01TESTLIFECYCLE0000000150" should be "stopped"
And the runner should not have received a docker stop call
# ── Activation fails when container_id is missing ────────────
Scenario: Activation fails when devcontainer up returns no container_id
Given a mock devcontainer CLI runner
And the runner configured for activation with no container_id
When I attempt to activate container "01TESTLIFECYCLE0000000160" at "/workspace"
Then the activation should raise RuntimeError
And the container state for "01TESTLIFECYCLE0000000160" should be "failed"
# ── Direct rebuild_container coverage ───────────────────────
Scenario: rebuild_container directly stops then reactivates
Given a mock devcontainer CLI runner
And the runner configured for successful activation
And a stopped container "01TESTLIFECYCLE0000000090"
When I call rebuild_container for "01TESTLIFECYCLE0000000090" at "/workspace"
Then the container state for "01TESTLIFECYCLE0000000090" should be "running"
Scenario: rebuild_container rejects empty resource_id
When I call rebuild_container with empty resource_id
Then the rebuild should raise ValueError with "resource_id"
Scenario: rebuild_container rejects empty workspace_folder
When I call rebuild_container with empty workspace_folder
Then the rebuild should raise ValueError with "workspace_folder"
# ── Stop container error path coverage ─────────────────────
Scenario: stop_container transitions to error when docker stop raises
Given a mock devcontainer CLI runner
And the runner configured to raise exception on stop
And an active container "01TESTLIFECYCLE0000000110" with container ID "ctr-sf"
When I attempt to stop container "01TESTLIFECYCLE0000000110"
Then the stop should raise RuntimeError
And the container state for "01TESTLIFECYCLE0000000110" should be "failed"
# ── Activate generic exception path coverage ───────────────
Scenario: activate_container transitions to error on generic exception
Given a mock devcontainer CLI runner
And the runner configured to raise generic exception on up
When I attempt to activate container "01TESTLIFECYCLE0000000120" at "/workspace"
Then the activation should raise RuntimeError
And the container state for "01TESTLIFECYCLE0000000120" should be "failed"
# ── Stop container non-zero return code (F2) ───────────────
Scenario: stop_container transitions to error when docker stop returns non-zero
Given a mock devcontainer CLI runner
And the runner configured for failed docker stop
And an active container "01TESTLIFECYCLE0000000170" with container ID "ctr-rc1"
When I attempt to stop container "01TESTLIFECYCLE0000000170"
Then the stop should raise RuntimeError
And the container state for "01TESTLIFECYCLE0000000170" should be "failed"
# ── R20: workspace_folder path validation ──────────────────
Scenario: Activate rejects relative workspace_folder
When I attempt to activate a container with relative workspace_folder
Then the activation should raise ValueError with "absolute path"
# ── S2: Activation timeout transitions to failed ───────────
Scenario: Activation timeout transitions container to failed state
Given a mock devcontainer CLI runner that times out
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000350"
When I attempt to activate the timed-out container
Then the activation should raise RuntimeError with "timed out"
And the tracker "01TESTLIFECYCLE0000000350" should be in "failed" state
# ── F4: Orphaned container cleanup on timeout ──────────────
Scenario: Activation timeout attempts to stop orphaned containers
Given a mock devcontainer CLI runner that times out with orphan containers
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000360"
When I attempt to activate the timed-out container with orphan cleanup
Then the activation should raise RuntimeError with "timed out"
And the runner should have attempted orphan container cleanup
# ── F6: R10 fix explicit assertion (container_id clearing) ─
Scenario: Stopped container has container_id cleared
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000380" with container ID "ctr-r10"
When I stop container "01TESTLIFECYCLE0000000380"
Then the container state for "01TESTLIFECYCLE0000000380" should be "stopped"
And the container_id for "01TESTLIFECYCLE0000000380" should be None
And the workspace_path for "01TESTLIFECYCLE0000000380" should be None
Scenario: Failed activation clears container_id
Given a mock devcontainer CLI runner
And the runner configured for failed activation
When I attempt to activate container "01TESTLIFECYCLE0000000381" at "/workspace/project"
Then the container state for "01TESTLIFECYCLE0000000381" should be "failed"
And the container_id for "01TESTLIFECYCLE0000000381" should be None
# ── R8-F2: stop_container early return on terminal state ────
Scenario: stop_container returns early when container already stopped
Given a mock devcontainer CLI runner
And a stopped container "01TESTLIFECYCLE0000000660"
When I stop container "01TESTLIFECYCLE0000000660" expecting early return
Then the container state for "01TESTLIFECYCLE0000000660" should be "stopped"
And the runner should not have received a docker stop call
Scenario: stop_container returns early when container already failed
Given a mock devcontainer CLI runner
And an errored container "01TESTLIFECYCLE0000000670"
When I stop container "01TESTLIFECYCLE0000000670" expecting early return
Then the container state for "01TESTLIFECYCLE0000000670" should be "failed"
And the runner should not have received a docker stop call
# ── F15: host_workspace_path stored on activation ───────────
Scenario: Activation stores host_workspace_path for health probes
Given a mock devcontainer CLI runner
And the runner configured for successful activation
When I activate container "01TESTLIFECYCLE0000000800" at "/workspace/project"
Then the container state should be "running"
And the host_workspace_path for "01TESTLIFECYCLE0000000800" should be "/workspace/project"
# ── F10: rebuild passes --reset-container flag ──────────────
Scenario: Rebuild passes --reset-container to devcontainer up
Given a mock devcontainer CLI runner
And the runner configured for successful activation
And a stopped container "01TESTLIFECYCLE0000000810"
When I call rebuild_container for "01TESTLIFECYCLE0000000810" at "/workspace/project"
Then the container state for "01TESTLIFECYCLE0000000810" should be "running"
And the devcontainer up call should include "--reset-container"
Scenario: Normal activation does not pass --reset-container
Given a mock devcontainer CLI runner
And the runner configured for successful activation
When I activate container "01TESTLIFECYCLE0000000811" at "/workspace/project"
Then the container state should be "running"
And the devcontainer up call should not include "--reset-container"