""" Comprehensive API tests to improve coverage of main.py. """ import pytest from fastapi.testclient import TestClient from unittest.mock import patch, MagicMock import json @pytest.mark.api @pytest.mark.unit class TestTaskCRUDOperations: """Comprehensive CRUD tests for task endpoints.""" def test_list_tasks_empty(self, client: TestClient, auth_headers: dict): """Test listing tasks when none exist.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get("/tasks", headers=auth_headers) if response.status_code == 200: data = response.json() assert "tasks" in data assert data["count"] == 0 def test_list_tasks_with_filters(self, client: TestClient, auth_headers: dict): """Test listing tasks with enabled and service filters.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get( "/tasks?enabled=true&service=scheduler", headers=auth_headers ) # Should execute filtered query assert mock_cursor.execute.called call_args = str(mock_cursor.execute.call_args) assert "enabled" in call_args.lower() or response.status_code in [200, 500] def test_get_task_details_not_found(self, client: TestClient, auth_headers: dict): """Test getting details for non-existent task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = None mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get("/tasks/nonexistent", headers=auth_headers) assert response.status_code == 404 def test_update_task(self, client: TestClient, auth_headers: dict): """Test updating a task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = { "task_name": "test", "priority": 60 } mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.put( "/tasks/test", headers=auth_headers, json={"priority": 60} ) # Should have attempted update assert mock_cursor.execute.called def test_update_task_not_found(self, client: TestClient, auth_headers: dict): """Test updating non-existent task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = None mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.put( "/tasks/nonexistent", headers=auth_headers, json={"priority": 60} ) assert response.status_code == 404 def test_update_task_no_fields(self, client: TestClient, auth_headers: dict): """Test updating task with no valid fields.""" response = client.put( "/tasks/test", headers=auth_headers, json={"invalid_field": "value"} ) assert response.status_code == 400 def test_delete_task(self, client: TestClient, auth_headers: dict): """Test deleting a task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = ("test_task",) mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.delete("/tasks/test_task", headers=auth_headers) if response.status_code == 200: data = response.json() assert "deleted successfully" in data["message"].lower() def test_delete_task_not_found(self, client: TestClient, auth_headers: dict): """Test deleting non-existent task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = None mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.delete("/tasks/nonexistent", headers=auth_headers) assert response.status_code == 404 @pytest.mark.api @pytest.mark.unit class TestTriggerEndpoint: """Tests for task trigger endpoint.""" def test_trigger_disabled_task(self, client: TestClient, auth_headers: dict): """Test triggering a disabled task.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = { "task_name": "test", "enabled": False } mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.post("/tasks/test/trigger", headers=auth_headers) assert response.status_code == 400 def test_trigger_nonexistent_task(self, client: TestClient, auth_headers: dict): """Test triggering a task that doesn't exist.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchone.return_value = None mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.post("/tasks/nonexistent/trigger", headers=auth_headers) assert response.status_code == 404 @pytest.mark.api @pytest.mark.unit class TestLegacyEndpoints: """Tests for deprecated/legacy endpoints.""" def test_trigger_backup_endpoint(self, client: TestClient, auth_headers: dict): """Test legacy backup trigger endpoint.""" response = client.post("/tasks/backup", headers=auth_headers) # Should return not implemented status if response.status_code == 200: data = response.json() assert data["status"] == "not_implemented" def test_trigger_docs_update_endpoint(self, client: TestClient, auth_headers: dict): """Test legacy docs update endpoint.""" response = client.post("/tasks/docs/update", headers=auth_headers) if response.status_code == 200: data = response.json() assert data["status"] == "not_implemented" def test_trigger_docs_update_with_project(self, client: TestClient, auth_headers: dict): """Test legacy docs update with project filter.""" response = client.post( "/tasks/docs/update?project=test", headers=auth_headers ) if response.status_code == 200: data = response.json() assert "test" in data["message"].lower() def test_check_doc_versions_endpoint(self, client: TestClient, auth_headers: dict): """Test legacy version check endpoint.""" response = client.post("/tasks/docs/check-versions", headers=auth_headers) if response.status_code == 200: data = response.json() assert data["status"] == "not_implemented" def test_trigger_cleanup_endpoint(self, client: TestClient, auth_headers: dict): """Test legacy cleanup endpoint.""" response = client.post("/tasks/cleanup", headers=auth_headers) if response.status_code == 200: data = response.json() assert data["status"] == "not_implemented" @pytest.mark.api @pytest.mark.unit class TestExecutionFiltering: """Tests for execution history filtering.""" def test_filter_by_service(self, client: TestClient, auth_headers: dict): """Test filtering executions by service.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get( "/executions?service=scheduler", headers=auth_headers ) assert mock_cursor.execute.called def test_filter_by_status(self, client: TestClient, auth_headers: dict): """Test filtering executions by status.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get( "/executions?status=success", headers=auth_headers ) assert mock_cursor.execute.called def test_custom_limit(self, client: TestClient, auth_headers: dict): """Test custom limit for executions.""" with patch('src.main.get_task_executor') as mock_executor: mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=None) mock_executor.return_value.get_db_connection.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_executor.return_value.get_db_connection.return_value.__exit__ = MagicMock(return_value=None) response = client.get("/executions?limit=50", headers=auth_headers) if response.status_code == 200: data = response.json() assert data["limit"] == 50