mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
feat: define matchmaking state transitions
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://cosmic-clash.invalid/contracts/v1/state-transitions.json",
|
||||
"version": 1,
|
||||
"resource_states": {
|
||||
"queue_ticket": ["QUEUED", "PROPOSED", "ACCEPTED", "ALLOCATING", "PROCESS_READY", "ASSIGNMENT_READY", "ASSIGNED", "CONNECTING", "LIVE", "RESULT_PENDING", "COMPLETED", "CANCELLED", "EXPIRED", "FAILED"],
|
||||
"proposal": ["OPEN", "ACCEPTED", "DECLINED", "EXPIRED", "CANCELLED"],
|
||||
"match": ["ALLOCATING", "PROCESS_READY", "ASSIGNMENT_READY", "ASSIGNED", "CONNECTING", "LIVE", "RESULT_PENDING", "COMPLETED", "CANCELLED", "FAILED"]
|
||||
},
|
||||
"transitions": {
|
||||
"queue_ticket": {
|
||||
"QUEUED": ["PROPOSED", "CANCELLED", "EXPIRED"],
|
||||
"PROPOSED": ["QUEUED", "ACCEPTED", "CANCELLED", "EXPIRED"],
|
||||
"ACCEPTED": ["QUEUED", "ALLOCATING", "CANCELLED", "FAILED"],
|
||||
"ALLOCATING": ["PROCESS_READY", "FAILED", "CANCELLED"],
|
||||
"PROCESS_READY": ["ASSIGNMENT_READY", "FAILED", "CANCELLED"],
|
||||
"ASSIGNMENT_READY": ["ASSIGNED", "FAILED", "CANCELLED"],
|
||||
"ASSIGNED": ["CONNECTING", "FAILED", "CANCELLED"],
|
||||
"CONNECTING": ["LIVE", "FAILED", "EXPIRED"],
|
||||
"LIVE": ["RESULT_PENDING", "FAILED"],
|
||||
"RESULT_PENDING": ["COMPLETED", "FAILED"],
|
||||
"COMPLETED": [],
|
||||
"CANCELLED": [],
|
||||
"EXPIRED": [],
|
||||
"FAILED": []
|
||||
},
|
||||
"proposal": {
|
||||
"OPEN": ["ACCEPTED", "DECLINED", "EXPIRED", "CANCELLED"],
|
||||
"ACCEPTED": [],
|
||||
"DECLINED": [],
|
||||
"EXPIRED": [],
|
||||
"CANCELLED": []
|
||||
},
|
||||
"match": {
|
||||
"ALLOCATING": ["PROCESS_READY", "FAILED", "CANCELLED"],
|
||||
"PROCESS_READY": ["ASSIGNMENT_READY", "FAILED", "CANCELLED"],
|
||||
"ASSIGNMENT_READY": ["ASSIGNED", "FAILED", "CANCELLED"],
|
||||
"ASSIGNED": ["CONNECTING", "FAILED", "CANCELLED"],
|
||||
"CONNECTING": ["LIVE", "FAILED", "CANCELLED"],
|
||||
"LIVE": ["RESULT_PENDING", "FAILED"],
|
||||
"RESULT_PENDING": ["COMPLETED", "FAILED"],
|
||||
"COMPLETED": [],
|
||||
"CANCELLED": [],
|
||||
"FAILED": []
|
||||
}
|
||||
},
|
||||
"mutation_rules": {
|
||||
"required_headers": ["Idempotency-Key", "If-Match-Revision"],
|
||||
"same_key_same_payload": "return_original_result_without_new_revision",
|
||||
"same_key_different_payload": "reject_conflict_without_state_change",
|
||||
"stale_revision": "reject_conflict_without_state_change",
|
||||
"event_revision": "strictly_increases_per_resource",
|
||||
"event_recovery": "REST_get_by_resource_id_then_resume_from_next_revision"
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ class ContractTest(unittest.TestCase):
|
||||
def setUpClass(cls):
|
||||
cls.openapi = json.loads((ROOT / "openapi.json").read_text())
|
||||
cls.events = json.loads((ROOT / "websocket-events.json").read_text())
|
||||
cls.transitions = json.loads((ROOT / "state-transitions.json").read_text())
|
||||
|
||||
def test_openapi_is_versioned_and_has_core_surfaces(self):
|
||||
self.assertEqual(self.openapi["openapi"], "3.1.0")
|
||||
@@ -58,6 +59,27 @@ class ContractTest(unittest.TestCase):
|
||||
self.assertNotIn("web_api_ticket", serialized)
|
||||
self.assertNotIn("relay_ticket", serialized)
|
||||
|
||||
def test_state_machine_has_explicit_recovery_and_terminal_edges(self):
|
||||
for resource, states in self.transitions["resource_states"].items():
|
||||
graph = self.transitions["transitions"][resource]
|
||||
self.assertEqual(set(states), set(graph))
|
||||
for state, targets in graph.items():
|
||||
self.assertTrue(set(targets) <= set(states))
|
||||
if state in {"COMPLETED", "CANCELLED", "EXPIRED", "FAILED"}:
|
||||
self.assertEqual(targets, [], state)
|
||||
|
||||
queue = self.transitions["transitions"]["queue_ticket"]
|
||||
self.assertIn("QUEUED", queue["PROPOSED"])
|
||||
self.assertIn("QUEUED", queue["ACCEPTED"])
|
||||
self.assertEqual(
|
||||
self.transitions["mutation_rules"]["same_key_same_payload"],
|
||||
"return_original_result_without_new_revision",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.transitions["mutation_rules"]["same_key_different_payload"],
|
||||
"reject_conflict_without_state_change",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user