import tempfile import unittest import os from pathlib import Path from uuid import uuid4 from archive_clients.state import ( ClientStore, CommandConflict, FileOperationConflict, 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}' ) def test_file_operation_journal_is_idempotent_and_content_addressed(self): with tempfile.TemporaryDirectory() as directory: store = ClientStore(Path(directory) / "state.db") store.initialize() first = store.begin_file_operation( "operation-1", "job-1", '{"destination":"a","source":"b"}' ) repeated = store.begin_file_operation( "operation-1", "job-1", '{"source":"b","destination":"a"}' ) self.assertEqual(first["state"], "intent") self.assertEqual(repeated["state"], "intent") completed = store.complete_file_operation( "operation-1", '{"method":1}' ) duplicate = store.complete_file_operation( "operation-1", '{"method":1}' ) self.assertEqual(completed["state"], "completed") self.assertEqual(duplicate["result_json"], '{"method":1}') with self.assertRaises(FileOperationConflict): store.begin_file_operation( "operation-1", "job-1", '{"source":"other"}' ) with self.assertRaises(FileOperationConflict): store.complete_file_operation( "operation-1", '{"method":2}' ) if __name__ == "__main__": unittest.main()