import tempfile import unittest import os from pathlib import Path from uuid import uuid4 from archive_clients.state import ClientStore, CommandConflict, JobConflict class ClientStoreTests(unittest.TestCase): def test_command_acceptance_is_durable_and_content_addressed(self): with tempfile.TemporaryDirectory() as directory: database = Path(directory) / "state.db" store = ClientStore(database) store.initialize() self.assertEqual(os.stat(database).st_mode & 0o777, 0o600) command_id = str(uuid4()) first = store.accept_command(command_id, '{"b":2,"a":1}', '{"ok":true}') duplicate = ClientStore(database).accept_command( command_id, '{"a":1,"b":2}', '{"ok":false}' ) self.assertFalse(first.duplicate) self.assertTrue(duplicate.duplicate) self.assertEqual(duplicate.acknowledgement_json, '{"ok":true}') with self.assertRaises(CommandConflict): store.accept_command(command_id, '{"a":2}', '{"ok":true}') def test_job_definition_is_immutable_while_cursor_advances(self): with tempfile.TemporaryDirectory() as directory: store = ClientStore(Path(directory) / "state.db") store.initialize() store.save_job( "job-1", '{"jobId":"job-1"}', "JOB_STATE_WAITING", 1, 2, False, ) store.save_job( "job-1", '{"jobId":"job-1"}', "JOB_STATE_RUNNING", 2, 3, False, ) self.assertEqual( store.job_snapshot_rows(["job-1"])[0]["revision"], 2 ) with self.assertRaisesRegex(JobConflict, "backwards"): store.save_job( "job-1", '{"jobId":"job-1"}', "JOB_STATE_WAITING", 1, 2, False, ) with self.assertRaises(JobConflict): store.save_job( "job-1", '{"jobId":"other"}', "JOB_STATE_RUNNING", 2, 3, False, ) def test_route_attempt_nonce_and_updates_survive_duplicate_commands(self): with tempfile.TemporaryDirectory() as directory: store = ClientStore(Path(directory) / "state.db") store.initialize() command_id = str(uuid4()) store.accept_command(command_id, '{"route":"one"}', '{"ok":true}') first = store.begin_route_attempt( command_id, "route-1", '{"routeId":"route-1"}', "nonce-1" ) duplicate = store.begin_route_attempt( command_id, "route-1", '{"routeId":"route-1"}', "new-nonce" ) self.assertEqual(first["nonce"], "nonce-1") self.assertEqual(duplicate["nonce"], "nonce-1") store.record_route_update( command_id, 1, "provisioning", '{"sequence":1}' ) store.record_route_ownership(command_id, True, True) store.record_route_update( command_id, 1, "provisioning", '{"sequence":1}' ) store.record_route_update( command_id, 2, "ready", '{"sequence":2}' ) self.assertEqual(store.get_route_attempt(command_id)["state"], "ready") self.assertEqual(store.get_route_attempt(command_id)["created_folder"], 1) self.assertEqual( [row["sequence"] for row in store.route_update_rows(command_id)], [1, 2], ) with self.assertRaises(CommandConflict): store.record_route_update( command_id, 2, "ready", '{"sequence":2,"changed":true}' ) if __name__ == "__main__": unittest.main()