Spaces:
Sleeping
Sleeping
| """ | |
| Test script for Tasks API endpoints. | |
| Tests both GET /tasks/today and PATCH /tasks/:id/status endpoints. | |
| """ | |
| import asyncio | |
| import asyncpg | |
| import os | |
| import requests | |
| import time | |
| from datetime import datetime, timedelta | |
| from dotenv import load_dotenv | |
| # Load environment variables | |
| load_dotenv() | |
| # Configuration | |
| API_BASE_URL = os.getenv("API_BASE_URL", "http://localhost:8003") | |
| DB_HOST = os.getenv("DB_HOST", "localhost") | |
| DB_PORT = int(os.getenv("DB_PORT", "5432")) | |
| DB_NAME = os.getenv("DB_NAME", "cuatrolabs") | |
| DB_USER = os.getenv("DB_USER", "postgres") | |
| DB_PASSWORD = os.getenv("DB_PASSWORD", "") | |
| # Test data | |
| TEST_MERCHANT_ID = "550e8400-e29b-41d4-a716-446655440000" | |
| TEST_EMPLOYEE_ID = "660e8400-e29b-41d4-a716-446655440001" | |
| def get_auth_token(): | |
| """Read JWT token from test_token.txt""" | |
| try: | |
| with open("test_token.txt", "r") as f: | |
| return f.read().strip() | |
| except FileNotFoundError: | |
| print("β test_token.txt not found. Run generate_test_token.py first.") | |
| exit(1) | |
| async def create_test_task(): | |
| """Create a test task in the database""" | |
| conn = await asyncpg.connect( | |
| host=DB_HOST, | |
| port=DB_PORT, | |
| database=DB_NAME, | |
| user=DB_USER, | |
| password=DB_PASSWORD | |
| ) | |
| try: | |
| # Delete existing test tasks | |
| await conn.execute(""" | |
| DELETE FROM trans.scm_tasks | |
| WHERE merchant_id = $1::uuid | |
| AND assigned_to = $2::uuid | |
| """, TEST_MERCHANT_ID, TEST_EMPLOYEE_ID) | |
| # Create new test task | |
| scheduled_time = datetime.now() + timedelta(hours=2) | |
| task_id = await conn.fetchval(""" | |
| INSERT INTO trans.scm_tasks ( | |
| merchant_id, assigned_to, title, description, | |
| status, latitude, longitude, address, scheduled_at | |
| ) VALUES ( | |
| $1::uuid, $2::uuid, $3, $4, $5, $6, $7, $8, $9 | |
| ) RETURNING id | |
| """, | |
| TEST_MERCHANT_ID, | |
| TEST_EMPLOYEE_ID, | |
| "Test Task - Visit Customer", | |
| "Deliver products and collect payment", | |
| "not_started", | |
| 19.0760, | |
| 72.8777, | |
| "123 Test Street, Mumbai", | |
| scheduled_time | |
| ) | |
| print(f"β Test task created: {task_id}") | |
| return str(task_id) | |
| finally: | |
| await conn.close() | |
| def test_get_today_tasks(token): | |
| """Test GET /tracker/tasks/today endpoint""" | |
| print("\n" + "="*80) | |
| print("TEST 1: GET /tracker/tasks/today") | |
| print("="*80) | |
| url = f"{API_BASE_URL}/tracker/tasks/today" | |
| headers = {"Authorization": f"Bearer {token}"} | |
| print(f"Request: GET {url}") | |
| response = requests.get(url, headers=headers) | |
| print(f"Status Code: {response.status_code}") | |
| print(f"Response: {response.json()}") | |
| if response.status_code == 200: | |
| data = response.json() | |
| if data.get("success") and data.get("count", 0) > 0: | |
| print("β Test passed: Tasks retrieved successfully") | |
| return data["tasks"][0]["id"] # Return first task ID for next tests | |
| else: | |
| print("β οΈ No tasks found for today") | |
| return None | |
| else: | |
| print("β Test failed") | |
| return None | |
| def test_update_task_status(token, task_id, new_status, should_succeed=True): | |
| """Test PATCH /tracker/tasks/:id/status endpoint""" | |
| print("\n" + "="*80) | |
| print(f"TEST: Update task status to '{new_status}'") | |
| print("="*80) | |
| url = f"{API_BASE_URL}/tracker/tasks/{task_id}/status" | |
| headers = { | |
| "Authorization": f"Bearer {token}", | |
| "Content-Type": "application/json" | |
| } | |
| payload = { | |
| "status": new_status, | |
| "timestamp": int(time.time() * 1000), # Current time in milliseconds | |
| "latitude": 19.0760 + (0.001 * hash(new_status) % 10), # Slightly different location | |
| "longitude": 72.8777 + (0.001 * hash(new_status) % 10) | |
| } | |
| print(f"Request: PATCH {url}") | |
| print(f"Payload: {payload}") | |
| response = requests.patch(url, headers=headers, json=payload) | |
| print(f"Status Code: {response.status_code}") | |
| print(f"Response: {response.json()}") | |
| if should_succeed: | |
| if response.status_code == 200: | |
| print(f"β Test passed: Status updated to '{new_status}'") | |
| return True | |
| else: | |
| print(f"β Test failed: Expected success but got {response.status_code}") | |
| return False | |
| else: | |
| if response.status_code in [400, 404]: | |
| print(f"β Test passed: Invalid transition correctly rejected") | |
| return True | |
| else: | |
| print(f"β Test failed: Expected error but got {response.status_code}") | |
| return False | |
| def test_invalid_task_id(token): | |
| """Test with invalid task ID""" | |
| print("\n" + "="*80) | |
| print("TEST: Invalid task ID (should return 404)") | |
| print("="*80) | |
| fake_task_id = "00000000-0000-0000-0000-000000000000" | |
| url = f"{API_BASE_URL}/tracker/tasks/{fake_task_id}/status" | |
| headers = { | |
| "Authorization": f"Bearer {token}", | |
| "Content-Type": "application/json" | |
| } | |
| payload = { | |
| "status": "in_progress", | |
| "timestamp": int(time.time() * 1000), | |
| "latitude": 19.0760, | |
| "longitude": 72.8777 | |
| } | |
| print(f"Request: PATCH {url}") | |
| response = requests.patch(url, headers=headers, json=payload) | |
| print(f"Status Code: {response.status_code}") | |
| print(f"Response: {response.json()}") | |
| if response.status_code == 404: | |
| print("β Test passed: Invalid task ID correctly rejected") | |
| return True | |
| else: | |
| print(f"β Test failed: Expected 404 but got {response.status_code}") | |
| return False | |
| async def main(): | |
| """Run all tests""" | |
| print("="*80) | |
| print("TASKS API TEST SUITE") | |
| print("="*80) | |
| print(f"API Base URL: {API_BASE_URL}") | |
| print(f"Database: {DB_HOST}:{DB_PORT}/{DB_NAME}") | |
| print("="*80) | |
| # Get auth token | |
| print("\n[1/9] Getting authentication token...") | |
| token = get_auth_token() | |
| print("β Token loaded") | |
| # Create test task | |
| print("\n[2/9] Creating test task...") | |
| task_id = await create_test_task() | |
| # Test 1: Get today's tasks | |
| print("\n[3/9] Testing GET /tracker/tasks/today...") | |
| retrieved_task_id = test_get_today_tasks(token) | |
| if not retrieved_task_id: | |
| print("\nβ Cannot continue tests without a task ID") | |
| return | |
| # Use the retrieved task ID for remaining tests | |
| task_id = retrieved_task_id | |
| # Test 2: Update to in_progress (valid transition) | |
| print("\n[4/9] Testing status update: not_started β in_progress...") | |
| test_update_task_status(token, task_id, "in_progress", should_succeed=True) | |
| # Test 3: Update to completed (valid transition) | |
| print("\n[5/9] Testing status update: in_progress β completed...") | |
| test_update_task_status(token, task_id, "completed", should_succeed=True) | |
| # Test 4: Reopen task (valid transition) | |
| print("\n[6/9] Testing status update: completed β in_progress...") | |
| test_update_task_status(token, task_id, "in_progress", should_succeed=True) | |
| # Test 5: Complete again (valid transition) | |
| print("\n[7/9] Testing status update: in_progress β completed...") | |
| test_update_task_status(token, task_id, "completed", should_succeed=True) | |
| # Test 6: Invalid transition (should fail) | |
| print("\n[8/9] Testing invalid transition: completed β not_started...") | |
| test_update_task_status(token, task_id, "not_started", should_succeed=False) | |
| # Test 7: Invalid task ID | |
| print("\n[9/9] Testing with invalid task ID...") | |
| test_invalid_task_id(token) | |
| # Summary | |
| print("\n" + "="*80) | |
| print("TEST SUITE COMPLETED") | |
| print("="*80) | |
| print("\nAll tests executed. Review results above.") | |
| print("\nTo verify in database:") | |
| print(f" SELECT * FROM trans.scm_tasks WHERE id = '{task_id}'::uuid;") | |
| print("="*80) | |
| if __name__ == "__main__": | |
| asyncio.run(main()) | |