246 lines
8.5 KiB
Python
246 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
E2E Test: Light Registration → Email Verification → KYC Completion
|
|
Verifies that all necessary database relationships are created after KYC.
|
|
"""
|
|
import asyncio
|
|
import httpx
|
|
import uuid
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
sys.path.insert(0, '/app')
|
|
|
|
from sqlalchemy import text
|
|
from app.db.session import AsyncSessionLocal
|
|
|
|
BASE_URL = "http://localhost:8000/api/v1"
|
|
TEST_EMAIL = f"test_kyc_{uuid.uuid4().hex[:8]}@example.com"
|
|
TEST_PASSWORD = "TestPass123!"
|
|
|
|
async def get_verification_token(email: str):
|
|
async with AsyncSessionLocal() as session:
|
|
result = await session.execute(
|
|
text("SELECT token FROM identity.verification_tokens vt "
|
|
"JOIN identity.users u ON u.id = vt.user_id "
|
|
"WHERE u.email = :email ORDER BY vt.created_at DESC LIMIT 1"),
|
|
{"email": email}
|
|
)
|
|
return result.scalar()
|
|
|
|
async def check_infrastructure(user_id: int):
|
|
"""Check all required infrastructure objects exist."""
|
|
async with AsyncSessionLocal() as session:
|
|
checks = {}
|
|
|
|
# Person
|
|
r = await session.execute(
|
|
text("SELECT id, is_active, user_id FROM identity.persons WHERE id = "
|
|
"(SELECT person_id FROM identity.users WHERE id = :uid)"),
|
|
{"uid": user_id}
|
|
)
|
|
person = r.fetchone()
|
|
checks["person"] = person is not None
|
|
if person:
|
|
checks["person_active"] = person[1] == True
|
|
checks["person_user_id"] = person[2] == user_id
|
|
|
|
# Organization
|
|
r = await session.execute(
|
|
text("SELECT id, name, org_type FROM fleet.organizations WHERE owner_id = :uid"),
|
|
{"uid": user_id}
|
|
)
|
|
org = r.fetchone()
|
|
checks["organization"] = org is not None
|
|
if org:
|
|
checks["org_id"] = org[0]
|
|
|
|
# Branch
|
|
if org:
|
|
r = await session.execute(
|
|
text("SELECT id, name, is_main FROM fleet.branches WHERE organization_id = :oid"),
|
|
{"oid": org[0]}
|
|
)
|
|
branch = r.fetchone()
|
|
checks["branch"] = branch is not None
|
|
if branch:
|
|
checks["branch_main"] = branch[2] == True
|
|
|
|
# OrganizationMember
|
|
r = await session.execute(
|
|
text("SELECT id, role FROM fleet.organization_members WHERE user_id = :uid"),
|
|
{"uid": user_id}
|
|
)
|
|
member = r.fetchone()
|
|
checks["org_member"] = member is not None
|
|
if member:
|
|
checks["org_member_role"] = member[1] == "OWNER"
|
|
|
|
# Wallet
|
|
r = await session.execute(
|
|
text("SELECT id FROM identity.wallets WHERE user_id = :uid"),
|
|
{"uid": user_id}
|
|
)
|
|
checks["wallet"] = r.fetchone() is not None
|
|
|
|
# UserStats
|
|
r = await session.execute(
|
|
text("SELECT user_id, total_xp, current_level FROM gamification.user_stats WHERE user_id = :uid"),
|
|
{"uid": user_id}
|
|
)
|
|
stats = r.fetchone()
|
|
checks["user_stats"] = stats is not None
|
|
if stats:
|
|
checks["user_stats_xp"] = stats[1] >= 500 # KYC bonus
|
|
checks["user_stats_level"] = stats[2] >= 1
|
|
|
|
# User scope_id
|
|
r = await session.execute(
|
|
text("SELECT scope_id FROM identity.users WHERE id = :uid"),
|
|
{"uid": user_id}
|
|
)
|
|
scope = r.fetchone()
|
|
checks["scope_id_set"] = scope is not None and scope[0] is not None
|
|
|
|
return checks
|
|
|
|
async def run_test():
|
|
passed = 0
|
|
failed = 0
|
|
|
|
print("=" * 60)
|
|
print(f"KYC E2E TEST - Email: {TEST_EMAIL}")
|
|
print("=" * 60)
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
# --- STEP 1: LITE REGISTRATION ---
|
|
print("\n--- 1. LITE REGISTRATION ---")
|
|
reg_payload = {
|
|
"email": TEST_EMAIL,
|
|
"password": TEST_PASSWORD,
|
|
"first_name": "KYC",
|
|
"last_name": "TestUser",
|
|
"region_code": "HU"
|
|
}
|
|
resp = await client.post(f"{BASE_URL}/auth/register", json=reg_payload)
|
|
print(f"Status: {resp.status_code}")
|
|
if resp.status_code == 201:
|
|
print("✓ Registration successful")
|
|
passed += 1
|
|
else:
|
|
print(f"✗ Registration failed: {resp.text}")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
# --- STEP 2: EMAIL VERIFICATION ---
|
|
print("\n--- 2. EMAIL VERIFICATION ---")
|
|
token = await get_verification_token(TEST_EMAIL)
|
|
if not token:
|
|
print("✗ No verification token found!")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
print(f"Token: {token}")
|
|
verify_resp = await client.post(f"{BASE_URL}/auth/verify-email", json={"token": str(token)})
|
|
print(f"Status: {verify_resp.status_code}")
|
|
if verify_resp.status_code == 200:
|
|
print("✓ Email verification successful")
|
|
passed += 1
|
|
else:
|
|
print(f"✗ Verification failed: {verify_resp.text}")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
# --- STEP 3: LOGIN TO GET TOKEN ---
|
|
print("\n--- 3. LOGIN ---")
|
|
login_data = {
|
|
"username": TEST_EMAIL,
|
|
"password": TEST_PASSWORD,
|
|
"grant_type": "password"
|
|
}
|
|
login_resp = await client.post(f"{BASE_URL}/auth/login", data=login_data)
|
|
print(f"Status: {login_resp.status_code}")
|
|
if login_resp.status_code == 200:
|
|
print("✓ Login successful")
|
|
passed += 1
|
|
access_token = login_resp.json().get("access_token")
|
|
else:
|
|
print(f"✗ Login failed: {login_resp.text}")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
headers = {"Authorization": f"Bearer {access_token}"}
|
|
|
|
# --- STEP 4: GET USER INFO ---
|
|
print("\n--- 4. GET USER INFO ---")
|
|
me_resp = await client.get(f"{BASE_URL}/auth/me", headers=headers)
|
|
print(f"Status: {me_resp.status_code}")
|
|
if me_resp.status_code == 200:
|
|
user_data = me_resp.json()
|
|
user_id = user_data.get("id")
|
|
print(f"User ID: {user_id}")
|
|
print(f"User data: {user_data}")
|
|
passed += 1
|
|
else:
|
|
print(f"✗ Failed to get user info: {me_resp.text}")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
# --- STEP 5: COMPLETE KYC ---
|
|
print("\n--- 5. COMPLETE KYC ---")
|
|
kyc_payload = {
|
|
"first_name": "KYC",
|
|
"last_name": "TestUser",
|
|
"birth_date": "1990-01-15",
|
|
"birth_place": "Budapest",
|
|
"mothers_last_name": "Anyuka",
|
|
"mothers_first_name": "Mária",
|
|
"phone_number": "+36301234567",
|
|
"address_zip": "1011",
|
|
"address_city": "Budapest",
|
|
"address_street_name": "Fő utca",
|
|
"address_street_type": "utca",
|
|
"address_house_number": "1",
|
|
"preferred_currency": "HUF",
|
|
"region_code": "HU",
|
|
"identity_docs": {
|
|
"PASSPORT": {"number": "AB123456", "expiry_date": "2030-01-01"}
|
|
}
|
|
}
|
|
kyc_resp = await client.post(f"{BASE_URL}/auth/complete-kyc", json=kyc_payload, headers=headers)
|
|
print(f"Status: {kyc_resp.status_code}")
|
|
print(f"Response: {kyc_resp.text}")
|
|
if kyc_resp.status_code == 200:
|
|
print("✓ KYC completion successful")
|
|
passed += 1
|
|
else:
|
|
print(f"✗ KYC failed: {kyc_resp.text}")
|
|
failed += 1
|
|
return passed, failed
|
|
|
|
# --- STEP 6: VERIFY INFRASTRUCTURE ---
|
|
print("\n--- 6. VERIFY INFRASTRUCTURE ---")
|
|
checks = await check_infrastructure(user_id)
|
|
all_ok = True
|
|
for check_name, check_result in checks.items():
|
|
status = "✓" if check_result else "✗"
|
|
if not check_result:
|
|
all_ok = False
|
|
print(f" {status} {check_name}: {check_result}")
|
|
|
|
if all_ok:
|
|
print("✓ All infrastructure checks passed!")
|
|
passed += 1
|
|
else:
|
|
print(f"✗ Some infrastructure checks failed!")
|
|
failed += 1
|
|
|
|
print("\n" + "=" * 60)
|
|
print(f"RESULTS: {passed} passed, {failed} failed")
|
|
print("=" * 60)
|
|
return passed, failed
|
|
|
|
if __name__ == "__main__":
|
|
p, f = asyncio.run(run_test())
|
|
sys.exit(1 if f > 0 else 0)
|