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
199 lines
9.6 KiB
Gherkin
199 lines
9.6 KiB
Gherkin
Feature: Devcontainer Lifecycle State Model
|
|
As a CleverAgents developer
|
|
I want the container lifecycle state model to enforce valid transitions
|
|
So that containers follow a predictable state machine
|
|
|
|
# ── Lifecycle state model ──────────────────────────────────
|
|
|
|
Scenario: ContainerLifecycleState has all required values
|
|
When I inspect ContainerLifecycleState enum values
|
|
Then the lifecycle enum should contain "detected"
|
|
And the lifecycle enum should contain "building"
|
|
And the lifecycle enum should contain "running"
|
|
And the lifecycle enum should contain "stopping"
|
|
And the lifecycle enum should contain "stopped"
|
|
And the lifecycle enum should contain "failed"
|
|
|
|
Scenario: Valid transitions are accepted
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000001"
|
|
When I transition from "detected" to "building"
|
|
Then the transition should succeed
|
|
And the tracker state should be "building"
|
|
|
|
Scenario: Active transition after starting
|
|
Given a lifecycle tracker in "building" state for resource "01TESTLIFECYCLE0000000002"
|
|
When I transition from "building" to "running"
|
|
Then the transition should succeed
|
|
And the tracker state should be "running"
|
|
|
|
Scenario: Invalid transition is rejected
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000003"
|
|
When I attempt to transition from "detected" to "running"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Stopping to error transition is valid
|
|
Given a lifecycle tracker in "stopping" state for resource "01TESTLIFECYCLE0000000004"
|
|
When I transition from "stopping" to "failed"
|
|
Then the transition should succeed
|
|
And the tracker state should be "failed"
|
|
|
|
Scenario: Error to starting transition is valid for retry
|
|
Given a lifecycle tracker in "failed" state for resource "01TESTLIFECYCLE0000000005"
|
|
When I transition from "failed" to "building"
|
|
Then the transition should succeed
|
|
And the tracker state should be "building"
|
|
|
|
Scenario: Stopped to starting transition is valid for rebuild
|
|
Given a lifecycle tracker in "stopped" state for resource "01TESTLIFECYCLE0000000006"
|
|
When I transition from "stopped" to "building"
|
|
Then the transition should succeed
|
|
|
|
Scenario: Transition history is recorded
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000007"
|
|
When I transition from "detected" to "building"
|
|
Then the tracker should have 1 transition in history
|
|
|
|
# ── Lifecycle registry ─────────────────────────────────────
|
|
|
|
Scenario: Lifecycle tracker persists state across calls
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000060"
|
|
When I transition from "detected" to "building"
|
|
And I retrieve the tracker for "01TESTLIFECYCLE0000000060"
|
|
Then the retrieved tracker state should be "building"
|
|
|
|
Scenario: List active containers returns only active ones
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful activation
|
|
And an active container "01TESTLIFECYCLE0000000070" with container ID "ctr-x"
|
|
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000071"
|
|
When I list active containers
|
|
Then the active list should contain "01TESTLIFECYCLE0000000070"
|
|
And the active list should not contain "01TESTLIFECYCLE0000000071"
|
|
|
|
# ── JSON output parsing ────────────────────────────────────
|
|
|
|
Scenario: Parse valid devcontainer up JSON output
|
|
When I parse devcontainer up output with containerId "abcdef123456" and workspace "/ws"
|
|
Then the parsed container ID should be "abcdef123456"
|
|
And the parsed workspace path should be "/ws"
|
|
|
|
Scenario: Parse invalid devcontainer up JSON output gracefully
|
|
When I parse devcontainer up output with invalid JSON
|
|
Then the parsed container ID should be None
|
|
And the parsed workspace path should be None
|
|
|
|
# ── Argument validation ────────────────────────────────────
|
|
|
|
Scenario: validate_transition rejects wrong types
|
|
When I call validate_transition with non-enum arguments
|
|
Then it should raise TypeError
|
|
|
|
Scenario: validate_transition rejects wrong to_state type
|
|
When I call validate_transition with non-enum to_state
|
|
Then it should raise TypeError
|
|
|
|
Scenario: transition_state rejects wrong tracker type
|
|
When I call transition_state with non-tracker argument
|
|
Then it should raise TypeError
|
|
|
|
Scenario: transition_state rejects wrong to_state type
|
|
When I call transition_state with non-enum to_state argument
|
|
Then it should raise TypeError
|
|
|
|
# ── Registry edge cases ────────────────────────────────────
|
|
|
|
Scenario: get_lifecycle_tracker rejects empty resource_id
|
|
When I attempt to get tracker with empty resource_id
|
|
Then the get tracker should raise ValueError
|
|
|
|
Scenario: set_lifecycle_tracker rejects wrong type
|
|
When I attempt to set tracker with wrong type
|
|
Then the set tracker should raise TypeError
|
|
|
|
# ── R13: Additional invalid transition coverage ────────────
|
|
|
|
Scenario: Invalid transition running to building is rejected
|
|
Given a lifecycle tracker in "running" state for resource "01TESTLIFECYCLE0000000240"
|
|
When I attempt to transition from "running" to "building"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition stopped to running is rejected
|
|
Given a lifecycle tracker in "stopped" state for resource "01TESTLIFECYCLE0000000241"
|
|
When I attempt to transition from "stopped" to "running"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition building to stopped is rejected
|
|
Given a lifecycle tracker in "building" state for resource "01TESTLIFECYCLE0000000242"
|
|
When I attempt to transition from "building" to "stopped"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition failed to running is rejected
|
|
Given a lifecycle tracker in "failed" state for resource "01TESTLIFECYCLE0000000243"
|
|
When I attempt to transition from "failed" to "running"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition detected to stopping is rejected
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000244"
|
|
When I attempt to transition from "detected" to "stopping"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition building to detected is rejected
|
|
Given a lifecycle tracker in "building" state for resource "01TESTLIFECYCLE0000000245"
|
|
When I attempt to transition from "building" to "detected"
|
|
Then the transition should raise ValueError
|
|
|
|
# ── R4: Multi-line JSON output parsing ─────────────────────
|
|
|
|
Scenario: Parse devcontainer up output with log lines before JSON
|
|
When I parse devcontainer up output with log lines before JSON
|
|
Then the parsed container ID should be "aabbccddee0099887766"
|
|
And the parsed workspace path should be "/workspaces/multi"
|
|
|
|
# ── T1: Transition history cap at 100 ──────────────────────
|
|
|
|
Scenario: Transition history is capped at 100 entries
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000300"
|
|
When I perform 105 transitions cycling through valid states
|
|
Then the tracker should have at most 100 transitions
|
|
|
|
# ── S1: Container ID format validation ─────────────────────
|
|
|
|
Scenario: Invalid container ID format is rejected during parsing
|
|
When I parse devcontainer up output with invalid container ID "not-a-hex-id!"
|
|
Then the parsed container ID should be empty
|
|
|
|
# ── F11: Invalid workspace path rejected during parsing ────
|
|
|
|
Scenario: Parse devcontainer up output with relative workspace path
|
|
When I parse devcontainer up output with relative workspace "relative/ws"
|
|
Then the parsed container ID should be "aabbccddee0011223344"
|
|
And the parsed workspace path should be None
|
|
|
|
# ── R7-F8: Terminal tracker eviction ────────────────────────
|
|
|
|
Scenario: Terminal tracker eviction removes oldest stopped trackers
|
|
Given 210 stopped container trackers in the registry
|
|
When I run terminal tracker eviction
|
|
Then the registry should have at most 200 terminal trackers
|
|
|
|
# ── TEST-3: Coverage gap scenarios ──────────────────────────
|
|
|
|
Scenario: evict_terminal_trackers returns 0 when below threshold
|
|
Given 50 stopped container trackers in the registry
|
|
When I run terminal tracker eviction
|
|
Then the eviction count should be 0
|
|
|
|
Scenario: get_lifecycle_tracker auto-creates tracker for new resource
|
|
When I get tracker for new resource "01TESTLIFECYCLE0000000730"
|
|
Then the auto-created tracker state should be "detected"
|
|
And the auto-created tracker resource_id should be "01TESTLIFECYCLE0000000730"
|
|
|
|
Scenario: clear_lifecycle_registry stops health check threads
|
|
Given a mock devcontainer CLI runner
|
|
And the runner configured for successful health check
|
|
And an active container "01TESTLIFECYCLE0000000740" with container ID "ctr-clr"
|
|
And a running health check for "01TESTLIFECYCLE0000000740"
|
|
When I clear the lifecycle registry
|
|
Then the registry should be empty
|
|
And the health check for "01TESTLIFECYCLE0000000740" should be unregistered
|