""" Integration tests for API (api.php) """ import pytest import subprocess import time import requests from pathlib import Path @pytest.fixture(scope="module") def php_server(): """Start PHP development server for testing""" # Start PHP server on a test port port = 8888 env = {**subprocess.os.environ, 'DEV_MODE': 'true'} process = subprocess.Popen( ["php", "-S", f"localhost:{port}"], cwd=Path(__file__).parent.parent, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env ) # Wait for server to start time.sleep(2) # Check if server is running try: requests.get(f"http://localhost:{port}/", timeout=5) except requests.RequestException: process.terminate() pytest.skip("Could not start PHP server") yield f"http://localhost:{port}" # Cleanup process.terminate() time.sleep(1) class TestAPIAuthentication: """Test API authentication""" def test_api_rejects_no_auth(self, php_server): """Test that API handles requests without authentication""" response = requests.get(f"{php_server}/api.php") # In dev mode (DEV_MODE=true), auth is bypassed so we get 400 (invalid action) # In production mode, we would get 401 assert response.status_code in [400, 401] data = response.json() assert data['success'] is False assert 'error' in data def test_api_accepts_valid_key(self, php_server): """Test that API accepts requests with valid dev key""" headers = {'X-API-Key': 'dev_key_12345'} response = requests.get(f"{php_server}/api.php", headers=headers) # Should return 200 and different error (invalid action, not auth error) assert response.status_code != 401 data = response.json() # Should get past authentication if 'error' in data: assert 'Unauthorized' not in data['error'] assert 'API key' not in data['error'] def test_api_accepts_bearer_token(self, php_server): """Test that API accepts Bearer token authentication""" headers = {'Authorization': 'Bearer dev_key_12345'} response = requests.get(f"{php_server}/api.php", headers=headers) # Should get past authentication assert response.status_code != 401 class TestAuthModule: """Test authentication module directly""" def test_auth_key_generation(self, php_server): """Test API key generation endpoint""" response = requests.get(f"{php_server}/auth.php?generate") assert response.status_code == 200 text = response.text # Should contain a generated key assert len(text) > 50 # Keys are 64 chars hex assert 'API Key' in text or 'New' in text def test_auth_test_endpoint(self, php_server): """Test authentication test endpoint""" headers = {'X-API-Key': 'dev_key_12345'} response = requests.get(f"{php_server}/auth.php?test", headers=headers) assert response.status_code == 200 text = response.text # Should indicate successful authentication assert '✅' in text or 'successful' in text.lower() class TestAPIEndpoints: """Test API endpoint structure""" def test_api_returns_json(self, php_server): """Test that API returns JSON""" headers = {'X-API-Key': 'dev_key_12345'} response = requests.get(f"{php_server}/api.php", headers=headers) assert response.headers.get('Content-Type') == 'application/json' # Should be valid JSON try: data = response.json() assert isinstance(data, dict) except ValueError: pytest.fail("API did not return valid JSON") def test_cors_headers_present(self, php_server): """Test that CORS headers are present""" headers = {'X-API-Key': 'dev_key_12345'} response = requests.get(f"{php_server}/api.php", headers=headers) assert 'Access-Control-Allow-Origin' in response.headers # CORS now returns specific origin or localhost in dev mode origin = response.headers['Access-Control-Allow-Origin'] assert origin in ['*', 'http://localhost:8888', 'http://localhost:8000', 'null'] def test_api_handles_options(self, php_server): """Test that API handles OPTIONS preflight requests""" response = requests.options(f"{php_server}/api.php") # OPTIONS should not require authentication assert response.status_code == 200 or response.status_code == 204 class TestHelperModules: """Test helper modules""" def test_logger_config_import(self): """Test logger_config module""" from logger_config import setup_logger logger = setup_logger("test", "test_api.log") assert logger is not None # Test logging logger.info("Test message from API tests") def test_retry_helper_import(self): """Test retry_helper module""" from retry_helper import retry_with_backoff, safe_execute assert callable(retry_with_backoff) assert callable(safe_execute) def test_retry_decorator_works(self): """Test that retry decorator functions""" from retry_helper import retry_with_backoff @retry_with_backoff(max_retries=2, initial_delay=0.1) def always_succeeds(): return "success" result = always_succeeds() assert result == "success" @pytest.mark.skipif( not Path("Test_files/sample_good.pdf").exists(), reason="Sample PDF not available" ) class TestAPIWithFile: """Test API with actual file upload (if samples available)""" def test_api_file_structure_exists(self): """Test that test files exist""" assert Path("Test_files").exists() assert Path("Test_files").is_dir() if __name__ == "__main__": pytest.main([__file__, "-v"])