forked from cleveragents/cleveragents-core
559 lines
19 KiB
Python
559 lines
19 KiB
Python
"""Step definitions for Resource domain model tests (B1.2, B1.3, B1.4)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from behave import given, then, when
|
|
from behave.runner import Context
|
|
from pydantic import ValidationError
|
|
|
|
from cleveragents.domain.models.core.resource import (
|
|
Resource,
|
|
ResourceType,
|
|
SandboxStrategy,
|
|
)
|
|
|
|
# ResourceType Steps
|
|
|
|
|
|
@then('the resource types should be "{expected_order}"')
|
|
def step_check_resource_type_values(context: Context, expected_order: str) -> None:
|
|
"""Verify that ResourceType has all expected values in order."""
|
|
expected = [v.strip() for v in expected_order.split(",")]
|
|
actual = [rt.value for rt in ResourceType]
|
|
assert actual == expected, f"Expected resource types {expected}, got {actual}"
|
|
|
|
|
|
@when("I access ResourceType.GIT_REPOSITORY")
|
|
def step_access_git_repository(context: Context) -> None:
|
|
"""Access the GIT_REPOSITORY enum member."""
|
|
context.resource_type = ResourceType.GIT_REPOSITORY
|
|
|
|
|
|
@when("I access ResourceType.FILESYSTEM")
|
|
def step_access_filesystem(context: Context) -> None:
|
|
"""Access the FILESYSTEM enum member."""
|
|
context.resource_type = ResourceType.FILESYSTEM
|
|
|
|
|
|
@when("I access ResourceType.DATABASE")
|
|
def step_access_database(context: Context) -> None:
|
|
"""Access the DATABASE enum member."""
|
|
context.resource_type = ResourceType.DATABASE
|
|
|
|
|
|
@when("I access ResourceType.API_ENDPOINT")
|
|
def step_access_api_endpoint(context: Context) -> None:
|
|
"""Access the API_ENDPOINT enum member."""
|
|
context.resource_type = ResourceType.API_ENDPOINT
|
|
|
|
|
|
@when("I access ResourceType.DOCUMENT_CORPUS")
|
|
def step_access_document_corpus(context: Context) -> None:
|
|
"""Access the DOCUMENT_CORPUS enum member."""
|
|
context.resource_type = ResourceType.DOCUMENT_CORPUS
|
|
|
|
|
|
@when("I access ResourceType.CLOUD_INFRASTRUCTURE")
|
|
def step_access_cloud_infrastructure(context: Context) -> None:
|
|
"""Access the CLOUD_INFRASTRUCTURE enum member."""
|
|
context.resource_type = ResourceType.CLOUD_INFRASTRUCTURE
|
|
|
|
|
|
@then('the resource type value should be "{expected}"')
|
|
def step_check_resource_type_value(context: Context, expected: str) -> None:
|
|
"""Check the resource type value matches expected."""
|
|
actual = context.resource_type.value
|
|
assert actual == expected, f"Expected value '{expected}', got '{actual}'"
|
|
|
|
|
|
@then("the resource type should be a string")
|
|
def step_check_resource_type_is_string(context: Context) -> None:
|
|
"""Verify ResourceType inherits from str."""
|
|
assert isinstance(context.resource_type, str), (
|
|
f"Expected ResourceType to be a string, got {type(context.resource_type)}"
|
|
)
|
|
|
|
|
|
@when('I create a ResourceType from string "{value}"')
|
|
def step_create_resource_type_from_string(context: Context, value: str) -> None:
|
|
"""Create a ResourceType from a string value."""
|
|
context.error = None
|
|
try:
|
|
context.resource_type = ResourceType(value)
|
|
except ValueError as e:
|
|
context.error = e
|
|
|
|
|
|
@when('I try to create a ResourceType from string "{value}"')
|
|
def step_try_create_resource_type_from_string(context: Context, value: str) -> None:
|
|
"""Attempt to create a ResourceType from an invalid string."""
|
|
context.error = None
|
|
try:
|
|
context.resource_type = ResourceType(value)
|
|
except ValueError as e:
|
|
context.error = e
|
|
|
|
|
|
@then("a ValueError should be raised")
|
|
def step_check_value_error_raised(context: Context) -> None:
|
|
"""Verify a ValueError was captured."""
|
|
assert context.error is not None, "Expected a ValueError but none was raised"
|
|
assert isinstance(context.error, ValueError), (
|
|
f"Expected ValueError, got {type(context.error).__name__}"
|
|
)
|
|
|
|
|
|
# SandboxStrategy Steps
|
|
|
|
|
|
@then('the sandbox strategies should be "{expected_order}"')
|
|
def step_check_sandbox_strategy_values(context: Context, expected_order: str) -> None:
|
|
"""Verify that SandboxStrategy has all expected values in order."""
|
|
expected = [v.strip() for v in expected_order.split(",")]
|
|
actual = [ss.value for ss in SandboxStrategy]
|
|
assert actual == expected, f"Expected sandbox strategies {expected}, got {actual}"
|
|
|
|
|
|
@when("I access SandboxStrategy.GIT_WORKTREE")
|
|
def step_access_git_worktree(context: Context) -> None:
|
|
"""Access the GIT_WORKTREE enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.GIT_WORKTREE
|
|
|
|
|
|
@when("I access SandboxStrategy.COPY_ON_WRITE")
|
|
def step_access_copy_on_write(context: Context) -> None:
|
|
"""Access the COPY_ON_WRITE enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.COPY_ON_WRITE
|
|
|
|
|
|
@when("I access SandboxStrategy.OVERLAY")
|
|
def step_access_overlay(context: Context) -> None:
|
|
"""Access the OVERLAY enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.OVERLAY
|
|
|
|
|
|
@when("I access SandboxStrategy.TRANSACTION_ROLLBACK")
|
|
def step_access_transaction_rollback(context: Context) -> None:
|
|
"""Access the TRANSACTION_ROLLBACK enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.TRANSACTION_ROLLBACK
|
|
|
|
|
|
@when("I access SandboxStrategy.VERSIONING")
|
|
def step_access_versioning(context: Context) -> None:
|
|
"""Access the VERSIONING enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.VERSIONING
|
|
|
|
|
|
@when("I access SandboxStrategy.NONE")
|
|
def step_access_none_strategy(context: Context) -> None:
|
|
"""Access the NONE enum member."""
|
|
context.sandbox_strategy = SandboxStrategy.NONE
|
|
|
|
|
|
@then('the sandbox strategy value should be "{expected}"')
|
|
def step_check_sandbox_strategy_value(context: Context, expected: str) -> None:
|
|
"""Check the sandbox strategy value matches expected."""
|
|
actual = context.sandbox_strategy.value
|
|
assert actual == expected, f"Expected value '{expected}', got '{actual}'"
|
|
|
|
|
|
@then("the sandbox strategy should be a string")
|
|
def step_check_sandbox_strategy_is_string(context: Context) -> None:
|
|
"""Verify SandboxStrategy inherits from str."""
|
|
assert isinstance(context.sandbox_strategy, str), (
|
|
f"Expected SandboxStrategy to be a string, got {type(context.sandbox_strategy)}"
|
|
)
|
|
|
|
|
|
# SandboxStrategy.supports_rollback Tests
|
|
|
|
|
|
@then("SandboxStrategy.GIT_WORKTREE should support rollback")
|
|
def step_git_worktree_supports_rollback(context: Context) -> None:
|
|
"""Verify GIT_WORKTREE supports rollback."""
|
|
assert SandboxStrategy.GIT_WORKTREE.supports_rollback is True
|
|
|
|
|
|
@then("SandboxStrategy.COPY_ON_WRITE should support rollback")
|
|
def step_copy_on_write_supports_rollback(context: Context) -> None:
|
|
"""Verify COPY_ON_WRITE supports rollback."""
|
|
assert SandboxStrategy.COPY_ON_WRITE.supports_rollback is True
|
|
|
|
|
|
@then("SandboxStrategy.OVERLAY should support rollback")
|
|
def step_overlay_supports_rollback(context: Context) -> None:
|
|
"""Verify OVERLAY supports rollback."""
|
|
assert SandboxStrategy.OVERLAY.supports_rollback is True
|
|
|
|
|
|
@then("SandboxStrategy.TRANSACTION_ROLLBACK should support rollback")
|
|
def step_transaction_rollback_supports_rollback(context: Context) -> None:
|
|
"""Verify TRANSACTION_ROLLBACK supports rollback."""
|
|
assert SandboxStrategy.TRANSACTION_ROLLBACK.supports_rollback is True
|
|
|
|
|
|
@then("SandboxStrategy.VERSIONING should support rollback")
|
|
def step_versioning_supports_rollback(context: Context) -> None:
|
|
"""Verify VERSIONING supports rollback."""
|
|
assert SandboxStrategy.VERSIONING.supports_rollback is True
|
|
|
|
|
|
@then("SandboxStrategy.NONE should not support rollback")
|
|
def step_none_does_not_support_rollback(context: Context) -> None:
|
|
"""Verify NONE does not support rollback."""
|
|
assert SandboxStrategy.NONE.supports_rollback is False
|
|
|
|
|
|
# SandboxStrategy.is_copy_based Tests
|
|
|
|
|
|
@then("SandboxStrategy.COPY_ON_WRITE should be copy based")
|
|
def step_copy_on_write_is_copy_based(context: Context) -> None:
|
|
"""Verify COPY_ON_WRITE is copy based."""
|
|
assert SandboxStrategy.COPY_ON_WRITE.is_copy_based is True
|
|
|
|
|
|
@then("SandboxStrategy.OVERLAY should be copy based")
|
|
def step_overlay_is_copy_based(context: Context) -> None:
|
|
"""Verify OVERLAY is copy based."""
|
|
assert SandboxStrategy.OVERLAY.is_copy_based is True
|
|
|
|
|
|
@then("SandboxStrategy.GIT_WORKTREE should not be copy based")
|
|
def step_git_worktree_not_copy_based(context: Context) -> None:
|
|
"""Verify GIT_WORKTREE is not copy based."""
|
|
assert SandboxStrategy.GIT_WORKTREE.is_copy_based is False
|
|
|
|
|
|
@then("SandboxStrategy.TRANSACTION_ROLLBACK should not be copy based")
|
|
def step_transaction_rollback_not_copy_based(context: Context) -> None:
|
|
"""Verify TRANSACTION_ROLLBACK is not copy based."""
|
|
assert SandboxStrategy.TRANSACTION_ROLLBACK.is_copy_based is False
|
|
|
|
|
|
@then("SandboxStrategy.VERSIONING should not be copy based")
|
|
def step_versioning_not_copy_based(context: Context) -> None:
|
|
"""Verify VERSIONING is not copy based."""
|
|
assert SandboxStrategy.VERSIONING.is_copy_based is False
|
|
|
|
|
|
@then("SandboxStrategy.NONE should not be copy based")
|
|
def step_none_not_copy_based(context: Context) -> None:
|
|
"""Verify NONE is not copy based."""
|
|
assert SandboxStrategy.NONE.is_copy_based is False
|
|
|
|
|
|
# Resource Pydantic Model Steps (B1.2)
|
|
|
|
VALID_ULID = "01ARZ3NDEKTSV4RRFFQ69G5FAV"
|
|
|
|
|
|
@given(
|
|
'a Resource with required fields id "{resource_id}" name "{name}" type "{rtype}" location "{location}"'
|
|
)
|
|
def step_create_resource(
|
|
context: Context, resource_id: str, name: str, rtype: str, location: str
|
|
) -> None:
|
|
"""Create a Resource with required fields only."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@given("I have a valid Resource")
|
|
def step_have_valid_resource(context: Context) -> None:
|
|
"""Create a valid Resource for mutation testing."""
|
|
context.resource = Resource(
|
|
resource_id=VALID_ULID,
|
|
name="my-repo",
|
|
type=ResourceType.GIT_REPOSITORY,
|
|
location="/tmp/repo",
|
|
)
|
|
|
|
|
|
@when("I try to modify the resource name")
|
|
def step_try_modify_resource_name(context: Context) -> None:
|
|
"""Attempt to modify a frozen model field."""
|
|
context.error = None
|
|
try:
|
|
context.resource.name = "new-name" # type: ignore[misc]
|
|
except ValidationError as e:
|
|
context.error = e
|
|
|
|
|
|
@given(
|
|
'a remote Resource with id "{resource_id}" name "{name}" type "{rtype}" location "{location}"'
|
|
)
|
|
def step_create_resource_remote(
|
|
context: Context, resource_id: str, name: str, rtype: str, location: str
|
|
) -> None:
|
|
"""Create a remote Resource."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
is_remote=True,
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@given(
|
|
'a read-only Resource with id "{resource_id}" name "{name}" type "{rtype}" location "{location}"'
|
|
)
|
|
def step_create_resource_read_only(
|
|
context: Context, resource_id: str, name: str, rtype: str, location: str
|
|
) -> None:
|
|
"""Create a read-only Resource."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
read_only=True,
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@given(
|
|
'a Resource with id "{resource_id}" name "{name}" type "{rtype}" location "{location}" strategy "{strategy}"'
|
|
)
|
|
def step_create_resource_with_strategy(
|
|
context: Context,
|
|
resource_id: str,
|
|
name: str,
|
|
rtype: str,
|
|
location: str,
|
|
strategy: str,
|
|
) -> None:
|
|
"""Create a Resource with a specific sandbox strategy."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
sandbox_strategy=SandboxStrategy(strategy),
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@given(
|
|
'a Resource with id "{resource_id}" name "{name}" type "{rtype}" location "{location}" metadata "{meta_str}"'
|
|
)
|
|
def step_create_resource_with_metadata(
|
|
context: Context,
|
|
resource_id: str,
|
|
name: str,
|
|
rtype: str,
|
|
location: str,
|
|
meta_str: str,
|
|
) -> None:
|
|
"""Create a Resource with metadata parsed from key=value pairs."""
|
|
metadata = {}
|
|
for pair in meta_str.split(","):
|
|
key, value = pair.strip().split("=", 1)
|
|
metadata[key.strip()] = value.strip()
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
metadata=metadata,
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@when(
|
|
'I try to create a Resource with id "{resource_id}" name "{name}" type "{rtype}" location "{location}"'
|
|
)
|
|
def step_try_create_resource(
|
|
context: Context, resource_id: str, name: str, rtype: str, location: str
|
|
) -> None:
|
|
"""Attempt to create a Resource that may fail validation."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=resource_id,
|
|
name=name,
|
|
type=ResourceType(rtype),
|
|
location=location,
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@when("I try to create a Resource with an empty name")
|
|
def step_try_create_resource_empty_name(context: Context) -> None:
|
|
"""Attempt to create a Resource with empty name."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=VALID_ULID,
|
|
name="",
|
|
type=ResourceType.GIT_REPOSITORY,
|
|
location="/tmp/repo",
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
@when("I try to create a Resource with an empty location")
|
|
def step_try_create_resource_empty_location(context: Context) -> None:
|
|
"""Attempt to create a Resource with empty location."""
|
|
context.error = None
|
|
try:
|
|
context.resource = Resource(
|
|
resource_id=VALID_ULID,
|
|
name="my-repo",
|
|
type=ResourceType.GIT_REPOSITORY,
|
|
location="",
|
|
)
|
|
except (ValidationError, ValueError) as e:
|
|
context.error = e
|
|
|
|
|
|
# Resource field assertion steps
|
|
|
|
|
|
@then('the resource name should be "{expected}"')
|
|
def step_check_resource_name(context: Context, expected: str) -> None:
|
|
"""Verify resource name."""
|
|
assert context.resource.name == expected, (
|
|
f"Expected name '{expected}', got '{context.resource.name}'"
|
|
)
|
|
|
|
|
|
@then("the resource type should be ResourceType.GIT_REPOSITORY")
|
|
def step_check_resource_type_git(context: Context) -> None:
|
|
"""Verify resource type is GIT_REPOSITORY."""
|
|
assert context.resource.type == ResourceType.GIT_REPOSITORY
|
|
|
|
|
|
@then('the resource location should be "{expected}"')
|
|
def step_check_resource_location(context: Context, expected: str) -> None:
|
|
"""Verify resource location."""
|
|
assert context.resource.location == expected, (
|
|
f"Expected location '{expected}', got '{context.resource.location}'"
|
|
)
|
|
|
|
|
|
@then("the resource is_remote should be false")
|
|
def step_check_resource_not_remote(context: Context) -> None:
|
|
"""Verify resource is not remote."""
|
|
assert context.resource.is_remote is False
|
|
|
|
|
|
@then("the resource is_remote should be true")
|
|
def step_check_resource_is_remote(context: Context) -> None:
|
|
"""Verify resource is remote."""
|
|
assert context.resource.is_remote is True
|
|
|
|
|
|
@then("the resource sandbox_strategy should be SandboxStrategy.NONE")
|
|
def step_check_resource_strategy_none(context: Context) -> None:
|
|
"""Verify default sandbox strategy is NONE."""
|
|
assert context.resource.sandbox_strategy == SandboxStrategy.NONE
|
|
|
|
|
|
@then("the resource sandbox_strategy should be SandboxStrategy.GIT_WORKTREE")
|
|
def step_check_resource_strategy_worktree(context: Context) -> None:
|
|
"""Verify sandbox strategy is GIT_WORKTREE."""
|
|
assert context.resource.sandbox_strategy == SandboxStrategy.GIT_WORKTREE
|
|
|
|
|
|
@then("the resource read_only should be false")
|
|
def step_check_resource_not_readonly(context: Context) -> None:
|
|
"""Verify resource is not read-only."""
|
|
assert context.resource.read_only is False
|
|
|
|
|
|
@then("the resource read_only should be true")
|
|
def step_check_resource_is_readonly(context: Context) -> None:
|
|
"""Verify resource is read-only."""
|
|
assert context.resource.read_only is True
|
|
|
|
|
|
@then("the resource metadata should be empty")
|
|
def step_check_resource_metadata_empty(context: Context) -> None:
|
|
"""Verify resource metadata is empty dict."""
|
|
assert context.resource.metadata == {}, (
|
|
f"Expected empty metadata, got {context.resource.metadata}"
|
|
)
|
|
|
|
|
|
@then("the resource created_at should be set")
|
|
def step_check_resource_created_at(context: Context) -> None:
|
|
"""Verify resource has a created_at timestamp."""
|
|
assert context.resource.created_at is not None
|
|
|
|
|
|
@then('the resource metadata should contain key "{key}" with value "{value}"')
|
|
def step_check_resource_metadata_key(context: Context, key: str, value: str) -> None:
|
|
"""Verify resource metadata contains expected key-value pair."""
|
|
assert key in context.resource.metadata, (
|
|
f"Expected key '{key}' in metadata, got {context.resource.metadata}"
|
|
)
|
|
assert context.resource.metadata[key] == value, (
|
|
f"Expected metadata['{key}'] = '{value}', got '{context.resource.metadata[key]}'"
|
|
)
|
|
|
|
|
|
# Note: "a validation error should be raised" step is defined in domain_models_steps.py
|
|
|
|
|
|
# Resource property assertion steps
|
|
|
|
|
|
@then("the resource supports_sandbox should be true")
|
|
def step_check_supports_sandbox_true(context: Context) -> None:
|
|
"""Verify resource supports sandbox."""
|
|
assert context.resource.supports_sandbox is True
|
|
|
|
|
|
@then("the resource supports_sandbox should be false")
|
|
def step_check_supports_sandbox_false(context: Context) -> None:
|
|
"""Verify resource does not support sandbox."""
|
|
assert context.resource.supports_sandbox is False
|
|
|
|
|
|
@then("the resource can_write should be true")
|
|
def step_check_can_write_true(context: Context) -> None:
|
|
"""Verify resource can be written to."""
|
|
assert context.resource.can_write is True
|
|
|
|
|
|
@then("the resource can_write should be false")
|
|
def step_check_can_write_false(context: Context) -> None:
|
|
"""Verify resource cannot be written to."""
|
|
assert context.resource.can_write is False
|
|
|
|
|
|
@then('the resource get_sandbox_path with base "{base}" should end with "{suffix}"')
|
|
def step_check_sandbox_path(context: Context, base: str, suffix: str) -> None:
|
|
"""Verify get_sandbox_path returns expected path."""
|
|
result = context.resource.get_sandbox_path(Path(base))
|
|
assert str(result).endswith(suffix), (
|
|
f"Expected path ending with '{suffix}', got '{result}'"
|
|
)
|