fc50a068a4
Add BDD scenarios to git_worktree_coverage_boost.feature and corresponding step definitions to cover the new error-path cleanup branches introduced by the TOCTOU race condition fix: - create() cleanup of _parent_temp_dir on TimeoutExpired during worktree add - create() cleanup of _parent_temp_dir on CalledProcessError during worktree add - commit() cleanup of _parent_temp_dir on TimeoutExpired - rollback() cleanup of _parent_temp_dir on TimeoutExpired - cleanup() OSError handler when removing parent temp directory These branches were previously uncovered, causing the CI coverage job to fail below the 97% threshold. ISSUES CLOSED: #7507
150 lines
6.9 KiB
Gherkin
150 lines
6.9 KiB
Gherkin
Feature: Git worktree sandbox coverage boost
|
|
As a developer
|
|
I want to exercise uncovered edge cases in the git worktree sandbox
|
|
So that code coverage is maximised for git_worktree.py
|
|
|
|
# --- _sanitise_branch_name edge case ---
|
|
|
|
Scenario: Sanitise branch name with all-special-chars falls back to sandbox
|
|
When gwtcb _sanitise_branch_name is called with "!!!"
|
|
Then gwtcb the result should be "sandbox"
|
|
|
|
# --- create fails when path is not repo root ---
|
|
|
|
Scenario: Create fails when path is not the repository root
|
|
Given a gwtcb sandbox pointed at a non-root subdirectory
|
|
When gwtcb create is called for plan "plan-001"
|
|
Then a gwtcb SandboxCreationError should be raised
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- create times out ---
|
|
|
|
Scenario: Create raises SandboxCreationError on timeout
|
|
Given a gwtcb sandbox with mocked _run_git that times out
|
|
When gwtcb create is called expecting a timeout error
|
|
Then a gwtcb SandboxCreationError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- get_path with None worktree_path ---
|
|
|
|
Scenario: get_path raises SandboxStateError when worktree_path is None
|
|
Given a gwtcb sandbox in CREATED state with None worktree_path
|
|
When gwtcb get_path is called with "some/file.py"
|
|
Then a gwtcb SandboxStateError should be raised with message "Worktree path not set"
|
|
|
|
# --- commit with uninitialised worktree ---
|
|
|
|
Scenario: Commit raises SandboxStateError when worktree not initialised
|
|
Given a gwtcb sandbox in ACTIVE state with no worktree or branch
|
|
When gwtcb commit is called with message "should fail"
|
|
Then a gwtcb SandboxStateError should be raised with message "Worktree not initialised"
|
|
|
|
# --- commit with modified files in diff output ---
|
|
|
|
Scenario: Commit parses modified files in diff output
|
|
Given a gwtcb sandbox ready to commit with modified-file diff output
|
|
When gwtcb commit is called with message "modify files"
|
|
Then the gwtcb commit result should include changed file "src/modified.py"
|
|
And the gwtcb commit result should include added file "src/new.py"
|
|
And the gwtcb commit result should include deleted file "src/old.py"
|
|
|
|
# --- commit timeout ---
|
|
|
|
Scenario: Commit raises SandboxCommitError on timeout
|
|
Given a gwtcb sandbox in ACTIVE state ready to commit
|
|
And gwtcb _run_git is mocked to raise TimeoutExpired on commit
|
|
When gwtcb commit is called expecting a timeout error
|
|
Then a gwtcb SandboxCommitError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- commit CalledProcessError ---
|
|
|
|
Scenario: Commit raises SandboxCommitError on CalledProcessError
|
|
Given a gwtcb sandbox in ACTIVE state ready to commit
|
|
And gwtcb _run_git is mocked to raise CalledProcessError on commit
|
|
When gwtcb commit is called expecting a process error
|
|
Then a gwtcb SandboxCommitError should be raised with message "Failed to commit"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- rollback with uninitialised worktree ---
|
|
|
|
Scenario: Rollback raises SandboxStateError when worktree not initialised
|
|
Given a gwtcb sandbox in ACTIVE state with no worktree or base commit
|
|
When gwtcb rollback is called expecting a state error
|
|
Then a gwtcb SandboxStateError should be raised with message "Worktree not initialised"
|
|
|
|
# --- rollback timeout ---
|
|
|
|
Scenario: Rollback raises SandboxRollbackError on timeout
|
|
Given a gwtcb sandbox in ACTIVE state ready to rollback
|
|
And gwtcb _run_git is mocked to raise TimeoutExpired on rollback
|
|
When gwtcb rollback is called expecting a timeout error
|
|
Then a gwtcb SandboxRollbackError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- rollback CalledProcessError ---
|
|
|
|
Scenario: Rollback raises SandboxRollbackError on CalledProcessError
|
|
Given a gwtcb sandbox in ACTIVE state ready to rollback
|
|
And gwtcb _run_git is mocked to raise CalledProcessError on rollback
|
|
When gwtcb rollback is called expecting a process error
|
|
Then a gwtcb SandboxRollbackError should be raised with message "Failed to rollback"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- cleanup with worktree remove failure ---
|
|
|
|
Scenario: Cleanup falls back to shutil when git worktree remove fails
|
|
Given a gwtcb sandbox with a worktree directory that exists
|
|
And gwtcb _run_git is mocked to fail on worktree remove
|
|
When gwtcb cleanup is called
|
|
Then the gwtcb sandbox should be in the "cleaned_up" state
|
|
|
|
# --- cleanup with branch delete failure ---
|
|
|
|
Scenario: Cleanup warns and continues when branch delete fails
|
|
Given a gwtcb sandbox with a branch name set but no worktree directory
|
|
And gwtcb _run_git is mocked to fail on branch delete
|
|
When gwtcb cleanup is called
|
|
Then the gwtcb sandbox should be in the "cleaned_up" state
|
|
|
|
# --- create: timeout after parent dir is created (TOCTOU fix coverage) ---
|
|
|
|
Scenario: Create cleans up parent dir on timeout during git worktree add
|
|
Given a gwtcb sandbox with mocked _run_git that times out on worktree add
|
|
When gwtcb create is called expecting a timeout error
|
|
Then a gwtcb SandboxCreationError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- create: CalledProcessError after parent dir is created (TOCTOU fix coverage) ---
|
|
|
|
Scenario: Create cleans up parent dir on CalledProcessError during git worktree add
|
|
Given a gwtcb sandbox with mocked _run_git that fails on worktree add
|
|
When gwtcb create is called expecting a process error
|
|
Then a gwtcb SandboxCreationError should be raised
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- commit: timeout with parent dir set (TOCTOU fix coverage) ---
|
|
|
|
Scenario: Commit cleans up parent dir on timeout
|
|
Given a gwtcb sandbox in ACTIVE state ready to commit with parent dir set
|
|
And gwtcb _run_git is mocked to raise TimeoutExpired on commit
|
|
When gwtcb commit is called expecting a timeout error
|
|
Then a gwtcb SandboxCommitError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- rollback: timeout with parent dir set (TOCTOU fix coverage) ---
|
|
|
|
Scenario: Rollback cleans up parent dir on timeout
|
|
Given a gwtcb sandbox in ACTIVE state ready to rollback with parent dir set
|
|
And gwtcb _run_git is mocked to raise TimeoutExpired on rollback
|
|
When gwtcb rollback is called expecting a timeout error
|
|
Then a gwtcb SandboxRollbackError should be raised with message "timed out"
|
|
And the gwtcb sandbox should be in the "errored" state
|
|
|
|
# --- cleanup: OSError when removing parent dir (TOCTOU fix coverage) ---
|
|
|
|
Scenario: Cleanup continues when parent dir removal raises OSError
|
|
Given a gwtcb sandbox with a parent dir that raises OSError on removal
|
|
When gwtcb cleanup is called
|
|
Then the gwtcb sandbox should be in the "cleaned_up" state
|