"""Temporary filesystem tests only; no process/brain/GPU execution.""" import copy import json import os from pathlib import Path import tempfile import unittest from unittest.mock import patch import append_ledger as L def put(path, value): path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes(value if type(value) is bytes else L.raw_json(value)) return L.identity(path) class LedgerTests(unittest.TestCase): def setUp(self): self.temp=tempfile.TemporaryDirectory();self.addCleanup(self.temp.cleanup) self.root=Path(self.temp.name).resolve()/'normal';self.root.mkdir() self.reg=self.root/L.REGISTRATION; info=put(self.reg,{'only':'synthetic-registration'}) self.initial={L.REGISTRATION:info};self.sha=info['sha256'] self.ledger=L.Ledger(self.root,self.sha,self.initial,1<<20,0) def job(self,name): job=self.root/'jobs'/(name+'.json');put(job,{'entry_id':name}) self.ledger.begin(name,job,{'synthetic':True}) return job def completion(self,name,job,*,payload=b'output',changes=None): out=self.root/'runs'/name/'payload.dat';put(out,payload) process=self.root/'receipts'/(name+'.json') value=dict(entry_id=name,registration_sha256=self.sha,job_sha256=L.digest(job),complete=True, exit_code=0,timed_out=False,exit_observed_by_parent=True) value.update(changes or {});put(process,value) inputs={str(self.reg):L.identity(self.reg),str(job):L.identity(job)} outputs={str(p):L.identity(p) for p in (job,out,process)} metadata=dict(job_file=str(job),process_receipt_file=str(process),scope='synthetic completed parent job only',observed_returncode=0) return inputs,outputs,metadata def commit(self,name): job=self.job(name);args=self.completion(name,job) return self.ledger.append(name,*args) def test_two_entries_chain_full_tree_and_cumulative_bytes(self): one=self.commit('one');two=self.commit('two') second=L.read_json(self.root/L.CONTROL/'entries/0000000000000002.json') self.assertEqual(second['prev_entry_sha256'],one['entry_sha256']) self.assertEqual(two['entry_sha256'],L.digest(self.root/L.CONTROL/'entries/0000000000000002.json')) inspected=self.ledger.inspect();self.assertEqual(inspected['entry_ids'],['one','two']) self.assertFalse(inspected['retry_authorized']);self.assertTrue(inspected['all_tracked_history_rehashed']) final=self.ledger.final_verify(['one','two']);self.assertTrue(final['pass_all']) self.assertEqual(final['actual_total_bytes'],sum(p.stat().st_size for p in self.root.rglob('*') if p.is_file())) self.assertFalse(final['scientific_gate_claimed']) def test_reopen_independent_read_verifies_no_reexecution_or_duplicate_append(self): self.commit('one') reopened=L.Ledger(self.root,self.sha,self.initial,1<<20,0) self.assertEqual(reopened.inspect()['entry_ids'],['one']) with self.assertRaisesRegex(ValueError,'already started/committed'): reopened.begin('one',self.root/'jobs/one.json') with self.assertRaisesRegex(ValueError,'No unique uncommitted'): reopened.append('one',{}, {},dict(job_file='x',process_receipt_file='y',scope='s',observed_returncode=0)) def test_pending_or_live_handle_is_unknown_and_never_retry_authority(self): job=self.job('live');state=self.ledger.inspect() self.assertEqual(state['uncommitted_state'],'STARTED-UNCOMMITTED-STATE-UNKNOWN') self.assertFalse(state['retry_authorized']) with self.assertRaisesRegex(ValueError,'uncommitted start'):self.ledger.begin('another',job) args=list(self.completion('live',job));args[2]['observed_returncode']=None with self.assertRaisesRegex(ValueError,'Live/failed'):self.ledger.append('live',*args) final=self.ledger.final_verify(['live']);self.assertFalse(final['pass_all']);self.assertTrue(final['uncommitted_state_unknown']) reopened=L.Ledger(self.root,self.sha,self.initial,1<<20,0) self.assertEqual(reopened.inspect()['uncommitted_entry_ids'],['live']) def test_actual_parent_receipt_required_not_worker_success_or_bool_exit(self): job=self.job('one') for mutation in ({'exit_code':False},{'complete':False},{'exit_observed_by_parent':False}, {'timed_out':True},{'registration_sha256':'0'*64},{'job_sha256':'0'*64},{'entry_id':'other'}): args=self.completion('one',job,changes=mutation) with self.subTest(mutation=mutation),self.assertRaisesRegex(ValueError,'parent process receipt'): self.ledger.append('one',*args) def test_same_size_same_mtime_mutation_fails_actual_SHA(self): job=self.job('one');args=self.completion('one',job,payload=b'aaaa') out=self.root/'runs/one/payload.dat';stat=out.stat();out.write_bytes(b'bbbb') os.utime(out,ns=(stat.st_atime_ns,stat.st_mtime_ns)) with self.assertRaisesRegex(ValueError,'Actual file SHA/bytes'):self.ledger.append('one',*args) def test_missing_extra_changed_files_reported_at_full_audit(self): self.commit('one');out=self.root/'runs/one/payload.dat' extra=self.root/'unexpected.log';put(extra,b'extra') final=self.ledger.final_verify(['one']);self.assertFalse(final['pass_all']);self.assertIn('unexpected.log',final['extra_files']) out.unlink();final=self.ledger.final_verify(['one']) self.assertIn('runs/one/payload.dat',final['missing_files']) put(out,b'different');final=self.ledger.final_verify(['one']) self.assertIn('runs/one/payload.dat',final['changed_files']) def test_tail_and_middle_tamper_not_trusted_by_inspect(self): self.commit('one');self.commit('two') first=self.root/L.CONTROL/'entries/0000000000000001.json' value=L.read_json(first);value['metadata']['scope']='tampered' put(first,value) with self.assertRaisesRegex(ValueError,'chain/start identity'):self.ledger.inspect() self.assertFalse(self.ledger.final_verify(['one','two'])['pass_all']) def test_previously_observed_head_rewrite_rejected_even_new_valid_JSON(self): self.commit('one');path=self.root/L.CONTROL/'entries/0000000000000001.json' value=L.read_json(path);value['metadata']['scope']='changed';put(path,value) with self.assertRaisesRegex(ValueError,'head changed'):self.ledger.inspect() def test_registered_final_entry_order_and_coverage_are_exact(self): self.commit('one');self.commit('two') for expected in (['two','one'],['one'],['one','two','three']): report=self.ledger.final_verify(expected) self.assertFalse(report['pass_all']);self.assertFalse(report['expected_order_exact']) with self.assertRaisesRegex(ValueError,'expected entry order'):self.ledger.final_verify(['one','one']) def test_path_escape_aliases_and_overwrite_rejected(self): self.commit('one');job=self.job('two');inputs,outputs,meta=self.completion('two',job) outside=self.root.parent/'outside.dat';put(outside,b'external') outputs[str(outside)]=L.identity(outside) with self.assertRaisesRegex(ValueError,'escapes experiment'):self.ledger.append('two',inputs,outputs,meta) del outputs[str(outside)];old=self.root/'runs/one/payload.dat';outputs[str(old)]=L.identity(old) with self.assertRaisesRegex(ValueError,'previously tracked'):self.ledger.append('two',inputs,outputs,meta) del outputs[str(old)];outputs['runs/two/payload.dat']=outputs[str(self.root/'runs/two/payload.dat')] with self.assertRaisesRegex(ValueError,'Duplicate path aliases'):self.ledger.append('two',inputs,outputs,meta) with self.assertRaisesRegex(ValueError,'Escaping/noncanonical'):L.relative_name('../escape') def test_consumed_tracked_input_cannot_be_silently_reauthorized_with_new_SHA(self): self.commit('one');job=self.job('two');inputs,outputs,meta=self.completion('two',job) prior=self.root/'runs/one/payload.dat';put(prior,b'overwritten') inputs[str(prior)]=L.identity(prior) with self.assertRaisesRegex(ValueError,'committed identity'):self.ledger.append('two',inputs,outputs,meta) def test_external_inputs_allowed_but_declared_bytes_reverified(self): job=self.job('one');inputs,outputs,meta=self.completion('one',job) external=self.root.parent/'frozen-reference.json';put(external,{'read_only':'data'}) inputs[str(external)]=L.identity(external);self.ledger.append('one',inputs,outputs,meta) row=L.read_json(self.root/L.CONTROL/'entries/0000000000000001.json') self.assertIsNone(next(r for r in row['consumed_inputs'] if r['path']==str(external))['relative_path']) put(external,{'read_only':'changed'}) with self.assertRaisesRegex(ValueError,'Actual file SHA/bytes'):self.ledger.inspect() def test_full_audit_hashes_shared_external_input_once_per_invocation(self): external=self.root.parent/'large-shared-reference';put(external,b'fixed external bytes') expected=L.identity(external) for name in ('one','two','three'): job=self.job(name);inputs,outputs,meta=self.completion(name,job) inputs[str(external)]=expected;self.ledger.append(name,inputs,outputs,meta) original=L.digest;counts={} def counted(path): key=str(Path(path));counts[key]=counts.get(key,0)+1 return original(path) with patch.object(L,'digest',side_effect=counted): self.assertTrue(self.ledger.final_verify(['one','two','three'])['pass_all']) self.assertEqual(counts[str(external)],1) counts.clear();self.ledger.inspect();self.assertEqual(counts[str(external)],1) counts.clear();self.ledger.inspect();self.assertEqual(counts[str(external)],1) oldstat=external.stat();external.write_bytes(b'other external bytes') os.utime(external,ns=(oldstat.st_atime_ns,oldstat.st_mtime_ns)) with self.assertRaisesRegex(ValueError,'Actual file SHA/bytes'):self.ledger.inspect() def test_append_does_not_iterate_or_sum_historical_maps_or_search_ordered_ids(self): self.commit('one') class LookupOnlyDict(dict): def __iter__(self):raise AssertionError('Historical map iteration in fast append') def keys(self):raise AssertionError('Historical map copy in fast append') def values(self):raise AssertionError('Historical map sum in fast append') def items(self):raise AssertionError('Historical map iteration in fast append') class NoLinearMembership(list): def __contains__(self,value):raise AssertionError('Linear completed-ID membership') self.ledger._tracked=LookupOnlyDict(self.ledger._tracked) self.ledger._controls=LookupOnlyDict(self.ledger._controls) self.ledger._completed=NoLinearMembership(self.ledger._completed) self.commit('two') self.assertEqual(self.ledger._completed,['one','two']) self.assertTrue(self.ledger.final_verify(['one','two'])['pass_all']) def test_head_is_freshly_checked_after_cached_full_tree_walk(self): self.commit('one');tail=self.root/L.CONTROL/'entries/0000000000000001.json' original_replay=self.ledger._replay;original_identity=self.ledger._identity_once state={'walking':False,'mutated':False} def replay(verified): original_replay(verified);state['walking']=True def during_walk(path,verified): if state['walking'] and not state['mutated']: value=L.read_json(tail);value['metadata']['scope']='mutation during final walk' put(tail,value);state['mutated']=True return original_identity(path,verified) with patch.object(self.ledger,'_replay',side_effect=replay),\ patch.object(self.ledger,'_identity_once',side_effect=during_walk): report=self.ledger.final_verify(['one']) self.assertTrue(state['mutated']);self.assertFalse(report['pass_all']) self.assertTrue(any('Known ledger tail changed' in message for message in report['errors'])) def test_shared_mutable_build_separate_current_inventory_and_cap(self): build=self.root/'extension-build/cache.bin';put(build,b'first');self.commit('one') put(build,b'changed build is allowed');self.commit('two') report=self.ledger.final_verify(['one','two']);self.assertTrue(report['pass_all']) self.assertEqual(report['shared_mutable_build_bytes'],len(b'changed build is allowed')) self.assertNotIn('extension-build/cache.bin',report['extra_files']) put(build,b'x'*(1<<20));report=self.ledger.final_verify(['one','two']) self.assertFalse(report['pass_all']);self.assertFalse(report['output_cap_respected']) def test_stale_writer_lock_and_partial_publication_never_auto_cleared(self): lock=self.root/L.CONTROL/'writer.lock';put(lock,b'unknown owner') with self.assertRaises(FileExistsError):self.ledger.begin('one',self.reg) with self.assertRaisesRegex(ValueError,'state unknown'):self.ledger.inspect() self.assertEqual(lock.read_bytes(),b'unknown owner') def test_exclusive_atomic_publication_and_preserved_failed_temporary(self): target=self.root/'standalone.json';info=L.publish_exclusive(target,{'a':1}) self.assertEqual(info,L.identity(target)) with self.assertRaisesRegex(ValueError,'already exists'):L.publish_exclusive(target,{'a':2}) self.assertEqual(L.read_json(target),{'a':1}) target2=self.root/'failed.json' with patch.object(L.os,'link',side_effect=OSError('synthetic unsupported filesystem')): with self.assertRaises(OSError):L.publish_exclusive(target2,{'a':2}) self.assertFalse(target2.exists());self.assertEqual(len(list(self.root.glob('.publishing-*'))),1) def test_linked_output_rejected_if_platform_supports_links(self): source=self.root.parent/'other';source.mkdir();link=self.root/'linked' try:link.symlink_to(source,target_is_directory=True) except OSError:self.skipTest('Platform disallows synthetic symlink') job=self.job('one');inputs,outputs,meta=self.completion('one',job) put(source/'payload',b'x');outputs[str(link/'payload')]=L.identity(source/'payload') with self.assertRaisesRegex(ValueError,'Linked'):self.ledger.append('one',inputs,outputs,meta) def test_initial_and_header_authority_are_not_optional(self): for change in ('registration','options'): with self.subTest(change=change),self.assertRaises(ValueError): L.Ledger(self.root,'0'*64 if change=='registration' else self.sha,self.initial, 2<<20 if change=='options' else 1<<20,0) header=self.root/L.CONTROL/'header.json';value=L.read_json(header);value['max_output_bytes']+=1;put(header,value) with self.assertRaisesRegex(ValueError,'header changed'):self.ledger.inspect() if __name__=='__main__':unittest.main()