Files
cleveractors-core/features/registry_exceptions.feature
CoreRasurae e8bd348c77
CI / lint (pull_request) Successful in 41s
CI / typecheck (pull_request) Successful in 56s
CI / security (pull_request) Successful in 51s
CI / quality (pull_request) Successful in 53s
CI / integration_tests (pull_request) Successful in 1m10s
CI / build (pull_request) Successful in 43s
CI / unit_tests (pull_request) Successful in 3m30s
CI / coverage (pull_request) Successful in 3m22s
CI / status-check (pull_request) Successful in 4s
CI / quality (push) Successful in 45s
CI / security (push) Successful in 48s
CI / lint (push) Successful in 49s
CI / typecheck (push) Successful in 50s
CI / build (push) Successful in 49s
CI / integration_tests (push) Successful in 1m9s
CI / unit_tests (push) Successful in 3m13s
CI / coverage (push) Successful in 3m7s
CI / status-check (push) Successful in 3s
feat(registry): implement RegistryError hierarchy with typed exceptions
Add RegistryError base with message, details, and original_reference fields.
Implement all 9 typed exception types per Package Registry Standard §13.2:
PackageNotFoundError, InvalidPackageIdError, InvalidPackageReferenceError,
VersionNotFoundError, ValidationError, AuthenticationRequiredError,
AccessDeniedError, ConflictError, and RegistryNetworkError.

RegistryNetworkError carries status_code and url for transport failures.
__str__ includes original_reference when available.
exception_for_status() maps HTTP codes to typed exceptions.
_ERROR_TYPE_MAP enables error-type parsing from JSON error bodies.

23 Behave BDD scenarios in features/registry_exceptions.feature.
12 Robot Framework integration tests in robot/exceptions.robot.
Existing registry_http_client tests updated for InternalServerError removal.

ISSUES CLOSED: #29
2026-06-11 20:44:54 +01:00

184 lines
9.3 KiB
Gherkin

