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
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
152 lines
8.6 KiB
Gherkin
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"
|