98 lines
3.2 KiB
Python
98 lines
3.2 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.core.crypto import hash_opaque_token
|
|
from app.modules.sync import repository as repo
|
|
|
|
|
|
from uuid import uuid4
|
|
|
|
|
|
@pytest.fixture()
|
|
def enterprise(client: TestClient):
|
|
slug = f"test-farm-{uuid4().hex[:8]}"
|
|
ent = repo.create_enterprise("Test Farm Co", slug)
|
|
admin = repo.get_member.__module__ # noqa: ensure import path
|
|
from app.modules.users.repository import get_user_by_email
|
|
|
|
user = get_user_by_email("admin@compton.example")
|
|
assert user
|
|
repo.add_member(user.id, ent.id, "admin")
|
|
return ent
|
|
|
|
|
|
def test_sync_capabilities(client: TestClient):
|
|
resp = client.get("/api/v1/sync/capabilities")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["protocol_version"] == "1.0"
|
|
assert "global" in data["domains"]
|
|
|
|
|
|
def test_pairing_flow(client: TestClient, enterprise):
|
|
login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
|
|
token = login.json()["access_token"]
|
|
start = client.post(
|
|
"/api/v1/enterprise/pair/start",
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
json={"enterprise_id": enterprise.id, "farm_name": "Farm A"},
|
|
)
|
|
assert start.status_code == 200
|
|
code = start.json()["code"]
|
|
confirm = client.post(
|
|
"/api/v1/enterprise/pair/confirm",
|
|
json={"code": code, "hub_site_id": "hub-site-001", "hub_name": "Farm A Hub"},
|
|
)
|
|
assert confirm.status_code == 200
|
|
body = confirm.json()
|
|
assert body["hub_site_id"] == "hub-site-001"
|
|
assert body["api_key"]
|
|
|
|
|
|
def test_hub_push_idempotent(client: TestClient, enterprise):
|
|
login = client.post("/api/v1/auth/login", json={"email": "admin@compton.example", "password": "Admin1234"})
|
|
token = login.json()["access_token"]
|
|
start = client.post(
|
|
"/api/v1/enterprise/pair/start",
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
json={"enterprise_id": enterprise.id, "farm_name": "Farm B"},
|
|
)
|
|
code = start.json()["code"]
|
|
confirm = client.post(
|
|
"/api/v1/enterprise/pair/confirm",
|
|
json={"code": code, "hub_site_id": "hub-site-002", "hub_name": "Farm B Hub"},
|
|
)
|
|
api_key = confirm.json()["api_key"]
|
|
hub_auth = f"Hub hub-site-002:{api_key}"
|
|
from datetime import UTC, datetime
|
|
|
|
event = {
|
|
"event_id": "evt-001",
|
|
"seq": 1,
|
|
"domain": "global",
|
|
"table": "component",
|
|
"record_id": "comp-001",
|
|
"action": "upsert",
|
|
"version": 1,
|
|
"content_hash": "hash1",
|
|
"payload": {"name": "Corn", "type": "grain", "dry_matter": 88.0},
|
|
"emitted_at": datetime.now(UTC).isoformat(),
|
|
"origin_site_id": "hub-site-002",
|
|
}
|
|
push1 = client.post(
|
|
"/api/v1/sync/changes/push",
|
|
headers={"Authorization": hub_auth},
|
|
json={"events": [event]},
|
|
)
|
|
assert push1.status_code == 200
|
|
assert "evt-001" in push1.json()["applied_event_ids"]
|
|
push2 = client.post(
|
|
"/api/v1/sync/changes/push",
|
|
headers={"Authorization": hub_auth},
|
|
json={"events": [event]},
|
|
)
|
|
assert push2.status_code == 200
|
|
assert "evt-001" in push2.json()["applied_event_ids"]
|