diff --git a/roadscore/prototype/composer_choice.py b/roadscore/prototype/composer_choice.py index 07942db140..1b3e2803fa 100644 --- a/roadscore/prototype/composer_choice.py +++ b/roadscore/prototype/composer_choice.py @@ -21,8 +21,12 @@ def check_available(): worker_state=json.loads((ROOT/'generated/ace_worker_state.json').read_text());profile=worker_state['profile'] except (OSError,ValueError,KeyError):raise SystemExit('ACE worker profile unavailable; restart preparation explicitly') from generation_seed import configured_seed - if worker_state.get('generation_seed')!=configured_seed():raise SystemExit('Resident ACE seed differs; stop owned worker and prepare requested seed') - if profile!=selected_profile():raise SystemExit('Resident ACE profile differs; stop owned worker and prepare requested profile') + resident_handoff=False + if os.environ.get('ROADSCORE_RESIDENT')=='1' and os.environ.get('ROADSCORE_SEED_ORIGIN')!='judging-route': + try:resident_handoff=json.loads((ROOT/'generated/ace_initial.json').read_text()).get('resident_capable') is True + except (OSError,ValueError):pass + if not resident_handoff and worker_state.get('generation_seed')!=configured_seed():raise SystemExit('Resident ACE seed differs; stop owned worker and prepare requested seed') + if not resident_handoff and profile!=selected_profile():raise SystemExit('Resident ACE profile differs; stop owned worker and prepare requested profile') return lockpath=ROOT/'generated/gpu.lock' if lockpath.exists(): diff --git a/roadscore/prototype/test_composer_resident_handoff.py b/roadscore/prototype/test_composer_resident_handoff.py new file mode 100644 index 0000000000..dee47d4668 --- /dev/null +++ b/roadscore/prototype/test_composer_resident_handoff.py @@ -0,0 +1,23 @@ +import json, os, tempfile, unittest +from pathlib import Path +from unittest.mock import patch, Mock +import composer_choice as c + +class ResidentHandoffTest(unittest.TestCase): + def check(self, optin, capable, judging=False): + with tempfile.TemporaryDirectory() as folder: + root=Path(folder); (root/'generated').mkdir() + (root/'generated/ace_worker_state.json').write_text(json.dumps({'profile':'prism','generation_seed':1})) + (root/'generated/ace_initial.json').write_text(json.dumps({'resident_capable':capable})) + command=Mock(); command.read_bytes.return_value=b'python /worker.py\0' + env={'ROADSCORE_COMPOSER':'ace','ROADSCORE_RESIDENT':optin,'ROADSCORE_SEED_ORIGIN':'judging-route' if judging else 'fresh-session'} + with patch.object(c,'ROOT',root),patch.object(c,'worker_path',return_value=Path('/worker.py')),patch.object(Path,'glob',return_value=[command]),patch.dict(os.environ,env),patch('generation_seed.configured_seed',return_value=2),patch('ace_profiles.selected',return_value='prism'): + c.check_available() + def test_opted_capable_reaches_authenticated_handoff(self):self.check('1',True) + def test_no_optin_rejects(self): + with self.assertRaises(SystemExit):self.check('0',True) + def test_nonresident_rejects(self): + with self.assertRaises(SystemExit):self.check('1',False) + def test_judging_rejects(self): + with self.assertRaises(SystemExit):self.check('1',True,True) +if __name__=='__main__':unittest.main()