Files
cleveragents-core/features/devcontainer_cleanup.feature
HAL9000 619e8eff36 feat(resource): add --clone-into to container-instance and fix devcontainer-instance sandbox strategy
- 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
2026-06-02 20:37:35 -04:00

239 lines
14 KiB
Gherkin

Feature: Devcontainer Session Cleanup and CLI Commands
As a CleverAgents developer
I want session-scoped container cleanup and CLI stop/rebuild commands
So that containers are cleaned up when sessions end and can be managed via CLI
# Session cleanup
Scenario: Active containers stopped on session cleanup
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000040" with container ID "ctr-a"
And an active container "01TESTLIFECYCLE0000000041" with container ID "ctr-b"
When I run session cleanup for session "session-001"
Then the container state for "01TESTLIFECYCLE0000000040" should be "stopped"
And the container state for "01TESTLIFECYCLE0000000041" should be "stopped"
# ── Cleanup service integration ────────────────────────────
Scenario: CleanupService stop_active_devcontainers is callable and returns list
When I call CleanupService stop_active_devcontainers with no active containers
Then the cleanup result should be an empty list
And CleanupService should have a stop_active_devcontainers method
Scenario: CleanupService stop_active_devcontainers calls handler cleanup
When I call CleanupService stop_active_devcontainers with no active containers
Then the cleanup result should be an empty list
# ── stop_all_active_containers error path ──────────────────
Scenario: Session cleanup handles stop failure gracefully
Given a mock devcontainer CLI runner
And the runner configured to raise exception on stop
And an active container "01TESTLIFECYCLE0000000130" with container ID "ctr-fail"
When I run session cleanup for session "session-err"
Then the cleanup should return 0 stopped containers
# ── CLI stop/rebuild commands (F6) ─────────────────────────
Scenario: CLI stop succeeds for active devcontainer-instance
Given a mock resource service with devcontainer "local/test-dc" id "01TESTLIFECYCLE0000000200" at "/workspace/project"
And an active container "01TESTLIFECYCLE0000000200" with container ID "ctr-cli-stop"
When I invoke CLI resource stop "local/test-dc"
Then the CLI exit code should be 0
And the CLI output should contain "Stopped"
Scenario: CLI stop rejects non-devcontainer resource type
Given a mock resource service with git-checkout "local/my-repo" id "01TESTLIFECYCLE0000000201"
When I invoke CLI resource stop "local/my-repo"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "not a stoppable container type"
Scenario: CLI rebuild succeeds for stopped devcontainer-instance
Given a mock resource service with devcontainer "local/test-dc-rb" id "01TESTLIFECYCLE0000000210" at "/workspace/project"
And a stopped container "01TESTLIFECYCLE0000000210"
When I invoke CLI resource rebuild "local/test-dc-rb"
Then the CLI exit code should be 0
And the CLI output should contain "Rebuilt"
Scenario: CLI rebuild rejects resource with no location
Given a mock resource service with devcontainer "local/dc-no-loc" id "01TESTLIFECYCLE0000000211" with no location
And a stopped container "01TESTLIFECYCLE0000000211"
When I invoke CLI resource rebuild "local/dc-no-loc"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "no location"
Scenario: CLI rebuild rejects non-devcontainer resource type
Given a mock resource service with git-checkout "local/git-rb" id "01TESTLIFECYCLE0000000212"
When I invoke CLI resource rebuild "local/git-rb"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "rebuild requires devcontainer"
# ── R7: CLI test mock assertions ───────────────────────────
Scenario: CLI stop calls stop_container with correct resource_id
Given a mock resource service with devcontainer "local/test-dc-r7" id "01TESTLIFECYCLE0000000220" at "/workspace/project"
And an active container "01TESTLIFECYCLE0000000220" with container ID "ctr-r7"
When I invoke CLI resource stop "local/test-dc-r7"
Then the CLI exit code should be 0
And the CLI stop mock should have been called with "01TESTLIFECYCLE0000000220"
Scenario: CLI rebuild calls rebuild_container with correct args
Given a mock resource service with devcontainer "local/test-dc-r7rb" id "01TESTLIFECYCLE0000000221" at "/workspace/project"
And a stopped container "01TESTLIFECYCLE0000000221"
When I invoke CLI resource rebuild "local/test-dc-r7rb"
Then the CLI exit code should be 0
And the CLI rebuild mock should have been called with "01TESTLIFECYCLE0000000221" and "/workspace/project"
# ── R8: DevcontainerHandler coverage ───────────────────────
Scenario: DevcontainerHandler has expected class attributes and is instantiable
Then DevcontainerHandler should have _default_strategy "snapshot"
And DevcontainerHandler should have _type_label "devcontainer"
And DevcontainerHandler should be instantiable
Scenario: DevcontainerHandler extends BaseResourceHandler and inherits resolve interface
Then DevcontainerHandler should be a subclass of BaseResourceHandler
And DevcontainerHandler instance should have a resolve method
# ── R12: CLI state precondition validation ─────────────────
Scenario: CLI stop rejects container not in running state
Given a mock resource service with devcontainer "local/dc-det" id "01TESTLIFECYCLE0000000230" at "/workspace/project"
And a lifecycle tracker for resource "01TESTLIFECYCLE0000000230"
When I invoke CLI resource stop "local/dc-det"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Cannot stop"
Scenario: CLI rebuild rejects container in running state
Given a mock resource service with devcontainer "local/dc-run" id "01TESTLIFECYCLE0000000231" at "/workspace/project"
And an active container "01TESTLIFECYCLE0000000231" with container ID "ctr-rb-state"
When I invoke CLI resource rebuild "local/dc-run"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Cannot rebuild"
# ── R14: stop_all return list assertion ────────────────────
Scenario: Session cleanup returns list of stopped resource IDs
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000250" with container ID "ctr-r14a"
And an active container "01TESTLIFECYCLE0000000251" with container ID "ctr-r14b"
When I run session cleanup for session "session-r14"
Then the cleanup stopped list should contain "01TESTLIFECYCLE0000000250"
And the cleanup stopped list should contain "01TESTLIFECYCLE0000000251"
# ── A2: Stop and rebuild accept --yes flag ─────────────────
Scenario: CLI stop with --yes skips confirmation and calls stop_container
Given a CLI-mockable running devcontainer resource "test-dc-yes-stop"
When I invoke CLI resource stop "test-dc-yes-stop"
Then the devcontainer CLI exit code should be 0
And the CLI stop mock should have been called once
Scenario: CLI rebuild with --yes skips confirmation and calls rebuild_container
Given a CLI-mockable stopped devcontainer resource "test-dc-yes-rebuild"
When I invoke CLI resource rebuild "test-dc-yes-rebuild"
Then the devcontainer CLI exit code should be 0
And the CLI rebuild mock should have been called once
# ── Issue #2588: container-instance IS stoppable via CLI ────
Scenario: CLI stop accepts container-instance type (issue #2588 fix)
Given a mock resource service with container-instance "local/ctr-stop" id "01TESTLIFECYCLE0000000370" at "/workspace/project"
And an active container "01TESTLIFECYCLE0000000370" with container ID "ctr-ci-stop"
When I invoke CLI resource stop "local/ctr-stop"
Then the CLI exit code should be 0
And the CLI output should contain "Stopped"
And the CLI stop mock should have been called with "01TESTLIFECYCLE0000000370"
# ── F6-r6: CLI handler-level error paths ────────────────────
Scenario: CLI stop handles NotFoundError from show_resource
Given a mock resource service that raises NotFoundError for "local/missing"
When I invoke CLI resource stop "local/missing"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Resource not found"
Scenario: CLI rebuild handles NotFoundError from show_resource
Given a mock resource service that raises NotFoundError for "local/missing-rb"
When I invoke CLI resource rebuild "local/missing-rb"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Resource not found"
Scenario: CLI stop handles RuntimeError from stop_container
Given a mock resource service with devcontainer "local/dc-rterr" id "01TESTLIFECYCLE0000000500" at "/workspace/project"
And an active container "01TESTLIFECYCLE0000000500" with container ID "ctr-rterr"
And CLI stop_container mock that raises RuntimeError
When I invoke CLI resource stop with error mock "local/dc-rterr"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Stop failed"
Scenario: CLI rebuild handles RuntimeError from rebuild_container
Given a mock resource service with devcontainer "local/dc-rberr" id "01TESTLIFECYCLE0000000501" at "/workspace/project"
And a stopped container "01TESTLIFECYCLE0000000501"
And CLI rebuild_container mock that raises RuntimeError
When I invoke CLI resource rebuild with error mock "local/dc-rberr"
Then the devcontainer CLI exit code should be non-zero
And the CLI output should contain "Rebuild failed"
# ── R7-F1: Session-scoped container cleanup ────────────────
Scenario: Session cleanup only stops containers belonging to that session
Given a mock devcontainer CLI runner
And a session-scoped active container "01TESTLIFECYCLE0000000600" with ID "ctr-s1" session "sess-A"
And a session-scoped active container "01TESTLIFECYCLE0000000601" with ID "ctr-s2" session "sess-B"
When I run session cleanup for session "sess-A"
Then the container state for "01TESTLIFECYCLE0000000600" should be "stopped"
And the container state for "01TESTLIFECYCLE0000000601" should be "running"
Scenario: Session cleanup with no session_id stops all containers
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000610" with container ID "ctr-all1"
And an active container "01TESTLIFECYCLE0000000611" with container ID "ctr-all2"
When I run session cleanup with no session filter
Then the container state for "01TESTLIFECYCLE0000000610" should be "stopped"
And the container state for "01TESTLIFECYCLE0000000611" should be "stopped"
# ── R8-F1: Eviction wired into production cleanup ────────────
Scenario: Session cleanup triggers terminal tracker eviction
Given a mock devcontainer CLI runner
And 210 stopped container trackers in the registry
And an active container "01TESTLIFECYCLE0000000650" with container ID "ctr-evict"
When I run session cleanup for session "session-evict"
Then the container state for "01TESTLIFECYCLE0000000650" should be "stopped"
And the registry should have at most 200 terminal trackers
# ── TEST-3: Coverage gap scenarios ──────────────────────────
Scenario: list_active_containers_for_session returns only matching session
Given a mock devcontainer CLI runner
And a session-scoped active container "01TESTLIFECYCLE0000000700" with ID "ctr-ts3a" session "sess-X"
And a session-scoped active container "01TESTLIFECYCLE0000000701" with ID "ctr-ts3b" session "sess-Y"
When I list active containers for session "sess-X"
Then the session container list should contain "01TESTLIFECYCLE0000000700"
And the session container list should not contain "01TESTLIFECYCLE0000000701"
Scenario: list_active_containers_for_session with empty session returns all
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000710" with container ID "ctr-ts3c"
And an active container "01TESTLIFECYCLE0000000711" with container ID "ctr-ts3d"
When I list active containers for an empty session
Then the session container list should contain "01TESTLIFECYCLE0000000710"
And the session container list should contain "01TESTLIFECYCLE0000000711"
Scenario: list_active_containers_for_session includes unscoped containers
Given a mock devcontainer CLI runner
And an active container "01TESTLIFECYCLE0000000720" with container ID "ctr-unscoped"
And a session-scoped active container "01TESTLIFECYCLE0000000721" with ID "ctr-scoped" session "sess-Z"
When I list active containers for session "sess-Z"
Then the session container list should contain "01TESTLIFECYCLE0000000720"
And the session container list should contain "01TESTLIFECYCLE0000000721"
# ── R7-F4: Session close cleanup without session service ────
Scenario: Session close cleans up containers even without session service
Given a facade with no session service
And a session-scoped active container "01TESTLIFECYCLE0000000630" with no docker ID session "sess-f4"
When I close session "sess-f4" via the facade
Then the container state for "01TESTLIFECYCLE0000000630" should be "stopped"