forked from cleveragents/cleveragents-core
2365f9a355
Behave BDD scenarios (3) tagged @tdd_bug @tdd_bug_592 @tdd_expected_fail exercise the real ActorRegistry._actor_name() code path with a provider whose default model contains '/' separators. The tests assert correct behaviour (exit 0, single-slash names, valid JSON) and fail while the bug is present; the @tdd_expected_fail handler inverts results so CI stays green. Includes Robot Framework integration smoke tests (3), ASV benchmarks (3), and a shared FakeProviderInfo/FakeProviderRegistry mock in features/mocks/fake_provider.py. ISSUES CLOSED: #634
89 lines
2.7 KiB
Python
89 lines
2.7 KiB
Python
"""Fake provider stubs for BDD and benchmark tests.
|
|
|
|
These lightweight stand-ins avoid importing the real ``ProviderInfo`` (which
|
|
pulls in heavy dependencies) while satisfying ``ActorRegistry``'s duck-typed
|
|
contract for provider discovery.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
from unittest.mock import MagicMock
|
|
|
|
from cleveragents.actor.registry import ActorRegistry
|
|
from cleveragents.domain.models.core.actor import Actor
|
|
from cleveragents.providers.registry import ProviderCapabilities
|
|
|
|
|
|
@dataclass
|
|
class FakeProviderInfo:
|
|
"""Minimal stand-in for ``ProviderInfo``."""
|
|
|
|
name: str
|
|
default_model: str
|
|
provider_type: Any = None
|
|
capabilities: Any = None
|
|
api_key_env_var: str = ""
|
|
|
|
def __post_init__(self) -> None:
|
|
if self.provider_type is None:
|
|
self.provider_type = MagicMock(value=self.name)
|
|
if self.capabilities is None:
|
|
self.capabilities = ProviderCapabilities()
|
|
|
|
|
|
@dataclass
|
|
class FakeProviderRegistry:
|
|
"""Stand-in for ``ProviderRegistry``."""
|
|
|
|
providers: list[FakeProviderInfo] = field(default_factory=list)
|
|
|
|
def get_configured_providers(self) -> list[FakeProviderInfo]:
|
|
return self.providers
|
|
|
|
|
|
def make_registry(
|
|
providers: list[FakeProviderInfo] | None = None,
|
|
) -> tuple[MagicMock, ActorRegistry]:
|
|
"""Build a real ``ActorRegistry`` with mocked service/settings.
|
|
|
|
The ``ActorService`` is mocked so there is no database dependency, but
|
|
the ``ActorRegistry`` code (including ``_actor_name()``) runs for real.
|
|
|
|
Actors successfully created by ``upsert_actor`` are captured so that
|
|
``list_actors`` returns them — ensuring Scenario 3 ("valid JSON") can
|
|
detect when the bug is actually fixed.
|
|
"""
|
|
provider_reg = FakeProviderRegistry(providers=providers or [])
|
|
|
|
captured_actors: list[Actor] = []
|
|
|
|
def _capturing_upsert(**kwargs: Any) -> Actor:
|
|
actor = Actor(
|
|
name=kwargs.get("name", "mock/actor"),
|
|
provider=kwargs.get("provider", "mock"),
|
|
model=kwargs.get("model", "actor"),
|
|
config_blob={},
|
|
config_hash=Actor.compute_hash({}),
|
|
)
|
|
captured_actors.append(actor)
|
|
return actor
|
|
|
|
mock_service = MagicMock()
|
|
mock_service.list_actors.side_effect = lambda: list(captured_actors)
|
|
mock_service.get_default_actor.return_value = None
|
|
mock_service.upsert_actor.side_effect = _capturing_upsert
|
|
|
|
mock_settings = MagicMock()
|
|
mock_settings.resolve_provider_defaults.return_value = MagicMock(
|
|
provider=None, model=None
|
|
)
|
|
|
|
registry = ActorRegistry(
|
|
actor_service=mock_service,
|
|
provider_registry=provider_reg,
|
|
settings=mock_settings,
|
|
)
|
|
return mock_service, registry
|