diff --git a/services/service-adapters/run_tests.py b/services/service-adapters/run_tests.py index de31e40..ae8879e 100644 --- a/services/service-adapters/run_tests.py +++ b/services/service-adapters/run_tests.py @@ -2,19 +2,19 @@ """ Test runner script for LabFusion Service Adapters """ +import os import subprocess import sys -import os def run_tests(): """Run the test suite""" print("🧪 Running LabFusion Service Adapters Tests") print("=" * 50) - + # Ensure test reports directory exists os.makedirs("tests/reports", exist_ok=True) - + # Run pytest with coverage cmd = [ "pytest", @@ -25,14 +25,14 @@ def run_tests(): "--cov-report=html", "--cov-report=xml", "--junitxml=tests/reports/junit.xml", - "--tb=short" + "--tb=short", ] - + print(f"Running: {' '.join(cmd)}") print() - + result = subprocess.run(cmd, cwd=os.path.dirname(__file__)) - + if result.returncode == 0: print("\n✅ All tests passed!") else: diff --git a/services/service-adapters/tests/conftest.py b/services/service-adapters/tests/conftest.py index c3a9cde..224149f 100644 --- a/services/service-adapters/tests/conftest.py +++ b/services/service-adapters/tests/conftest.py @@ -1,9 +1,11 @@ """ Pytest configuration and fixtures for service adapters tests """ + +from unittest.mock import patch + import pytest from fastapi.testclient import TestClient -from unittest.mock import patch from main import app @@ -21,17 +23,14 @@ def mock_services_config(): "home_assistant": { "enabled": True, "url": "http://homeassistant.local:8123", - "token": "test_token" - }, - "frigate": { - "enabled": True, - "url": "http://frigate.local:5000" + "token": "test_token", }, + "frigate": {"enabled": True, "url": "http://frigate.local:5000"}, "immich": { "enabled": False, "url": "http://immich.local:2283", - "api_key": "test_key" - } + "api_key": "test_key", + }, } @@ -42,18 +41,13 @@ def sample_ha_entities(): "sensor.temperature": { "entity_id": "sensor.temperature", "state": "22.5", - "attributes": { - "unit_of_measurement": "°C", - "friendly_name": "Temperature" - } + "attributes": {"unit_of_measurement": "°C", "friendly_name": "Temperature"}, }, "light.living_room": { "entity_id": "light.living_room", "state": "on", - "attributes": { - "friendly_name": "Living Room Light" - } - } + "attributes": {"friendly_name": "Living Room Light"}, + }, } @@ -67,15 +61,15 @@ def sample_frigate_events(): "timestamp": "2024-01-01T12:00:00Z", "camera": "front_door", "label": "person", - "confidence": 0.95 + "confidence": 0.95, }, { "id": "event_456", "timestamp": "2024-01-01T12:05:00Z", "camera": "back_yard", "label": "car", - "confidence": 0.87 - } + "confidence": 0.87, + }, ] } @@ -90,7 +84,7 @@ def sample_immich_assets(): "filename": "IMG_20240101_120000.jpg", "created_at": "2024-01-01T12:00:00Z", "tags": ["family", "vacation"], - "faces": ["person_1", "person_2"] + "faces": ["person_1", "person_2"], } ] } @@ -99,7 +93,7 @@ def sample_immich_assets(): @pytest.fixture(autouse=True) def mock_redis(): """Mock Redis client for all tests""" - with patch('services.redis_client.redis_client') as mock_redis: + with patch("services.redis_client.redis_client") as mock_redis: mock_redis.ping.return_value = True mock_redis.set.return_value = True mock_redis.get.return_value = None diff --git a/services/service-adapters/tests/test_general_routes.py b/services/service-adapters/tests/test_general_routes.py index 8bf6197..2ea42d2 100644 --- a/services/service-adapters/tests/test_general_routes.py +++ b/services/service-adapters/tests/test_general_routes.py @@ -1,10 +1,11 @@ """ Tests for general API routes """ -import pytest -from fastapi.testclient import TestClient + from unittest.mock import patch +from fastapi.testclient import TestClient + from main import app client = TestClient(app) @@ -17,7 +18,7 @@ class TestGeneralRoutes: """Test the root endpoint""" response = client.get("/") assert response.status_code == 200 - + data = response.json() assert data["message"] == "LabFusion Service Adapters API" assert data["version"] == "1.0.0" @@ -26,40 +27,34 @@ class TestGeneralRoutes: """Test the health check endpoint""" response = client.get("/health") assert response.status_code == 200 - + data = response.json() assert data["status"] == "healthy" assert "timestamp" in data # Verify timestamp is in ISO format assert "T" in data["timestamp"] or "Z" in data["timestamp"] - @patch('services.config.SERVICES') + @patch("services.config.SERVICES") def test_get_services(self, mock_services): """Test the get services endpoint""" # Mock the services configuration mock_services.items.return_value = [ - ("home_assistant", { - "enabled": True, - "url": "http://homeassistant.local:8123" - }), - ("frigate", { - "enabled": True, - "url": "http://frigate.local:5000" - }), - ("immich", { - "enabled": False, - "url": "http://immich.local:2283" - }) + ( + "home_assistant", + {"enabled": True, "url": "http://homeassistant.local:8123"}, + ), + ("frigate", {"enabled": True, "url": "http://frigate.local:5000"}), + ("immich", {"enabled": False, "url": "http://immich.local:2283"}), ] - + response = client.get("/services") assert response.status_code == 200 - + data = response.json() assert "home_assistant" in data assert "frigate" in data assert "immich" in data - + # Check service status structure ha_service = data["home_assistant"] assert ha_service["enabled"] is True @@ -70,7 +65,7 @@ class TestGeneralRoutes: """Test that health check returns proper response model""" response = client.get("/health") data = response.json() - + # Verify all required fields are present required_fields = ["status", "timestamp"] for field in required_fields: @@ -80,7 +75,7 @@ class TestGeneralRoutes: """Test that root endpoint returns proper response model""" response = client.get("/") data = response.json() - + # Verify all required fields are present required_fields = ["message", "version"] for field in required_fields: diff --git a/services/service-adapters/tests/test_home_assistant_routes.py b/services/service-adapters/tests/test_home_assistant_routes.py index 45132d4..65d0528 100644 --- a/services/service-adapters/tests/test_home_assistant_routes.py +++ b/services/service-adapters/tests/test_home_assistant_routes.py @@ -1,9 +1,10 @@ """ Tests for Home Assistant routes """ -import pytest + +from unittest.mock import AsyncMock, patch + from fastapi.testclient import TestClient -from unittest.mock import patch, AsyncMock from main import app @@ -13,7 +14,7 @@ client = TestClient(app) class TestHomeAssistantRoutes: """Test Home Assistant API routes""" - @patch('routes.home_assistant.httpx.AsyncClient') + @patch("routes.home_assistant.httpx.AsyncClient") async def test_get_entities_success(self, mock_client_class): """Test successful retrieval of Home Assistant entities""" # Mock the HTTP client response @@ -24,57 +25,57 @@ class TestHomeAssistantRoutes: "state": "22.5", "attributes": { "unit_of_measurement": "°C", - "friendly_name": "Temperature" - } + "friendly_name": "Temperature", + }, }, "light.living_room": { "entity_id": "light.living_room", "state": "on", - "attributes": { - "friendly_name": "Living Room Light" - } - } + "attributes": {"friendly_name": "Living Room Light"}, + }, } mock_response.status_code = 200 - + mock_client = AsyncMock() mock_client.get.return_value = mock_response mock_client_class.return_value.__aenter__.return_value = mock_client - + response = client.get("/home-assistant/entities") assert response.status_code == 200 - + data = response.json() assert "entities" in data assert len(data["entities"]) == 2 - + # Check first entity temp_entity = data["entities"][0] assert temp_entity["entity_id"] == "sensor.temperature" assert temp_entity["state"] == "22.5" assert temp_entity["attributes"]["unit_of_measurement"] == "°C" - @patch('routes.home_assistant.httpx.AsyncClient') + @patch("routes.home_assistant.httpx.AsyncClient") async def test_get_entities_api_error(self, mock_client_class): """Test handling of Home Assistant API errors""" # Mock HTTP error response mock_response = AsyncMock() mock_response.status_code = 500 mock_response.text = "Internal Server Error" - + mock_client = AsyncMock() mock_client.get.return_value = mock_response mock_client_class.return_value.__aenter__.return_value = mock_client - + response = client.get("/home-assistant/entities") assert response.status_code == 500 - @patch('routes.home_assistant.httpx.AsyncClient') + @patch("routes.home_assistant.httpx.AsyncClient") async def test_get_entities_connection_error(self, mock_client_class): """Test handling of connection errors""" # Mock connection error - mock_client_class.return_value.__aenter__.side_effect = Exception("Connection failed") - + mock_client_class.return_value.__aenter__.side_effect = Exception( + "Connection failed" + ) + response = client.get("/home-assistant/entities") assert response.status_code == 500 diff --git a/services/service-adapters/tests/test_main.py b/services/service-adapters/tests/test_main.py index e41be7f..834a4e8 100644 --- a/services/service-adapters/tests/test_main.py +++ b/services/service-adapters/tests/test_main.py @@ -1,7 +1,7 @@ """ Tests for the main FastAPI application """ -import pytest + from fastapi.testclient import TestClient from main import app @@ -30,12 +30,12 @@ class TestMainApp: """Test that all routers are included""" # Check that all expected routes are available routes = [route.path for route in app.routes] - + # General routes assert "/" in routes assert "/health" in routes assert "/services" in routes - + # Other service routes should be included # (exact paths depend on router definitions) @@ -43,7 +43,7 @@ class TestMainApp: """Test that OpenAPI documentation is available""" response = client.get("/docs") assert response.status_code == 200 - + response = client.get("/openapi.json") assert response.status_code == 200 assert "openapi" in response.json() diff --git a/services/service-adapters/tests/test_models.py b/services/service-adapters/tests/test_models.py index d3e98c9..0ab02e9 100644 --- a/services/service-adapters/tests/test_models.py +++ b/services/service-adapters/tests/test_models.py @@ -1,16 +1,13 @@ """ Tests for Pydantic models and schemas """ -import pytest -from datetime import datetime -from typing import Dict, Any -from models.schemas import ( - ServiceStatus, HAAttributes, HAEntity, HAEntitiesResponse, - FrigateEvent, FrigateEventsResponse, ImmichAsset, ImmichAssetsResponse, - EventData, EventResponse, Event, EventsResponse, - HealthResponse, RootResponse -) +from datetime import datetime + +import pytest + +from models.schemas import (EventData, FrigateEvent, HAAttributes, HAEntity, + HealthResponse, RootResponse, ServiceStatus) class TestServiceStatus: @@ -19,9 +16,7 @@ class TestServiceStatus: def test_service_status_creation(self): """Test creating a ServiceStatus instance""" service = ServiceStatus( - enabled=True, - url="http://example.com", - status="healthy" + enabled=True, url="http://example.com", status="healthy" ) assert service.enabled is True assert service.url == "http://example.com" @@ -31,9 +26,7 @@ class TestServiceStatus: """Test ServiceStatus validation""" # Valid data service = ServiceStatus( - enabled=False, - url="https://api.example.com", - status="unhealthy" + enabled=False, url="https://api.example.com", status="unhealthy" ) assert service.enabled is False @@ -49,8 +42,7 @@ class TestHAAttributes: def test_ha_attributes_creation(self): """Test creating HAAttributes instance""" attrs = HAAttributes( - unit_of_measurement="°C", - friendly_name="Living Room Temperature" + unit_of_measurement="°C", friendly_name="Living Room Temperature" ) assert attrs.unit_of_measurement == "°C" assert attrs.friendly_name == "Living Room Temperature" @@ -67,14 +59,9 @@ class TestHAEntity: def test_ha_entity_creation(self): """Test creating HAEntity instance""" - attributes = HAAttributes( - unit_of_measurement="°C", - friendly_name="Temperature" - ) + attributes = HAAttributes(unit_of_measurement="°C", friendly_name="Temperature") entity = HAEntity( - entity_id="sensor.temperature", - state="22.5", - attributes=attributes + entity_id="sensor.temperature", state="22.5", attributes=attributes ) assert entity.entity_id == "sensor.temperature" assert entity.state == "22.5" @@ -91,7 +78,7 @@ class TestFrigateEvent: timestamp="2024-01-01T12:00:00Z", camera="front_door", label="person", - confidence=0.95 + confidence=0.95, ) assert event.id == "event_123" assert event.camera == "front_door" @@ -106,7 +93,7 @@ class TestFrigateEvent: timestamp="2024-01-01T12:00:00Z", camera="front_door", label="person", - confidence=0.5 + confidence=0.5, ) assert event.confidence == 0.5 @@ -117,7 +104,7 @@ class TestFrigateEvent: timestamp="2024-01-01T12:00:00Z", camera="front_door", label="person", - confidence=1.5 + confidence=1.5, ) # Invalid confidence (negative) @@ -127,7 +114,7 @@ class TestFrigateEvent: timestamp="2024-01-01T12:00:00Z", camera="front_door", label="person", - confidence=-0.1 + confidence=-0.1, ) @@ -139,7 +126,7 @@ class TestEventData: event = EventData( service="home_assistant", event_type="state_changed", - metadata={"entity_id": "sensor.temperature", "new_state": "22.5"} + metadata={"entity_id": "sensor.temperature", "new_state": "22.5"}, ) assert event.service == "home_assistant" assert event.event_type == "state_changed" @@ -147,10 +134,7 @@ class TestEventData: def test_event_data_default_metadata(self): """Test default metadata is empty dict""" - event = EventData( - service="test_service", - event_type="test_event" - ) + event = EventData(service="test_service", event_type="test_event") assert event.metadata == {} @@ -160,10 +144,7 @@ class TestHealthResponse: def test_health_response_creation(self): """Test creating HealthResponse instance""" timestamp = datetime.now().isoformat() - health = HealthResponse( - status="healthy", - timestamp=timestamp - ) + health = HealthResponse(status="healthy", timestamp=timestamp) assert health.status == "healthy" assert health.timestamp == timestamp @@ -173,9 +154,6 @@ class TestRootResponse: def test_root_response_creation(self): """Test creating RootResponse instance""" - response = RootResponse( - message="Test API", - version="1.0.0" - ) + response = RootResponse(message="Test API", version="1.0.0") assert response.message == "Test API" assert response.version == "1.0.0"