c9abb45adf
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 31s
CI / typecheck (pull_request) Successful in 55s
CI / integration_tests (pull_request) Successful in 3m28s
CI / unit_tests (pull_request) Successful in 10m38s
CI / docker (pull_request) Successful in 16s
CI / benchmark-regression (pull_request) Successful in 20m39s
CI / coverage (pull_request) Successful in 41m22s
CI / lint (push) Successful in 13s
CI / quality (push) Successful in 17s
CI / build (push) Successful in 22s
CI / typecheck (push) Successful in 29s
CI / security (push) Successful in 29s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 2m40s
CI / unit_tests (push) Successful in 11m4s
CI / docker (push) Successful in 1m5s
CI / benchmark-publish (push) Successful in 12m10s
CI / coverage (push) Successful in 1h7m46s
Added 246 new BDD scenarios across 9 feature files to improve unit test coverage for modules that were either entirely untested or had significant coverage gaps: - lock_service_coverage.feature (27 scenarios): validation branches, TTL boundaries, re-entrant acquisition, rollback on exceptions - plan_apply_service_coverage.feature (54 scenarios): operation labels, diff rendering (plain/rich/json), artifact building, validation gate, changeset resolution and cleanup - plan_executor_coverage.feature (51 scenarios): step parsing, execute actor integration, strategize/execute guards, stub retry/recovery, decision tree construction - skill_cli_coverage_r3.feature (22 scenarios): tools refresh, list/show JSON fallback, capability summary errors, remove confirmation - changeset_repository_coverage.feature (39 scenarios): entry/tool repos validation, database error wrapping, domain conversion, SQLite store CRUD operations - repositories_coverage.feature (20 scenarios): get_by_name/namespace errors, list_available filters, delete with ActionInUseError, plan update with invariants/processing_state/error_details - sandbox_copy_on_write_coverage.feature (12 scenarios): create OSError wrapping, get_path state transitions, commit edge cases, rollback errors, cleanup with missing paths - bridge_coverage.feature (8 scenarios): __del__ suppression, async task cancellation, execute_graph message type handling, stream config, state checkpointer - plan_cli_coverage.feature (13 scenarios): legacy apply/list/cd paths, use-action with estimation/invariant actors, lifecycle-apply guards, status errors, error recovery display All 246 scenarios (1105 steps) pass. Step definitions use unique prefixes to prevent ambiguous step conflicts with existing tests. ISSUES CLOSED: #467
233 lines
13 KiB
Gherkin
233 lines
13 KiB
Gherkin
@unit @repository @coverage
|
||
Feature: Repository coverage for ActionRepository and LifecyclePlanRepository
|
||
Exercise uncovered lines and branches in repositories.py to boost
|
||
line-rate and branch-rate for ActionRepository and LifecyclePlanRepository.
|
||
|
||
Background:
|
||
Given a repos-cov in-memory database with lifecycle schema
|
||
And a repos-cov action repository
|
||
And a repos-cov lifecycle plan repository
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.get_by_name – DatabaseError on OperationalError
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @error_handling
|
||
Scenario: ActionRepository.get_by_name raises DatabaseError on OperationalError
|
||
Given a repos-cov action repository with a session that raises OperationalError on query
|
||
When repos-cov get_by_name is called with "local/broken-action"
|
||
Then repos-cov a DatabaseError should be raised containing "Failed to get action by name"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.get_by_name – success path returns domain object
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action
|
||
Scenario: ActionRepository.get_by_name returns domain object for existing action
|
||
Given repos-cov an available action "local/findable" exists
|
||
When repos-cov get_by_name is called with "local/findable"
|
||
Then repos-cov the returned action should have name "local/findable"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.get_by_namespace – with state filter returning results
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action
|
||
Scenario: ActionRepository.get_by_namespace with state filter returns matching actions
|
||
Given repos-cov an action "local/active-one" exists with state "available"
|
||
And repos-cov an action "local/archived-one" exists with state "archived"
|
||
When repos-cov get_by_namespace is called with namespace "local" and state "available"
|
||
Then repos-cov exactly 1 action should be in the result list
|
||
And repos-cov the result list should contain action named "local/active-one"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.get_by_namespace – DatabaseError on OperationalError
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @error_handling
|
||
Scenario: ActionRepository.get_by_namespace raises DatabaseError on OperationalError
|
||
Given a repos-cov action repository with a session that raises OperationalError on query
|
||
When repos-cov get_by_namespace is called with namespace "local" expecting error
|
||
Then repos-cov a DatabaseError should be raised containing "Failed to list actions in namespace"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.list_available – without namespace filter
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action
|
||
Scenario: ActionRepository.list_available returns all available actions without namespace
|
||
Given repos-cov an action "ns1/act-a" exists with state "available"
|
||
And repos-cov an action "ns2/act-b" exists with state "available"
|
||
And repos-cov an action "ns1/act-c" exists with state "archived"
|
||
When repos-cov list_available is called without a namespace filter
|
||
Then repos-cov exactly 2 actions should be in the result list
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.list_available – with namespace filter
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action
|
||
Scenario: ActionRepository.list_available returns available actions filtered by namespace
|
||
Given repos-cov an action "nsx/avail-1" exists with state "available"
|
||
And repos-cov an action "nsy/avail-2" exists with state "available"
|
||
When repos-cov list_available is called with namespace "nsx"
|
||
Then repos-cov exactly 1 action should be in the result list
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.list_available – DatabaseError on OperationalError
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @error_handling
|
||
Scenario: ActionRepository.list_available raises DatabaseError on OperationalError
|
||
Given a repos-cov action repository with a session that raises OperationalError on query
|
||
When repos-cov list_available is called and an error is expected
|
||
Then repos-cov a DatabaseError should be raised containing "Failed to list available actions"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.update – with arguments having min_value and max_value
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @update
|
||
Scenario: ActionRepository.update persists arguments with min_value and max_value
|
||
Given repos-cov an available action "local/minmax-action" exists
|
||
And repos-cov the action has arguments with min_value and max_value set
|
||
When repos-cov the action is updated via the repository
|
||
Then repos-cov the update should succeed
|
||
And repos-cov the retrieved action arguments should have min_value and max_value
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.delete – ActionInUseError when plans reference the action
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @delete @error_handling
|
||
Scenario: ActionRepository.delete raises ActionInUseError when plans reference the action
|
||
Given repos-cov an available action "local/in-use-action" exists
|
||
And a repos-cov lifecycle plan references action "local/in-use-action"
|
||
When repos-cov delete is called for action "local/in-use-action"
|
||
Then repos-cov an ActionInUseError should be raised for "local/in-use-action"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.delete – successful deletion when no plans reference it
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @delete
|
||
Scenario: ActionRepository.delete succeeds and returns True for unreferenced action
|
||
Given repos-cov an available action "local/deletable" exists
|
||
When repos-cov delete is called for action "local/deletable"
|
||
Then repos-cov the delete result should be True
|
||
And repos-cov get_by_id for "local/deletable" should return None
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# ActionRepository.delete – returns False for non-existent action
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@action @delete
|
||
Scenario: ActionRepository.delete returns False for non-existent action
|
||
When repos-cov delete is called for action "local/ghost"
|
||
Then repos-cov the delete result should be False
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# DuplicatePlanError instantiation
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @error_class
|
||
Scenario: DuplicatePlanError stores plan_id and message
|
||
When repos-cov a DuplicatePlanError is created for plan_id "01HGZ6FE0A00000000TESTPLAN"
|
||
Then repos-cov the error message should contain "01HGZ6FE0A00000000TESTPLAN"
|
||
And repos-cov the error plan_id attribute should be "01HGZ6FE0A00000000TESTPLAN"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.get_by_name – success path
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan
|
||
Scenario: LifecyclePlanRepository.get_by_name returns domain object for existing plan
|
||
Given repos-cov an available action "local/plan-target" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-target" with name "local/my-plan" has been persisted
|
||
When repos-cov plan get_by_name is called with "local/my-plan"
|
||
Then repos-cov the returned plan should not be None
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.get_by_name – returns None for missing
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan
|
||
Scenario: LifecyclePlanRepository.get_by_name returns None for non-existent plan
|
||
When repos-cov plan get_by_name is called with "local/no-such-plan"
|
||
Then repos-cov the returned plan should be None
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.get_by_name – DatabaseError on OperationalError
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @error_handling
|
||
Scenario: LifecyclePlanRepository.get_by_name raises DatabaseError on OperationalError
|
||
Given a repos-cov plan repository with a session that raises OperationalError on query
|
||
When repos-cov plan get_by_name is called with "local/error-plan" expecting error
|
||
Then repos-cov a DatabaseError should be raised containing "Failed to get plan by name"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.update – full update with project_links, arguments, invariants
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @update
|
||
Scenario: LifecyclePlanRepository.update persists project links, arguments, and invariants
|
||
Given repos-cov an available action "local/plan-upd-action" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-upd-action" with name "local/upd-plan" has been persisted
|
||
And repos-cov the plan has project_links, arguments, and invariants with text attribute
|
||
When repos-cov the plan is updated via the repository
|
||
Then repos-cov the plan update should succeed
|
||
And repos-cov the retrieved plan should have project links
|
||
And repos-cov the retrieved plan should have arguments
|
||
And repos-cov the retrieved plan should have invariants
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.update – invariants as plain strings (no .text attr)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @update
|
||
Scenario: LifecyclePlanRepository.update handles invariants as plain strings
|
||
Given repos-cov an available action "local/plan-str-inv" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-str-inv" with name "local/str-inv-plan" has been persisted
|
||
And repos-cov the plan has invariants as plain strings without text attribute
|
||
When repos-cov the plan is updated via the repository
|
||
Then repos-cov the plan update should succeed
|
||
And repos-cov the retrieved plan should have invariants
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.update – invariant source with .value attribute
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @update
|
||
Scenario: LifecyclePlanRepository.update handles invariant source with .value enum
|
||
Given repos-cov an available action "local/plan-enum-inv" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-enum-inv" with name "local/enum-inv-plan" has been persisted
|
||
And repos-cov the plan has invariants with InvariantSource enum values
|
||
When repos-cov the plan is updated via the repository
|
||
Then repos-cov the plan update should succeed
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.update – processing_state without .value (plain str)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @update
|
||
Scenario: LifecyclePlanRepository.update handles processing_state as plain string
|
||
Given repos-cov an available action "local/plan-str-state" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-str-state" with name "local/str-state-plan" has been persisted
|
||
And repos-cov the plan processing_state is set to a plain string "processing"
|
||
When repos-cov the plan is updated via the repository
|
||
Then repos-cov the plan update should succeed
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# LifecyclePlanRepository.update – error_details and changeset_id fields
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@plan @update
|
||
Scenario: LifecyclePlanRepository.update persists error_details and changeset_id
|
||
Given repos-cov an available action "local/plan-err-detail" exists
|
||
And a repos-cov lifecycle plan linked to "local/plan-err-detail" with name "local/err-detail-plan" has been persisted
|
||
And repos-cov the plan has error_message, error_details, and changeset_id set
|
||
When repos-cov the plan is updated via the repository
|
||
Then repos-cov the plan update should succeed
|
||
And repos-cov the retrieved plan should have the error_message set
|