#!/usr/bin/env python3 """ E2E Smoke Test for Registration Flow Performs a complete "Blind Test" of the registration-to-activation flow. """ import asyncio import uuid import httpx import json import time from datetime import datetime from typing import Dict, Any, Optional import sys # Configuration API_BASE_URL = "http://sf_api:8000/api/v1" MAILPIT_API = "http://sf_mailpit:8025/api/v1" def generate_unique_email() -> str: """Generate a unique email for testing.""" timestamp = int(time.time()) random_id = uuid.uuid4().hex[:8] return f"test_{timestamp}_{random_id}@example.com" async def call_registration(email: str) -> Dict[str, Any]: """Call the registration API endpoint.""" async with httpx.AsyncClient(timeout=30.0) as client: payload = { "email": email, "password": "TestPassword123!", "first_name": "Test", "last_name": "User", "region_code": "HU", "lang": "hu" } print(f"šŸ“ Registering user with email: {email}") response = await client.post(f"{API_BASE_URL}/auth/register", json=payload) if response.status_code != 201: print(f"āŒ Registration failed: {response.status_code}") print(f"Response: {response.text}") return {"success": False, "error": f"HTTP {response.status_code}"} data = response.json() print(f"āœ… Registration successful: {data.get('message')}") print(f" User ID: {data.get('user_id')}") return {"success": True, "data": data} async def get_verification_token_from_db(email: str) -> Optional[str]: """Get verification token directly from the database.""" import os import asyncpg # Database connection parameters from environment db_host = os.getenv("DB_HOST", "shared-postgres") db_name = os.getenv("DB_NAME", "service_finder") db_user = os.getenv("DB_USER", "service_finder_app") db_password = os.getenv("DB_PASSWORD", "JELSZAVAD") try: # Connect to database conn = await asyncpg.connect( host=db_host, database=db_name, user=db_user, password=db_password ) # Get user ID from email user_row = await conn.fetchrow( "SELECT id FROM identity.users WHERE email = $1", email ) if not user_row: print(f"āŒ User not found in database for email: {email}") return None user_id = user_row['id'] # Get verification token token_row = await conn.fetchrow( """SELECT token FROM identity.verification_tokens WHERE user_id = $1 AND token_type = 'registration' ORDER BY created_at DESC LIMIT 1""", user_id ) await conn.close() if token_row: token = str(token_row['token']) print(f"šŸ”‘ Found verification token in DB: {token[:8]}...") return token else: print("āŒ No verification token found in database") return None except Exception as e: print(f"āŒ Database error: {e}") return None async def get_verification_token_from_mailpit(email: str) -> Optional[str]: """Try to get verification token from Mailpit API.""" try: async with httpx.AsyncClient(timeout=10.0) as client: # Get latest messages response = await client.get(f"{MAILPIT_API}/messages") if response.status_code != 200: print(f"āŒ Mailpit API error: {response.status_code}") return None messages = response.json().get('messages', []) # Find message sent to our test email for msg in messages: if msg.get('To', [{}])[0].get('Address') == email: msg_id = msg['ID'] # Get message details msg_response = await client.get(f"{MAILPIT_API}/message/{msg_id}") if msg_response.status_code == 200: msg_data = msg_response.json() html = msg_data.get('HTML', '') # Extract token from HTML (look for token= parameter) import re token_match = re.search(r'token=([a-f0-9\-]+)', html) if token_match: token = token_match.group(1) print(f"šŸ“§ Found verification token in email: {token[:8]}...") return token # Also check text body text = msg_data.get('Text', '') token_match = re.search(r'token=([a-f0-9\-]+)', text) if token_match: token = token_match.group(1) print(f"šŸ“§ Found verification token in email text: {token[:8]}...") return token print("āŒ No email found in Mailpit for the test address") return None except Exception as e: print(f"āŒ Mailpit error: {e}") return None async def verify_email(token: str) -> bool: """Call the verify-email endpoint.""" async with httpx.AsyncClient(timeout=30.0) as client: payload = {"token": token} print(f"šŸ” Verifying email with token: {token[:8]}...") response = await client.post(f"{API_BASE_URL}/auth/verify-email", json=payload) if response.status_code != 200: print(f"āŒ Email verification failed: {response.status_code}") print(f"Response: {response.text}") return False data = response.json() print(f"āœ… Email verification successful: {data.get('message')}") return True async def check_user_activated(email: str) -> bool: """Check if user is activated in database.""" import os import asyncpg db_host = os.getenv("DB_HOST", "shared-postgres") db_name = os.getenv("DB_NAME", "service_finder") db_user = os.getenv("DB_USER", "service_finder_app") db_password = os.getenv("DB_PASSWORD", "JELSZAVAD") try: conn = await asyncpg.connect( host=db_host, database=db_name, user=db_user, password=db_password ) user_row = await conn.fetchrow( "SELECT is_active FROM identity.users WHERE email = $1", email ) await conn.close() if user_row: is_active = user_row['is_active'] print(f"šŸ‘¤ User activation status: {'ACTIVE' if is_active else 'INACTIVE'}") return is_active else: print("āŒ User not found when checking activation") return False except Exception as e: print(f"āŒ Database error checking activation: {e}") return False async def main(): """Main test execution.""" print("=" * 60) print("šŸš€ Service Finder Registration E2E Smoke Test") print("=" * 60) # Generate unique test email test_email = generate_unique_email() print(f"šŸ“§ Test email: {test_email}") # Step 1: Register user print("\n1ļøāƒ£ Step 1: Registration") reg_result = await call_registration(test_email) if not reg_result["success"]: print("āŒ TEST FAILED: Registration failed") return False # Wait a moment for email to be sent print("\nā³ Waiting 3 seconds for email processing...") await asyncio.sleep(3) # Step 2: Get verification token print("\n2ļøāƒ£ Step 2: Token Retrieval") # Try database first (more reliable) token = await get_verification_token_from_db(test_email) # If not found in DB, try Mailpit if not token: print("āš ļø Token not found in DB, trying Mailpit...") token = await get_verification_token_from_mailpit(test_email) if not token: print("āŒ TEST FAILED: Could not retrieve verification token") return False # Step 3: Verify email print("\n3ļøāƒ£ Step 3: Email Verification") verify_success = await verify_email(token) if not verify_success: print("āŒ TEST FAILED: Email verification failed") return False # Step 4: Check user activation print("\n4ļøāƒ£ Step 4: Activation Verification") await asyncio.sleep(2) # Give DB time to update is_active = await check_user_activated(test_email) if not is_active: print("āŒ TEST FAILED: User not activated after verification") return False # Final report print("\n" + "=" * 60) print("āœ… TEST PASSED: Registration-to-Activation flow is 100% OK") print("=" * 60) print(f"Summary:") print(f" • Test email: {test_email}") print(f" • Registration: āœ… Success") print(f" • Token retrieval: āœ… Success") print(f" • Email verification: āœ… Success") print(f" • User activation: āœ… Success") print("=" * 60) return True if __name__ == "__main__": # Install asyncpg if needed try: import asyncpg except ImportError: print("āš ļø asyncpg not installed. Installing...") import subprocess subprocess.check_call([sys.executable, "-m", "pip", "install", "asyncpg"]) import asyncpg # Run the test success = asyncio.run(main()) sys.exit(0 if success else 1)