cf67ba0a86
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 18s
CI / security (pull_request) Successful in 35s
CI / typecheck (pull_request) Successful in 37s
CI / unit_tests (pull_request) Successful in 2m27s
CI / docker (pull_request) Successful in 49s
CI / integration_tests (pull_request) Successful in 3m46s
CI / coverage (pull_request) Successful in 4m56s
CI / lint (push) Successful in 12s
CI / build (push) Successful in 14s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 32s
CI / typecheck (push) Successful in 36s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 4m7s
CI / integration_tests (push) Successful in 4m41s
CI / docker (push) Successful in 44s
CI / coverage (push) Successful in 4m56s
CI / benchmark-publish (push) Successful in 17m17s
CI / benchmark-regression (pull_request) Successful in 31m25s
Implemented lazy container activation for devcontainer-instance resources with ContainerLifecycleState enum tracking six states (inactive, starting, active, stopping, stopped, error) with validated transitions. Extended DevcontainerHandler with devcontainer up CLI integration and JSON output parsing for container start. Added periodic health checking via devcontainer exec ping with configurable interval. Added agents resource stop and agents resource rebuild CLI commands for manual lifecycle control. Wired session close and plan completion hooks to automatic container cleanup. Includes lifecycle state persistence in resource registry with timestamped transitions. Added Behave BDD tests, Robot integration tests, and ASV activation latency benchmarks. - Added remoteWorkspaceFolder absolute-path validation - Aligned spec: handler name, rebuild types, --yes flag on stop/rebuild - Added registry re-read in stop_container success path for consistency - Added session_id field to ContainerLifecycleTracker for scoped cleanup - Scoped stop_all_active_containers to session_id when provided - Wired _cleanup_devcontainers into fail_apply and fail_execute - Wired start_health_check into activate_container success path - Restructured facade session close to always run container cleanup even without session service (F4) - Re-read tracker from registry in activate_container success path - Added evict_terminal_trackers to cap registry growth - Updated devcontainer_resources.md: health check auto-start, scoped cleanup hooks, known limitations for eviction and sandbox_strategy - Wired evict_terminal_trackers into stop_all_active_containers so terminal-state trackers are actually evicted in production - Made stop_container idempotent: returns early when container is already in a terminal state instead of raising ValueError - Fixed benchmark health check thread leak in TimeActivationLatency by clearing registry after each timing loop - Added rebuild pass-through (--reset-container flag to devcontainer up) - Added host_workspace_path field on ContainerLifecycleTracker so health probes use the host-side path for devcontainer exec - Wired lazy activation into DevcontainerHandler.resolve() for devcontainer-instance resources in non-running states - Changed _default_strategy from SNAPSHOT to NONE (container itself provides isolation; SandboxFactory raises NotImplementedError for snapshot) - Restricted _STOPPABLE_TYPES to devcontainer-instance only (container-instance is not directly stoppable via CLI) ISSUES CLOSED: #514
127 lines
6.9 KiB
Gherkin
127 lines
6.9 KiB
Gherkin
Feature: Devcontainer Health Checking
|
|
As a CleverAgents developer
|
|
I want running devcontainers to be health-checked periodically
|
|
So that unhealthy containers are detected and transitioned to failed state
|
|
|
|
# ── Health check ───────────────────────────────────────────
|
|
|
|
Scenario: Health check failure transitions to error
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for failed health check
|
|
And an active container "01TESTLIFECYCLE0000000050" with container ID "ctr-hc"
|
|
When I run a single health check probe for "01TESTLIFECYCLE0000000050"
|
|
Then the container state for "01TESTLIFECYCLE0000000050" should be "failed"
|
|
|
|
# ── start_health_check and health_check_loop coverage ──────
|
|
|
|
Scenario: Health check loop success path runs and returns
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful health check
|
|
And an active container "01TESTLIFECYCLE0000000100" with container ID "ctr-hcbg"
|
|
When I run one iteration of the health check loop for "01TESTLIFECYCLE0000000100"
|
|
Then the health check should have probed "01TESTLIFECYCLE0000000100"
|
|
And the container state for "01TESTLIFECYCLE0000000100" should be "running"
|
|
|
|
Scenario: Health check loop transitions to error on probe failure
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for failed health check
|
|
And an active container "01TESTLIFECYCLE0000000101" with container ID "ctr-hcf"
|
|
When I run one iteration of the health check loop for "01TESTLIFECYCLE0000000101"
|
|
Then the container state for "01TESTLIFECYCLE0000000101" should be "failed"
|
|
|
|
Scenario: Health check loop transitions to error on exception
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured to raise exception on exec
|
|
And an active container "01TESTLIFECYCLE0000000102" with container ID "ctr-hce"
|
|
When I run one iteration of the health check loop for "01TESTLIFECYCLE0000000102"
|
|
Then the container state for "01TESTLIFECYCLE0000000102" should be "failed"
|
|
|
|
Scenario: start_health_check registers thread and stop event
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful health check
|
|
And an active container "01TESTLIFECYCLE0000000103" with container ID "ctr-reg"
|
|
When I call start_health_check for "01TESTLIFECYCLE0000000103"
|
|
Then a health check thread should be registered for "01TESTLIFECYCLE0000000103"
|
|
|
|
Scenario: Stopping active container stops running health check
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful health check
|
|
And an active container "01TESTLIFECYCLE0000000104" with container ID "ctr-hcstop"
|
|
And a registered health check for "01TESTLIFECYCLE0000000104"
|
|
When I stop container "01TESTLIFECYCLE0000000104"
|
|
Then the container state for "01TESTLIFECYCLE0000000104" should be "stopped"
|
|
And the health check for "01TESTLIFECYCLE0000000104" should be unregistered
|
|
|
|
Scenario: Health check exits when container is no longer active
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful health check
|
|
And a stopped container "01TESTLIFECYCLE0000000105"
|
|
When I run one iteration of the health check loop for "01TESTLIFECYCLE0000000105"
|
|
Then the container state for "01TESTLIFECYCLE0000000105" should be "stopped"
|
|
|
|
Scenario: start_health_check rejects empty resource_id
|
|
When I attempt to start health check with empty resource_id
|
|
Then the health check should raise ValueError
|
|
|
|
# ── T2: Concurrent activation rejects second caller ────────
|
|
|
|
Scenario: Concurrent activation of the same container is rejected
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful activation
|
|
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000310"
|
|
When I activate the container concurrently from two threads
|
|
Then exactly one activation should succeed
|
|
And exactly one activation should fail with ValueError
|
|
|
|
# ── T3: _single_probe uses /workspace fallback ─────────────
|
|
|
|
Scenario: Single probe falls back to /workspace when workspace_path is None
|
|
Given a mock devcontainer CLI runner
|
|
And an active container "01TESTLIFECYCLE0000000320" with container ID "ctr-t3"
|
|
When I run a single probe with no workspace_path set
|
|
Then the probe command should use "/workspace" as workspace folder
|
|
|
|
# ── T4: Health check thread join timeout ───────────────────
|
|
|
|
Scenario: Stopping health check joins thread with timeout
|
|
Given a mock devcontainer CLI runner
|
|
And an active container "01TESTLIFECYCLE0000000330" with container ID "ctr-t4"
|
|
And a running health check for "01TESTLIFECYCLE0000000330"
|
|
When I stop the health check for "01TESTLIFECYCLE0000000330"
|
|
Then the health check thread should have been joined
|
|
|
|
# ── F7: Concurrent stop_container ──────────────────────────
|
|
|
|
Scenario: Concurrent stop of the same container is handled safely
|
|
Given a mock devcontainer CLI runner
|
|
And an active container "01TESTLIFECYCLE0000000390" with container ID "ctr-cs"
|
|
When I stop the container concurrently from two threads
|
|
Then both stops should succeed
|
|
And the container state for "01TESTLIFECYCLE0000000390" should be "stopped"
|
|
And exactly 1 docker stop call should have been made
|
|
|
|
# ── R7-F3: Auto health check on activation ─────────────────
|
|
|
|
Scenario: Activation automatically starts health check
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful activation
|
|
When I activate container "01TESTLIFECYCLE0000000620" at "/workspace/project"
|
|
Then the container state should be "running"
|
|
And a health check thread should be registered for "01TESTLIFECYCLE0000000620"
|
|
|
|
# ── F16: resolve() triggers lazy activation ─────────────────
|
|
|
|
Scenario: DevcontainerHandler.resolve triggers lazy activation for detected resource
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful activation
|
|
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000820"
|
|
When I resolve a devcontainer-instance "01TESTLIFECYCLE0000000820" at "/workspace/project"
|
|
Then the container state for "01TESTLIFECYCLE0000000820" should be "running"
|
|
|
|
Scenario: DevcontainerHandler.resolve skips activation for running resource
|
|
Given a mock devcontainer CLI runner
|
|
And an active container "01TESTLIFECYCLE0000000821" with container ID "ctr-resolve"
|
|
When I resolve a devcontainer-instance "01TESTLIFECYCLE0000000821" at "/workspace/project"
|
|
Then the container state for "01TESTLIFECYCLE0000000821" should be "running"
|
|
And the runner should not have received a devcontainer up call
|