#!/usr/bin/env python3 """ Test Asset Logic - Validates AssetCreate schema, dynamic defaults, and draft/active logic. This script must be run inside the sf_api container. """ import asyncio import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) from app.db.session import AsyncSessionLocal from app.schemas.asset import AssetCreate from app.services.config_service import config from datetime import datetime async def test_asset_create_schema(): """Test AssetCreate instantiation with various field combinations.""" print("=== Testing AssetCreate Schema ===") # Test 1: Minimal required fields (license_plate only) print("\n1. Minimal required fields (license_plate only):") try: asset = AssetCreate(license_plate="ABC-123") print(f" Success: license_plate={asset.license_plate}") print(f" vehicle_class={asset.vehicle_class}") print(f" status={asset.status}") print(f" brand={asset.brand}") except Exception as e: print(f" ❌ Error: {e}") # Test 2: With vehicle_class provided print("\n2. With vehicle_class provided:") try: asset = AssetCreate(license_plate="DEF-456", vehicle_class="SUV") print(f" Success: vehicle_class={asset.vehicle_class}") print(f" status={asset.status}") except Exception as e: print(f" ❌ Error: {e}") # Test 3: All core fields (should be active) print("\n3. All core fields (should be active):") try: asset = AssetCreate( license_plate="GHI-789", brand="Toyota", model="Corolla", vehicle_class="car", fuel_type="petrol" ) print(f" Success: status={asset.status}") print(f" brand={asset.brand}, model={asset.model}") print(f" vehicle_class={asset.vehicle_class}, fuel_type={asset.fuel_type}") except Exception as e: print(f" ❌ Error: {e}") # Test 4: Missing one core field (should be draft) print("\n4. Missing one core field (should be draft):") try: asset = AssetCreate( license_plate="JKL-012", brand="Toyota", model="Corolla", vehicle_class="car" # fuel_type missing ) print(f" Success: status={asset.status}") print(f" fuel_type={asset.fuel_type}") except Exception as e: print(f" ❌ Error: {e}") # Test 5: With catalog_id print("\n5. With catalog_id:") try: asset = AssetCreate( license_plate="MNO-345", catalog_id=123 ) print(f" Success: catalog_id={asset.catalog_id}") print(f" status={asset.status}") except Exception as e: print(f" ❌ Error: {e}") print("\n=== Schema tests completed ===\n") async def test_dynamic_default_vehicle_class(): """Test that vehicle_class default is fetched from config_service.""" print("=== Testing Dynamic Default Vehicle Class ===") async with AsyncSessionLocal() as db: # First, check if DEFAULT_VEHICLE_CLASS parameter exists default_class = await config.get_setting(db, "DEFAULT_VEHICLE_CLASS", default="car") print(f"1. DEFAULT_VEHICLE_CLASS from config: '{default_class}'") # Test 2: Create AssetCreate without vehicle_class, should not be hardcoded print("\n2. Creating AssetCreate without vehicle_class:") asset = AssetCreate(license_plate="TEST-001") print(f" vehicle_class from schema: {asset.vehicle_class}") print(f" Note: The schema doesn't set a default, so it's None.") print(f" The service layer should use config default when needed.") # Test 3: Verify config.get_setting works with different scopes org_default = await config.get_setting(db, "DEFAULT_VEHICLE_CLASS", default="car", org_id=1) print(f"\n3. DEFAULT_VEHICLE_CLASS with org_id=1: '{org_default}'") # Test 4: Insert a test parameter and retrieve it print("\n4. Testing parameter insertion and retrieval...") from app.models.system.system import SystemParameter, ParameterScope from sqlalchemy import select # Check if parameter exists stmt = select(SystemParameter).where( SystemParameter.key == "DEFAULT_VEHICLE_CLASS", SystemParameter.scope_level == ParameterScope.GLOBAL, SystemParameter.is_active == True ) result = await db.execute(stmt) param = result.scalar_one_or_none() if param: print(f" Parameter exists: {param.value}") else: print(f" Parameter does not exist, using default 'car'") print("\n=== Dynamic default tests completed ===\n") async def test_draft_vs_active_logic(): """Test the draft vs active status determination logic.""" print("=== Testing Draft vs Active Logic ===") test_cases = [ { "name": "All core fields", "fields": { "license_plate": "CORE-001", "brand": "Ford", "model": "Focus", "vehicle_class": "car", "fuel_type": "diesel" }, "expected_status": "active" }, { "name": "Missing brand", "fields": { "license_plate": "CORE-002", "model": "Focus", "vehicle_class": "car", "fuel_type": "diesel" }, "expected_status": "draft" }, { "name": "Empty string brand", "fields": { "license_plate": "CORE-003", "brand": "", "model": "Focus", "vehicle_class": "car", "fuel_type": "diesel" }, "expected_status": "draft" }, { "name": "Only license_plate", "fields": { "license_plate": "CORE-004" }, "expected_status": "draft" }, { "name": "With catalog_id but missing core fields", "fields": { "license_plate": "CORE-005", "catalog_id": 999 }, "expected_status": "draft" }, ] for tc in test_cases: print(f"\nTest: {tc['name']}") try: asset = AssetCreate(**tc['fields']) status = asset.status print(f" Fields: {list(tc['fields'].keys())}") print(f" Expected status: {tc['expected_status']}") print(f" Actual status: {status}") if status == tc['expected_status']: print(" ✅ PASS") else: print(" ❌ FAIL") except Exception as e: print(f" ❌ Error: {e}") print("\n=== Draft/Active tests completed ===\n") async def main(): """Run all tests.""" print("🚀 Starting Asset Logic Tests") print("=" * 50) try: await test_asset_create_schema() await test_dynamic_default_vehicle_class() await test_draft_vs_active_logic() print("=" * 50) print("✅ All tests completed successfully!") return 0 except Exception as e: print(f"❌ Critical error during tests: {e}") import traceback traceback.print_exc() return 1 if __name__ == "__main__": exit_code = asyncio.run(main()) sys.exit(exit_code)