"""Robot Framework keyword library for RegistryCache integration tests. Provides keywords for testing the RegistryCache against a fake registry server started by the test suite. """ from __future__ import annotations import asyncio from typing import Any, Optional from cleveractors.registry.cache import RegistryCache from cleveractors.registry.client import RegistryClient ROBOT_LIBRARY_SCOPE = "TEST SUITE" # pragma: no cover - integration test library class RegistryCacheLib: # pragma: no cover - integration test library """Keyword library for RegistryCache Robot Framework integration tests.""" def __init__(self) -> None: self._client: Optional[RegistryClient] = None self._cache: Optional[RegistryCache] = None self._result: Any = None def create_registry_cache(self, base_url: str) -> None: self._client = RegistryClient(base_url=base_url) self._cache = RegistryCache(self._client, validate_content=False) def create_registry_cache_with_config( self, base_url: str, max_size: str, ttl: str ) -> None: self._client = RegistryClient(base_url=base_url) self._cache = RegistryCache( self._client, max_size=int(max_size), ttl=float(ttl), validate_content=False ) def cache_get_package(self, package_id: str) -> None: async def _call() -> None: self._result = await self._cache.get_package(package_id) self._run(_call) def cache_stats_hits_equals(self, expected: str) -> None: actual = str(self._cache.stats.hits) if actual != expected: raise AssertionError(f"Hits: expected {expected!r}, got {actual!r}") def cache_stats_misses_equals(self, expected: str) -> None: actual = str(self._cache.stats.misses) if actual != expected: raise AssertionError(f"Misses: expected {expected!r}, got {actual!r}") def cache_stats_evictions_equals(self, expected: str) -> None: actual = str(self._cache.stats.evictions) if actual != expected: raise AssertionError(f"Evictions: expected {expected!r}, got {actual!r}") def cache_should_not_contain(self, package_id: str) -> None: if package_id in self._cache: raise AssertionError(f"Cache still contains {package_id!r}") def cache_should_contain(self, package_id: str) -> None: if package_id not in self._cache: raise AssertionError(f"Cache does not contain {package_id!r}") def cache_clear(self) -> None: async def _call() -> None: await self._cache.clear() self._run(_call) def cache_invalidate(self, package_id: str) -> None: async def _call() -> None: self._result = await self._cache.invalidate(package_id) self._run(_call) def invalidate_result_should_be(self, expected: str) -> None: result_str = str(self._result) if result_str != expected: raise AssertionError( f"Invalidate result: expected {expected!r}, got {result_str!r}" ) def close_cache(self) -> None: async def _call() -> None: await self._cache.close() self._run(_call) @staticmethod def _run(coro_fn: Any, timeout: float = 30.0) -> None: try: loop = asyncio.get_running_loop() future = asyncio.run_coroutine_threadsafe(coro_fn(), loop) future.result(timeout=timeout) except RuntimeError: asyncio.run(asyncio.wait_for(coro_fn(), timeout=timeout))