Files
cleveragents-core/features/resource_handler_service_coverage.feature
T
freemo 55aee7cf22
CI / lint (pull_request) Successful in 18s
CI / quality (pull_request) Successful in 21s
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 14s
CI / security (pull_request) Successful in 49s
CI / typecheck (pull_request) Successful in 56s
CI / integration_tests (pull_request) Successful in 2m35s
CI / unit_tests (pull_request) Successful in 14m30s
CI / docker (pull_request) Successful in 55s
CI / benchmark-regression (pull_request) Successful in 21m11s
CI / coverage (pull_request) Successful in 34m22s
CI / lint (push) Successful in 12s
CI / build (push) Successful in 16s
CI / quality (push) Successful in 17s
CI / security (push) Successful in 29s
CI / typecheck (push) Successful in 1m0s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 4m54s
CI / benchmark-publish (push) Successful in 11m48s
CI / unit_tests (push) Successful in 16m30s
CI / docker (push) Successful in 28s
CI / coverage (push) Successful in 25m45s
fix(test): commit after each add_skill to prevent session GC rollback, and improved coverage.
The step_register_skills_table step called add_skill in a loop but only
committed once at the end. Because SkillRepository.create() obtains a
new session per call and only flushes (never commits), the intermediate
sessions could be garbage-collected before the final commit, rolling
back their transactions on the shared SQLite :memory: connection. Moving
_commit_pending inside the loop ensures each skill is durably committed
before the next session is created.

ISSUES CLOSED: #418
2026-02-24 12:19:04 -05:00

152 lines
8.6 KiB
Gherkin

