71 lines
4.4 KiB
Python
71 lines
4.4 KiB
Python
"""Run the real archiver against synthetic sealed startup logs, without engines."""
|
|
from pathlib import Path
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0,str(ROOT/'tools'))
|
|
from native_provenance import snapshot,persist,bindings,seal_run
|
|
from test_vanilla_game_control import BASE
|
|
|
|
ORDINARY='''00 SCRIPT : Module: Game; defines: "PLATFORM_WINDOWS"
|
|
00 SCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems
|
|
00 SCRIPT : Rereintroduced [mission]: phase 0 -> 1
|
|
00 SCRIPT : ERR ORDINARY: local participant verified project=core phase=prison
|
|
'''
|
|
|
|
class ArchiveControl(unittest.TestCase):
|
|
def archive(self,project,result,control=None,cleanup=True,content=None):
|
|
tmp=tempfile.TemporaryDirectory(prefix='erri-archive-control-test-');self.addCleanup(tmp.cleanup)
|
|
root=Path(tmp.name);(root/'addons/core').mkdir(parents=True)
|
|
(root/'addons/core/addon.gproj').write_text('Synthetic fixture source, not a native project')
|
|
tools=root/'tools';tools.mkdir()
|
|
for name in ('archive_native.py','native_report.py','source_manifest.py','native_provenance.py','headless_game.py','project_schema.py'):
|
|
shutil.copyfile(ROOT/'tools'/name,tools/name)
|
|
session=root/'session';session.mkdir()
|
|
(session/'console.log').write_text(content if content is not None else BASE if project=='vanilla-control' else ORDINARY)
|
|
captured=snapshot(root,['synthetic-archive-test-no-engine']);persist(session,captured)
|
|
data={**bindings(captured),'started_unix':json.loads(captured[1])['captured_unix'],**seal_run(root,session,captured),'project':project,'result':result,'cleanup_confirmed':cleanup}
|
|
if control is not None:data['control_only']=control
|
|
(session/'runner.json').write_text(json.dumps(data))
|
|
# Deliberately false saved status; actual archiver must recompute sealed log.
|
|
(session/'game-startup-report.json').write_text('{"ready":true,"failed":false}')
|
|
command=[sys.executable,str(tools/'archive_native.py'),str(session),'control']
|
|
done=subprocess.run(command,text=True,capture_output=True)
|
|
dest=root/'docs/evidence/control'
|
|
self.assertTrue(dest.exists(),done.stderr)
|
|
self.assertEqual((dest/'console.log.txt').read_bytes(),(session/'console.log').read_bytes())
|
|
self.assertTrue((dest/'report.json').is_file(), done.stderr)
|
|
return done,json.loads((dest/'report.json').read_text()),command,dest
|
|
def test_clean_control_gets_own_result_and_no_successor_qualification(self):
|
|
result,report,command,dest=self.archive('vanilla-control','vanilla-control-started',True)
|
|
self.assertEqual(result.returncode,0,result.stderr)
|
|
self.assertTrue(report['control_metadata_consistent']);self.assertTrue(report['control_only'])
|
|
self.assertFalse(report['normal_mission_ready']);self.assertFalse(report['scenario_header_verified'])
|
|
self.assertIn('no successor',report['qualification'])
|
|
before=(dest/'report.json').read_bytes()
|
|
duplicate=subprocess.run(command,capture_output=True,text=True)
|
|
self.assertNotEqual(duplicate.returncode,0);self.assertEqual((dest/'report.json').read_bytes(),before)
|
|
def test_control_rejects_ordinary_result_or_inconsistent_flag(self):
|
|
for result,flag in [('game-started',True),('vanilla-control-started',None),('vanilla-control-started',False),('vanilla-control-started','true')]:
|
|
with self.subTest(result=result,flag=flag):
|
|
done,report,_,_=self.archive('vanilla-control',result,flag)
|
|
self.assertEqual(done.returncode,1);self.assertTrue(report['ready'])
|
|
def test_control_retains_native_failure_despite_saved_success(self):
|
|
done,report,_,_=self.archive('vanilla-control','vanilla-control-started',True,content=BASE+"00 GUI (E): Unknown class 'SCR_WidgetExportRuleRoot'")
|
|
self.assertEqual(done.returncode,1);self.assertFalse(report['ready']);self.assertTrue(report['engine_errors'])
|
|
def test_cleanup_is_still_required(self):
|
|
done,_,_,_=self.archive('vanilla-control','vanilla-control-started',True,cleanup=False)
|
|
self.assertEqual(done.returncode,1)
|
|
def test_ordinary_current_and_legacy_status_remain_strict(self):
|
|
for flag in (None,False):
|
|
done,report,_,_=self.archive('core','game-started',flag)
|
|
self.assertEqual(done.returncode,0,done.stderr);self.assertTrue(report['normal_mission_ready'])
|
|
for result,flag in [('vanilla-control-started',False),('game-started',True)]:
|
|
done,_,_,_=self.archive('core',result,flag);self.assertEqual(done.returncode,1)
|
|
|
|
if __name__=='__main__':unittest.main()
|