#!/usr/bin/env python3 """ Authenticated E2E test for vehicle registration endpoint. Reads credentials from backend/tests/test_credentials.json, authenticates via /api/v1/auth/login, obtains JWT token, and tests POST /api/v1/assets/vehicles endpoint. """ import json import sys import os import asyncio import aiohttp import logging from typing import Dict, Any # Add parent directory to path to import app modules if needed sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) CREDENTIALS_PATH = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "tests", "test_credentials.json" ) async def load_credentials() -> Dict[str, Any]: """Load test credentials from JSON file.""" try: with open(CREDENTIALS_PATH, 'r') as f: creds = json.load(f) logger.info(f"Loaded credentials for {creds.get('email')}") return creds except FileNotFoundError: logger.error(f"Credentials file not found at {CREDENTIALS_PATH}") sys.exit(1) except json.JSONDecodeError as e: logger.error(f"Invalid JSON in credentials file: {e}") sys.exit(1) async def authenticate(session: aiohttp.ClientSession, base_url: str, email: str, password: str) -> str: """Authenticate and return JWT token.""" login_url = f"{base_url}/api/v1/auth/login" # Use form data as required by OAuth2PasswordRequestForm form_data = aiohttp.FormData() form_data.add_field('username', email) form_data.add_field('password', password) try: async with session.post(login_url, data=form_data) as resp: if resp.status != 200: text = await resp.text() logger.error(f"Authentication failed: {resp.status} - {text}") raise ValueError(f"Authentication failed: {resp.status}") data = await resp.json() token = data.get("access_token") if not token: logger.error(f"No access_token in response: {data}") raise ValueError("No access_token in response") logger.info("Authentication successful") return token except aiohttp.ClientError as e: logger.error(f"Network error during authentication: {e}") raise async def test_vehicle_creation(session: aiohttp.ClientSession, base_url: str, token: str): """Test POST /api/v1/assets/vehicles endpoint.""" url = f"{base_url}/api/v1/assets/vehicles" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } # Realistic payload with valid catalog_id and required fields payload = { "vin": "TESTVIN1234567890", "license_plate": "TEST-001", "catalog_id": 5, # Valid catalog_id from database "brand": "BMW", "model": "X5", "vehicle_class": "car", "fuel_type": "petrol", "engine_capacity": 3000, "power_kw": 200, "transmission_type": "automatic", "drive_type": "awd" } logger.info(f"Testing vehicle creation with payload: {payload}") try: async with session.post(url, json=payload, headers=headers) as resp: status = resp.status text = await resp.text() logger.info(f"Response status: {status}") logger.info(f"Response body: {text}") if status == 201: logger.info("✅ Vehicle creation test PASSED") return True elif status == 404: logger.error("❌ Endpoint not found (404). Check API route.") return False elif status == 400: logger.warning("⚠️ Bad request (400). Might be due to missing catalog_id or validation.") # Try to parse error details try: error_data = json.loads(text) logger.warning(f"Error details: {error_data}") except: pass return False elif status == 500: logger.error("❌ Internal server error (500). Check server logs.") # Try to parse error details try: error_data = json.loads(text) logger.error(f"Error details: {error_data}") except: pass return False else: logger.error(f"❌ Unexpected status: {status}") return False except aiohttp.ClientError as e: logger.error(f"Network error during vehicle creation: {e}") return False async def main(): """Main test execution.""" logger.info("Starting authenticated E2E test for vehicle registration") # Load credentials creds = await load_credentials() base_url = creds.get("base_url", "http://localhost:8000") email = creds["email"] password = creds["password"] # Create aiohttp session async with aiohttp.ClientSession() as session: # Authenticate try: token = await authenticate(session, base_url, email, password) except Exception as e: logger.error(f"Authentication failed: {e}") sys.exit(1) # Test vehicle creation success = await test_vehicle_creation(session, base_url, token) if success: logger.info("🎉 All tests passed!") sys.exit(0) else: logger.error("💥 Test failed!") sys.exit(1) if __name__ == "__main__": asyncio.run(main())