308 lines
12 KiB
Python
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())
|