Feature: ResourceHandlerService full coverage
As a plan execution engine
I want the ResourceHandlerService to resolve bindings into BoundResources
So that tools receive sandbox-backed resource paths during execution
Background:
Given a mock sandbox manager for rhs
And a mock resource lookup for rhs
And a mock type lookup for rhs
And a ResourceHandlerService under test
# --- resolve_binding: deferred / missing resource_id ---
Scenario: Resolving a deferred binding raises ValueError
Given an rhs binding that is deferred with slot name "repo"
When I resolve the rhs single binding
Then an rhs ValueError is raised with message containing "Cannot resolve deferred binding for slot 'repo'"
Scenario: Resolving a binding with no resource_id raises ValueError
Given an rhs binding with no resource_id and slot name "data"
When I resolve the rhs single binding
Then an rhs ValueError is raised with message containing "Cannot resolve deferred binding for slot 'data'"
# --- resolve_binding: successful resolution ---
Scenario: Resolving a valid binding returns a BoundResource
Given an rhs non-deferred binding with slot "repo" and resource_id "RES001"
And rhs resource "RES001" typed "git-checkout" located at "/tmp/repo" with strategy "none"
And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
And the rhs sandbox manager returns a sandbox with path "/sandbox/abc"
When I resolve the rhs single binding with plan_id "plan-1" and access "read_write"
Then the rhs result is a BoundResource with slot "repo" and sandbox_path "/sandbox/abc"
And the rhs BoundResource has resource_id "RES001" and access "read_write"
# --- _resolve_handler_for_type: type_spec has a handler ---
Scenario: Handler is resolved from type_spec handler reference
Given an rhs non-deferred binding with slot "code" and resource_id "RES002"
And rhs resource "RES002" typed "custom/py" located at "/src" with strategy "none"
And an rhs type spec "custom/py" with handler "some.module:Handler" and sandbox strategy "copy_on_write"
And the rhs resolve_handler function returns a mock handler
And the rhs mock handler resolves to a BoundResource with sandbox_path "/sandbox/custom"
When I resolve the rhs single binding with plan_id "plan-2" and access "read_only"
Then the rhs result is a BoundResource with slot "code" and sandbox_path "/sandbox/custom"
# --- _resolve_handler_for_type: handler resolution fails, falls back ---
Scenario: Handler resolution failure falls back to DefaultHandler
Given an rhs non-deferred binding with slot "files" and resource_id "RES003"
And rhs resource "RES003" typed "custom/broken" located at "/data" with strategy "copy_on_write"
And an rhs type spec "custom/broken" with handler "bad.module:Missing" and sandbox strategy "copy_on_write"
And the rhs resolve_handler function raises HandlerResolutionError
And the rhs sandbox manager returns a sandbox with path "/sandbox/fallback"
When I resolve the rhs single binding with plan_id "plan-3" and access "read_only"
Then the rhs result is a BoundResource with slot "files" and sandbox_path "/sandbox/fallback"
# --- _resolve_handler_for_type: no handler on type_spec ---
Scenario: No handler on type_spec uses DefaultHandler directly
Given an rhs non-deferred binding with slot "dir" and resource_id "RES004"
And rhs resource "RES004" typed "fs-directory" located at "/home/user" with strategy "copy_on_write"
And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
And the rhs sandbox manager returns a sandbox with path "/sandbox/dir"
When I resolve the rhs single binding with plan_id "plan-4" and access "read_only"
Then the rhs result is a BoundResource with slot "dir" and sandbox_path "/sandbox/dir"
# --- resolve_bindings: mixed deferred and non-deferred ---
Scenario: resolve_bindings skips deferred bindings and resolves the rest
Given an rhs binding list with:
| slot_name | resource_id | deferred |
| repo | RES010 | false |
| param | | true |
| config | RES011 | false |
And rhs resource "RES010" typed "git-checkout" located at "/repo" with strategy "none"
And rhs resource "RES011" typed "fs-directory" located at "/config" with strategy "none"
And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
And the rhs sandbox manager returns a sandbox with path "/sandbox/multi"
When I resolve all rhs bindings with plan_id "plan-5" and access "read_only"
Then the rhs result dict has keys "repo" and "config"
And the rhs result dict does not contain key "param"
# --- resolve_bindings: failure propagation ---
Scenario: resolve_bindings raises when a non-deferred binding fails
Given an rhs binding list with:
| slot_name | resource_id | deferred |
| broken | RES_MISSING | false |
And the rhs resource lookup raises NotFoundError for "RES_MISSING"
When I resolve all rhs bindings expecting an error
Then an rhs NotFoundError is raised
# --- resolve_bindings: all deferred returns empty dict ---
Scenario: resolve_bindings with all deferred bindings returns empty dict
Given an rhs binding list with:
| slot_name | resource_id | deferred |
| a | | true |
| b | | true |
When I resolve all rhs bindings with plan_id "plan-6" and access "read_only"
Then the rhs result dict is empty
# --- resolve_resource: direct resolution ---
Scenario: resolve_resource resolves a resource directly without a binding
Given rhs resource "RES020" typed "git-checkout" located at "/direct/repo" with strategy "none"
And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
And the rhs sandbox manager returns a sandbox with path "/sandbox/direct"
When I resolve the rhs resource directly with plan_id "plan-7" slot "src" and access "read_write"
Then the rhs result is a BoundResource with slot "src" and sandbox_path "/sandbox/direct"
And the rhs BoundResource has resource_id "RES020" and access "read_write"
# --- _DefaultHandler: resource sandbox_strategy overrides type ---
Scenario: DefaultHandler uses resource sandbox_strategy when present
Given an rhs non-deferred binding with slot "db" and resource_id "RES030"
And rhs resource "RES030" typed "custom/db" located at "/data/db" with strategy "snapshot"
And an rhs type spec "custom/db" with no handler and sandbox strategy "copy_on_write"
And the rhs sandbox manager returns a sandbox with path "/sandbox/snap"
When I resolve the rhs single binding with plan_id "plan-8" and access "read_only"
Then the rhs sandbox manager was called with strategy "snapshot"
# --- _DefaultHandler: falls back to type_spec sandbox_strategy ---
Scenario: DefaultHandler falls back to type_spec sandbox_strategy when resource has none
Given an rhs non-deferred binding with slot "fs" and resource_id "RES031"
And rhs resource "RES031" typed "fs-directory" located at "/mnt/share" with strategy "none"
And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
And the rhs sandbox manager returns a sandbox with path "/sandbox/cow"
When I resolve the rhs single binding with plan_id "plan-9" and access "read_only"
Then the rhs sandbox manager was called with strategy "copy_on_write"
# --- _DefaultHandler: no location error ---
Scenario: DefaultHandler raises ValueError when resource has no location
Given an rhs non-deferred binding with slot "empty" and resource_id "RES040"
And rhs resource "RES040" typed "fs-directory" with no location
And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
When I resolve the rhs single binding
Then an rhs ValueError is raised with message containing "has no location"
# --- _DefaultHandler: sandbox context is None ---
Scenario: DefaultHandler raises RuntimeError when sandbox has no context
Given an rhs non-deferred binding with slot "ctx" and resource_id "RES050"
And rhs resource "RES050" typed "fs-directory" located at "/tmp/ctx" with strategy "none"
And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
And the rhs sandbox manager returns a sandbox with no context
When I resolve the rhs single binding
Then an rhs RuntimeError is raised with message containing "has no context"