"""Shared fixtures — clear all registries and the event bus between tests.""" from __future__ import annotations import os from unittest.mock import MagicMock import pytest from openjarvis.core.config import GpuInfo, HardwareInfo from openjarvis.core.events import EventBus, reset_event_bus from openjarvis.core.registry import ( AgentRegistry, BenchmarkRegistry, ChannelRegistry, CompressionRegistry, ConnectorRegistry, EngineRegistry, MemoryRegistry, ModelRegistry, RouterPolicyRegistry, SpeechRegistry, ToolRegistry, ) @pytest.fixture(autouse=True) def _clean_registries() -> None: """Ensure each test starts with empty registries and a fresh event bus.""" ModelRegistry.clear() EngineRegistry.clear() MemoryRegistry.clear() AgentRegistry.clear() ToolRegistry.clear() RouterPolicyRegistry.clear() BenchmarkRegistry.clear() ChannelRegistry.clear() SpeechRegistry.clear() CompressionRegistry.clear() ConnectorRegistry.clear() reset_event_bus() # --------------------------------------------------------------------------- # Hardware fixtures # --------------------------------------------------------------------------- @pytest.fixture def nvidia_gpu() -> GpuInfo: """NVIDIA A100 GPU fixture.""" return GpuInfo(vendor="nvidia", name="NVIDIA A100-SXM4-80GB", vram_gb=80.0, count=1) @pytest.fixture def nvidia_consumer_gpu() -> GpuInfo: """NVIDIA consumer GPU fixture.""" return GpuInfo( vendor="nvidia", name="NVIDIA GeForce RTX 4090", vram_gb=24.0, count=1, ) @pytest.fixture def nvidia_multi_gpu() -> GpuInfo: """NVIDIA multi-GPU fixture.""" return GpuInfo(vendor="nvidia", name="NVIDIA H100", vram_gb=80.0, count=4) @pytest.fixture def amd_gpu() -> GpuInfo: """AMD MI300X GPU fixture.""" return GpuInfo(vendor="amd", name="AMD Instinct MI300X", vram_gb=192.0, count=1) @pytest.fixture def apple_gpu() -> GpuInfo: """Apple Silicon GPU fixture.""" return GpuInfo(vendor="apple", name="Apple M4 Max", vram_gb=128.0, count=1) @pytest.fixture def hardware_nvidia(nvidia_gpu: GpuInfo) -> HardwareInfo: """Full NVIDIA hardware profile.""" return HardwareInfo( platform="linux", cpu_brand="AMD EPYC 7763", cpu_count=64, ram_gb=512.0, gpu=nvidia_gpu, ) @pytest.fixture def hardware_nvidia_consumer(nvidia_consumer_gpu: GpuInfo) -> HardwareInfo: """Consumer NVIDIA hardware profile.""" return HardwareInfo( platform="linux", cpu_brand="Intel Core i9-14900K", cpu_count=24, ram_gb=64.0, gpu=nvidia_consumer_gpu, ) @pytest.fixture def hardware_amd(amd_gpu: GpuInfo) -> HardwareInfo: """Full AMD hardware profile.""" return HardwareInfo( platform="linux", cpu_brand="AMD EPYC 9654", cpu_count=96, ram_gb=768.0, gpu=amd_gpu, ) @pytest.fixture def hardware_apple(apple_gpu: GpuInfo) -> HardwareInfo: """Apple Silicon hardware profile.""" return HardwareInfo( platform="darwin", cpu_brand="Apple M4 Max", cpu_count=16, ram_gb=128.0, gpu=apple_gpu, ) @pytest.fixture def hardware_cpu_only() -> HardwareInfo: """CPU-only hardware profile (no GPU).""" return HardwareInfo( platform="linux", cpu_brand="Intel Xeon E5-2686 v4", cpu_count=8, ram_gb=32.0, gpu=None, ) # --------------------------------------------------------------------------- # Engine availability fixtures # --------------------------------------------------------------------------- @pytest.fixture def has_ollama() -> bool: """Check if Ollama is running locally.""" try: import httpx resp = httpx.get("http://localhost:11434/api/tags", timeout=2.0) return resp.status_code == 200 except Exception: return False @pytest.fixture def has_vllm() -> bool: """Check if vLLM is running locally.""" try: import httpx resp = httpx.get("http://localhost:8000/v1/models", timeout=2.0) return resp.status_code == 200 except Exception: return False @pytest.fixture def has_llamacpp() -> bool: """Check if llama.cpp server is running locally.""" try: import httpx resp = httpx.get("http://localhost:8080/v1/models", timeout=2.0) return resp.status_code == 200 except Exception: return False # --------------------------------------------------------------------------- # Cloud API key fixtures # --------------------------------------------------------------------------- @pytest.fixture def has_openai_key() -> bool: """Check if OPENAI_API_KEY is set.""" return bool(os.environ.get("OPENAI_API_KEY")) @pytest.fixture def has_anthropic_key() -> bool: """Check if ANTHROPIC_API_KEY is set.""" return bool(os.environ.get("ANTHROPIC_API_KEY")) @pytest.fixture def has_gemini_key() -> bool: """Check if GEMINI_API_KEY or GOOGLE_API_KEY is set.""" return bool(os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")) # --------------------------------------------------------------------------- # Mock engine factory # --------------------------------------------------------------------------- @pytest.fixture def mock_engine(): """Factory for mock InferenceEngine instances.""" def _factory( engine_id: str = "mock", model_response: str = "Hello!", tool_calls: list | None = None, models: list[str] | None = None, ) -> MagicMock: engine = MagicMock() engine.engine_id = engine_id engine.health.return_value = True engine.list_models.return_value = models or ["test-model"] result = { "content": model_response, "usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}, "model": "test-model", "finish_reason": "stop", } if tool_calls: result["tool_calls"] = tool_calls result["finish_reason"] = "tool_calls" engine.generate.return_value = result return engine return _factory @pytest.fixture def event_bus() -> EventBus: """Fresh EventBus with history recording enabled.""" return EventBus(record_history=True)