"""Integration tests for PM3 API endpoints. Tests the refactored PM3 API endpoints to ensure: - Proper integration with PM3Service - Correct HTTP status codes for different error types - Request/response format consistency - Session management integration """ import pytest from fastapi.testclient import TestClient from unittest.mock import patch, AsyncMock, Mock from app.backend.services.pm3_service import PM3ServiceResult, PM3ServiceError class TestPM3APIStatus: """Test /api/pm3/status endpoint.""" def test_get_status_success(self, test_client, mock_pm3_service): """Test successful status retrieval.""" # Arrange mock_pm3_service.get_status.return_value = PM3ServiceResult( success=True, data={ "connected": True, "device_path": "/dev/ttyACM0", "version": "Proxmark3 v4.0", "session_active": False } ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.get("/api/pm3/status") # Assert assert response.status_code == 200 data = response.json() assert data["connected"] is True assert data["device"] == "/dev/ttyACM0" assert "Proxmark3" in data["version"] def test_get_status_error(self, test_client, mock_pm3_service): """Test status retrieval with error.""" # Arrange mock_pm3_service.get_status.return_value = PM3ServiceResult( success=False, error=PM3ServiceError( code="status_error", message="Failed to query status" ) ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.get("/api/pm3/status") # Assert assert response.status_code == 500 assert "Failed to query status" in response.json()["detail"] class TestPM3APICommand: """Test /api/pm3/command endpoint.""" def test_execute_command_success(self, test_client, mock_pm3_service): """Test successful command execution.""" # Arrange mock_pm3_service.execute_command.return_value = PM3ServiceResult( success=True, data={ "output": "Proxmark3 RFID instrument", "command": "hw version", "session_id": "test-session" } ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post( "/api/pm3/command", json={"command": "hw version", "session_id": "test-session"} ) # Assert assert response.status_code == 200 data = response.json() assert data["success"] is True assert "Proxmark3" in data["output"] assert data["error"] is None def test_execute_command_session_locked(self, test_client, mock_pm3_service): """Test command execution with session locked.""" # Arrange mock_pm3_service.execute_command.return_value = PM3ServiceResult( success=False, error=PM3ServiceError( code="session_locked", message="Another session is active" ) ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post( "/api/pm3/command", json={"command": "hw version", "session_id": "test-session"} ) # Assert assert response.status_code == 423 # Locked assert "Another session is active" in response.json()["detail"] def test_execute_command_pm3_not_connected(self, test_client, mock_pm3_service): """Test command execution when PM3 not connected.""" # Arrange mock_pm3_service.execute_command.return_value = PM3ServiceResult( success=False, error=PM3ServiceError( code="pm3_not_connected", message="Proxmark3 not connected" ) ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post( "/api/pm3/command", json={"command": "hw version"} ) # Assert assert response.status_code == 200 # Returns in body, not HTTP error data = response.json() assert data["success"] is False assert "not connected" in data["error"].lower() class TestPM3APIConnection: """Test PM3 connection endpoints.""" def test_connect_success(self, test_client, mock_pm3_service): """Test successful PM3 connection.""" # Arrange mock_pm3_service.connect.return_value = PM3ServiceResult( success=True, data={"message": "Connected to Proxmark3"} ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post("/api/pm3/connect") # Assert assert response.status_code == 200 assert response.json()["success"] is True def test_connect_failure(self, test_client, mock_pm3_service): """Test PM3 connection failure.""" # Arrange mock_pm3_service.connect.return_value = PM3ServiceResult( success=False, error=PM3ServiceError( code="connection_error", message="Device not found" ) ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post("/api/pm3/connect") # Assert assert response.status_code == 503 assert "Device not found" in response.json()["detail"] def test_disconnect_success(self, test_client, mock_pm3_service): """Test successful PM3 disconnection.""" # Arrange mock_pm3_service.disconnect.return_value = PM3ServiceResult( success=True, data={"message": "Disconnected from Proxmark3"} ) # Act with patch('app.backend.api.pm3.container') as mock_container: mock_container.pm3_service = mock_pm3_service response = test_client.post("/api/pm3/disconnect") # Assert assert response.status_code == 200 assert response.json()["success"] is True