Files
bakery-ia/scripts/test/demo_determinism.py
2025-12-13 23:57:54 +01:00

111 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""
Test deterministic cloning by creating multiple sessions and comparing data hashes.
"""
import asyncio
import hashlib
import json
from typing import List, Dict
import httpx
DEMO_API_URL = "http://localhost:8018"
INTERNAL_API_KEY = "test-internal-key"
async def create_demo_session(tier: str = "professional") -> dict:
"""Create a demo session"""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{DEMO_API_URL}/api/demo/sessions",
json={"demo_account_type": tier}
)
return response.json()
async def get_all_data_from_service(
service_url: str,
tenant_id: str
) -> dict:
"""Fetch all data for a tenant from a service"""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{service_url}/internal/demo/export/{tenant_id}",
headers={"X-Internal-API-Key": INTERNAL_API_KEY}
)
return response.json()
def calculate_data_hash(data: dict) -> str:
"""
Calculate SHA-256 hash of data, excluding audit timestamps.
"""
# Remove non-deterministic fields
clean_data = remove_audit_fields(data)
# Sort keys for consistency
json_str = json.dumps(clean_data, sort_keys=True)
return hashlib.sha256(json_str.encode()).hexdigest()
def remove_audit_fields(data: dict) -> dict:
"""Remove created_at, updated_at fields recursively"""
if isinstance(data, dict):
return {
k: remove_audit_fields(v)
for k, v in data.items()
if k not in ["created_at", "updated_at", "id"] # IDs are UUIDs
}
elif isinstance(data, list):
return [remove_audit_fields(item) for item in data]
else:
return data
async def test_determinism(tier: str = "professional", iterations: int = 10):
"""
Test that cloning is deterministic across multiple sessions.
"""
print(f"Testing determinism for {tier} tier ({iterations} iterations)...")
services = [
("inventory", "http://inventory-service:8002"),
("production", "http://production-service:8003"),
("recipes", "http://recipes-service:8004"),
]
hashes_by_service = {svc[0]: [] for svc in services}
for i in range(iterations):
# Create session
session = await create_demo_session(tier)
tenant_id = session["virtual_tenant_id"]
# Get data from each service
for service_name, service_url in services:
data = await get_all_data_from_service(service_url, tenant_id)
data_hash = calculate_data_hash(data)
hashes_by_service[service_name].append(data_hash)
# Cleanup
async with httpx.AsyncClient() as client:
await client.delete(f"{DEMO_API_URL}/api/demo/sessions/{session['session_id']}")
if (i + 1) % 10 == 0:
print(f" Completed {i + 1}/{iterations} iterations")
# Check consistency
all_consistent = True
for service_name, hashes in hashes_by_service.items():
unique_hashes = set(hashes)
if len(unique_hashes) == 1:
print(f"{service_name}: All {iterations} hashes identical")
else:
print(f"{service_name}: {len(unique_hashes)} different hashes found!")
all_consistent = False
if all_consistent:
print("\n✅ DETERMINISM TEST PASSED")
return 0
else:
print("\n❌ DETERMINISM TEST FAILED")
return 1
if __name__ == "__main__":
exit_code = asyncio.run(test_determinism())
exit(exit_code)