Feature: Registry Exception Hierarchy
As a developer using the Package Registry Standard v1.0.0
I want a typed exception hierarchy per §13.2
So that I can handle each error type appropriately
Background:
Given I have imported the registry exception module
# ── RegistryError construction ────────────────────────────────────────
Scenario: RegistryError with message only
When I raise a plain RegistryError with text "something went wrong"
Then the error message should be "something went wrong"
And the error should have no details
And the error should have no original_reference
Scenario: RegistryError with message and details
When I raise a RegistryError text "invalid input" and detail {"field": "name"}
Then the error message should be "invalid input"
And the error details should equal {"field": "name"}
And the error should have no original_reference
Scenario: RegistryError with message and original_reference
When I raise a RegistryError text "not found" and reference "pkg_act_unknown"
Then the error message should be "not found"
And the error original_reference should be "pkg_act_unknown"
And str of the error should be "not found [ref: pkg_act_unknown]"
Scenario: RegistryError with message, details, and original_reference
When I raise a RegistryError text "conflict" detail {"dup": true} and reference "pkg_act_abc"
Then the error message should be "conflict"
And the error details should equal {"dup": true}
And the error original_reference should be "pkg_act_abc"
And str of the error should be "conflict [ref: pkg_act_abc]"
# ── __str__ without original_reference ────────────────────────────────
Scenario: RegistryError __str__ is just the message when no reference
When I raise a plain RegistryError with text "plain error"
Then str of the error should be "plain error"
# ── RegistryNetworkError specific fields ──────────────────────────────
Scenario: RegistryNetworkError carries status_code and url
When I raise a simple network error message "server error" status 500 url "https://registry.example.com/packages/pkg_act_test"
Then the error message should be "server error"
And the error status_code should be 500
And the error url should be "https://registry.example.com/packages/pkg_act_test"
And str of the error should be "server error [status: 500] [url: https://registry.example.com/packages/pkg_act_test]"
Scenario: RegistryNetworkError with all fields
When I raise a fully detailed network error message "timeout" detail {"retries": 3} ref "pkg_act_x" status None url "https://bad.example.com"
Then the error message should be "timeout"
And the error details should equal {"retries": 3}
And the error original_reference should be "pkg_act_x"
And the error status_code should be None
And the error url should be "https://bad.example.com"
And str of the error should be "timeout [ref: pkg_act_x] [url: https://bad.example.com]"
# ── Typed subclass construction ──────────────────────────────────────
Scenario: PackageNotFoundError construction
When I raise a PackageNotFoundError with message "pkg not found"
Then the error message should be "pkg not found"
And the error should be an instance of PackageNotFoundError
Scenario: InvalidPackageIdError construction
When I raise an InvalidPackageIdError with message "bad id"
Then the error message should be "bad id"
And the error should be an instance of InvalidPackageIdError
Scenario: InvalidPackageReferenceError construction
When I raise an InvalidPackageReferenceError with message "bad ref"
Then the error message should be "bad ref"
And the error should be an instance of InvalidPackageReferenceError
Scenario: VersionNotFoundError construction
When I raise a VersionNotFoundError with message "version missing"
Then the error message should be "version missing"
And the error should be an instance of VersionNotFoundError
Scenario: ValidationError construction
When I raise a ValidationError with message "invalid"
Then the error message should be "invalid"
And the error should be an instance of ValidationError
Scenario: AuthenticationRequiredError construction
When I raise an AuthenticationRequiredError with message "auth needed"
Then the error message should be "auth needed"
And the error should be an instance of AuthenticationRequiredError
Scenario: AccessDeniedError construction
When I raise an AccessDeniedError with message "no access"
Then the error message should be "no access"
And the error should be an instance of AccessDeniedError
Scenario: ConflictError construction
When I raise a ConflictError with message "duplicate"
Then the error message should be "duplicate"
And the error should be an instance of ConflictError
# ── HTTP status code mapping (§13.2) ─────────────────────────────────
Scenario: 400 maps to InvalidPackageIdError
When I call exception_for_status with code 400 and message "bad request"
Then the result should be an instance of InvalidPackageIdError
And the error message should be "bad request"
Scenario: 401 maps to AuthenticationRequiredError
When I call exception_for_status with code 401 and message "auth required"
Then the result should be an instance of AuthenticationRequiredError
And the error message should be "auth required"
Scenario: 403 maps to AccessDeniedError
When I call exception_for_status with code 403 and message "denied"
Then the result should be an instance of AccessDeniedError
And the error message should be "denied"
Scenario: 404 maps to PackageNotFoundError
When I call exception_for_status with code 404 and message "gone"
Then the result should be an instance of PackageNotFoundError
And the error message should be "gone"
Scenario: 409 maps to ConflictError
When I call exception_for_status with code 409 and message "conflict"
Then the result should be an instance of ConflictError
And the error message should be "conflict"
Scenario: 500 maps to RegistryNetworkError
When I call exception_for_status with code 500 and message "server error"
Then the result should be an instance of RegistryNetworkError
And the error message should be "server error"
And the error status_code should be 500
Scenario: 503 maps to RegistryNetworkError
When I call exception_for_status with code 503 and message "unavailable"
Then the result should be an instance of RegistryNetworkError
And the error message should be "unavailable"
And the error status_code should be 503
Scenario: non-integer status_code falls back to RegistryError
When I call exception_for_status with non-integer code "not-a-number" and message "bad status"
Then the result should be an instance of RegistryError
And the error message should be "bad status"
Scenario: Unknown status falls back to RegistryError
When I call exception_for_status with code 418 and message "teapot"
Then the result should be an instance of RegistryError
And the error message should be "teapot"
# ── Inheritance chain ─────────────────────────────────────────────────
Scenario: All typed errors inherit from RegistryError
When I check that PackageNotFoundError is a subclass of RegistryError
And I check that InvalidPackageIdError is a subclass of RegistryError
And I check that InvalidPackageReferenceError is a subclass of RegistryError
And I check that VersionNotFoundError is a subclass of RegistryError
And I check that ValidationError is a subclass of RegistryError
And I check that AuthenticationRequiredError is a subclass of RegistryError
And I check that AccessDeniedError is a subclass of RegistryError
And I check that ConflictError is a subclass of RegistryError
And I check that RegistryNetworkError is a subclass of RegistryError
Then all 9 checks should pass
Scenario: RegistryError inherits from CleverAgentsException
When I check that RegistryError is a subclass of CleverAgentsException
Then all 1 checks should pass
# ── Error type map completeness ──────────────────────────────────────
Scenario: _ERROR_TYPE_MAP contains all error type keys
When I inspect the _ERROR_TYPE_MAP
Then the map should contain key "PackageNotFound"
And the map should contain key "InvalidPackageId"
And the map should contain key "InvalidPackageReference"
And the map should contain key "VersionNotFound"
And the map should contain key "ValidationError"
And the map should contain key "AuthenticationRequired"
And the map should contain key "AccessDenied"
And the map should contain key "Conflict"
And the map should contain key "InternalServerError"
And the value for key "InternalServerError" should be RegistryNetworkError
And the map should have exactly 9 keys