cosmo/backend/test_phase5.py

308 lines
12 KiB
Python

"""
Test script for Phase 5 features
Tests social features (follows, channel messages) and event system
"""
import asyncio
import httpx
import json
from datetime import datetime
BASE_URL = "http://localhost:8000/api"
# Test user credentials (assuming these exist from previous tests)
TEST_USER = {
"username": "testuser",
"password": "testpass123"
}
async def get_auth_token():
"""Login and get JWT token"""
async with httpx.AsyncClient(timeout=30.0, proxies={}) as client:
# Try to register first (in case user doesn't exist)
register_response = await client.post(
f"{BASE_URL}/auth/register",
json={
"username": TEST_USER["username"],
"password": TEST_USER["password"],
"email": "test@example.com"
}
)
# If register fails (user exists), try to login
if register_response.status_code != 200:
response = await client.post(
f"{BASE_URL}/auth/login",
json={
"username": TEST_USER["username"],
"password": TEST_USER["password"]
}
)
else:
response = register_response
if response.status_code == 200:
data = response.json()
return data.get("access_token")
else:
print(f"Login failed: {response.status_code} - {response.text}")
return None
async def test_follow_operations(token):
"""Test user follow operations"""
print("\n=== Testing Follow Operations ===")
headers = {"Authorization": f"Bearer {token}"}
async with httpx.AsyncClient(timeout=30.0, proxies={}) as client:
# Test: Follow a celestial body (Mars)
print("\n1. Following Mars (499)...")
response = await client.post(
f"{BASE_URL}/social/follow/499",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code in [200, 400]: # 400 if already following
print(f"Response: {response.json()}")
# Test: Get user's follows
print("\n2. Getting user follows...")
response = await client.get(
f"{BASE_URL}/social/follows",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
follows = response.json()
print(f"Following {len(follows)} bodies:")
for follow in follows[:5]: # Show first 5
print(f" - Body ID: {follow['body_id']}, Since: {follow['created_at']}")
# Test: Check if following Mars
print("\n3. Checking if following Mars...")
response = await client.get(
f"{BASE_URL}/social/follows/check/499",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
print(f"Response: {response.json()}")
return response.status_code == 200
async def test_channel_messages(token):
"""Test channel message operations"""
print("\n=== Testing Channel Messages ===")
headers = {"Authorization": f"Bearer {token}"}
async with httpx.AsyncClient(timeout=30.0, proxies={}) as client:
# Test: Post a message to Mars channel
print("\n1. Posting message to Mars channel...")
message_data = {
"content": f"Test message at {datetime.now().isoformat()}"
}
response = await client.post(
f"{BASE_URL}/social/channel/499/message",
headers=headers,
json=message_data
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
print(f"Response: {response.json()}")
elif response.status_code == 403:
print("Error: User is not following this body (need to follow first)")
# Test: Get channel messages
print("\n2. Getting Mars channel messages...")
response = await client.get(
f"{BASE_URL}/social/channel/499/messages?limit=10",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
messages = response.json()
print(f"Found {len(messages)} messages:")
for msg in messages[-3:]: # Show last 3
print(f" - {msg['username']}: {msg['content'][:50]}...")
return response.status_code == 200
async def test_celestial_events(token):
"""Test celestial event operations"""
print("\n=== Testing Celestial Events ===")
headers = {"Authorization": f"Bearer {token}"}
async with httpx.AsyncClient(timeout=30.0, proxies={}) as client:
# Test: Get upcoming events
print("\n1. Getting upcoming celestial events...")
response = await client.get(
f"{BASE_URL}/events?limit=10",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
events = response.json()
print(f"Found {len(events)} events:")
for event in events[:5]: # Show first 5
print(f" - {event['title']} at {event['event_time']}")
print(f" Type: {event['event_type']}, Source: {event['source']}")
# Test: Get events for a specific body
print("\n2. Getting events for Mars (499)...")
response = await client.get(
f"{BASE_URL}/events?body_id=499&limit=5",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
events = response.json()
print(f"Found {len(events)} events for Mars")
return response.status_code == 200
async def test_scheduled_tasks(token):
"""Test scheduled task functionality"""
print("\n=== Testing Scheduled Tasks ===")
headers = {"Authorization": f"Bearer {token}"}
async with httpx.AsyncClient(timeout=120.0, proxies={}) as client:
# Test: Get available tasks
print("\n1. Getting available scheduled tasks...")
response = await client.get(
f"{BASE_URL}/scheduled-jobs/available-tasks",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
tasks = response.json()
print(f"Found {len(tasks)} available tasks")
# Find our Phase 5 task
phase5_task = None
for task in tasks:
if task['name'] == 'fetch_close_approach_events':
phase5_task = task
print(f"\nFound Phase 5 task: {task['name']}")
print(f" Description: {task['description']}")
print(f" Category: {task['category']}")
break
if phase5_task:
# Test: Create a scheduled job for this task
print("\n2. Creating a scheduled job for fetch_close_approach_events...")
job_data = {
"name": "Test Phase 5 Close Approach Events",
"job_type": "predefined",
"predefined_function": "fetch_close_approach_events",
"function_params": {
"days_ahead": 30,
"dist_max": "0.2",
"approach_body": "Earth",
"limit": 50,
"clean_old_events": False
},
"cron_expression": "0 0 * * *", # Daily at midnight
"description": "Test job for Phase 5",
"is_active": False # Don't activate for test
}
response = await client.post(
f"{BASE_URL}/scheduled-jobs",
headers=headers,
json=job_data
)
print(f"Status: {response.status_code}")
if response.status_code == 201:
job = response.json()
job_id = job['id']
print(f"Created job with ID: {job_id}")
# Test: Run the job immediately
print(f"\n3. Triggering job {job_id} to run now...")
print(" (This may take 30-60 seconds...)")
response = await client.post(
f"{BASE_URL}/scheduled-jobs/{job_id}/run",
headers=headers
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
print(f"Response: {response.json()}")
# Wait a bit and check job status
print("\n4. Waiting 60 seconds for job to complete...")
await asyncio.sleep(60)
# Get job status
response = await client.get(
f"{BASE_URL}/scheduled-jobs/{job_id}",
headers=headers
)
if response.status_code == 200:
job_status = response.json()
print(f"Job status: {job_status.get('last_run_status')}")
print(f"Last run at: {job_status.get('last_run_at')}")
# Check if events were created
response = await client.get(
f"{BASE_URL}/events?limit=10",
headers=headers
)
if response.status_code == 200:
events = response.json()
print(f"\nEvents in database: {len(events)}")
for event in events[:3]:
print(f" - {event['title']}")
# Clean up: delete the test job
await client.delete(
f"{BASE_URL}/scheduled-jobs/{job_id}",
headers=headers
)
print(f"\nCleaned up test job {job_id}")
return True
else:
print(f"Error triggering job: {response.text}")
else:
print(f"Error creating job: {response.text}")
return False
async def main():
"""Main test function"""
print("=" * 60)
print("Phase 5 Feature Testing")
print("=" * 60)
# Get authentication token
print("\nAuthenticating...")
token = await get_auth_token()
if not token:
print("ERROR: Failed to authenticate. Please ensure test user exists.")
print("You may need to create a test user first.")
return
print(f"✓ Authentication successful")
# Run tests
results = {
"follow_operations": await test_follow_operations(token),
"channel_messages": await test_channel_messages(token),
"celestial_events": await test_celestial_events(token),
"scheduled_tasks": await test_scheduled_tasks(token)
}
# Summary
print("\n" + "=" * 60)
print("Test Summary")
print("=" * 60)
for test_name, passed in results.items():
status = "✓ PASS" if passed else "✗ FAIL"
print(f"{status} - {test_name}")
total_passed = sum(results.values())
total_tests = len(results)
print(f"\nTotal: {total_passed}/{total_tests} tests passed")
if __name__ == "__main__":
asyncio.run(main())