trainlog/tests/test_sync_orchestrator.py

31 lines
2.6 KiB
Python

import json, os, subprocess, tempfile, unittest, uuid
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
ORCHESTRATOR=ROOT/"tools/sync_orchestrator.py"
FIXTURE=ROOT/"tests/sync_orchestrator_peer_fixture.py"
class OrchestratorTest(unittest.TestCase):
def test_correlated_worker_report_is_durable_and_reopenable(self):
for trigger in ("web","android"):
with self.subTest(trigger=trigger), tempfile.TemporaryDirectory() as directory:
root=Path(directory);db=root/"trainlog.db";db.touch();state=Path(str(db)+".sync-run.json")
run="sy_"+str(uuid.uuid4());request="sy_"+str(uuid.uuid4())
state.write_text(json.dumps({"run_id":run,"request_id":request,"trigger":trigger,"phase":"requested","progress_revision":1,"result":"running"}))
config=root/"config.json";config.write_text(json.dumps({"format":"trainlog-sync-orchestrator-config","version":1,"enabled":True,"mode":"directory-test-double","capabilities":["generation-manifest-v1","generation-ack-v1","causal-delete-v1","mobile-history-v4","execution-draft-v1"],"peer_command":["python3",str(FIXTURE)],"timeout_seconds":30}))
result=subprocess.run(["python3",str(ORCHESTRATOR),"--database",str(db),"--state",str(state),"--config",str(config),"--run-id",run,"--request-id",request],capture_output=True,text=True)
self.assertEqual(result.returncode,0,result.stderr)
final=json.loads(state.read_text());self.assertEqual(final["phase"],"completed")
self.assertEqual(final["result"],"completed");self.assertEqual(final["sessions_reconciled"],1)
self.assertTrue(final["domains"]["causal-delete-v1"]);self.assertEqual(final["drafts"][0]["state"],"pending")
def test_missing_capability_is_explicitly_degraded(self):
with tempfile.TemporaryDirectory() as directory:
root=Path(directory);db=root/"trainlog.db";db.touch();state=Path(str(db)+".sync-run.json")
run="sy_"+str(uuid.uuid4());request="sy_"+str(uuid.uuid4())
state.write_text(json.dumps({"run_id":run,"request_id":request,"trigger":"web","phase":"requested","progress_revision":1,"result":"running"}))
config=root/"config.json";config.write_text(json.dumps({"format":"trainlog-sync-orchestrator-config","version":1,"enabled":True,"mode":"directory-test-double","capabilities":[],"peer_command":["python3",str(FIXTURE)],"timeout_seconds":30}))
result=subprocess.run(["python3",str(ORCHESTRATOR),"--database",str(db),"--state",str(state),"--config",str(config),"--run-id",run,"--request-id",request])
self.assertEqual(result.returncode,3);self.assertEqual(json.loads(state.read_text())["phase"],"explicitly_degraded")
if __name__=="__main__":unittest.main()