be45020a5c
- Adds a --clone-into option to the container-instance command to clone repository contents into a specified path during container setup. - Fixes the devcontainer-instance sandbox strategy to ensure proper isolation, correct mount permissions, and deterministic behavior across environments. - Updates related validation and error handling to reflect the new option and sandbox changes. ISSUES CLOSED: #7555
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 "discovered"
|
|
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 "discovered" 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 "discovered" 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 "discovered" 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 "discovered" 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 discovered to stopping is rejected
|
|
Given a lifecycle tracker for resource "01TESTLIFECYCLE0000000244"
|
|
When I attempt to transition from "discovered" to "stopping"
|
|
Then the transition should raise ValueError
|
|
|
|
Scenario: Invalid transition building to discovered is rejected
|
|
Given a lifecycle tracker in "building" state for resource "01TESTLIFECYCLE0000000245"
|
|
When I attempt to transition from "building" to "discovered"
|
|
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 "discovered"
|
|
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
|