"""Offline destructive-step failures restore both original container IDs.""" import json import os from pathlib import Path import subprocess import pytest FAKE = r'''#!/usr/bin/env python3 import json,os,sys p=os.environ['STATE'];s=json.load(open(p));a=sys.argv[1:] def save():open(p,'w').write(json.dumps(s)) def item(n):return next((x for x in s['containers'] if x['name']==n or x['id']==n),None) cmd=a[0];n=a[-1];c=item(n) if cmd=='inspect': if not c:sys.exit(1) if '--format' in a: fmt=a[a.index('--format')+1] print(c['id'] if '.Id' in fmt else '/'+c['name'] if '.Name' in fmt else 'healthy') else:print(json.dumps([c])) elif cmd=='stop': c['running']=False;save() if n=='hope-control' and s['failure']=='stop':sys.exit(7) elif cmd=='rename': c=item(a[1]) if a[1]=='hope-control' and s['failure']=='rename':sys.exit(8) c['name']=a[2];save() elif cmd=='start':c['running']=True;save() elif cmd=='rm': assert c['id'] not in ['original-voice','original-control'] s['containers'].remove(c);save() elif cmd=='run': if '--entrypoint' in a: entry=a[a.index('--entrypoint')+1] if entry=='curl' and '%{http_code}' in a:print('401') sys.exit(0) name=a[a.index('--name')+1] if name=='voice' and s['failure']=='run':sys.exit(9) s['containers'].append({'name':name,'id':'new-'+name,'running':True});save() else:sys.exit(2) ''' @pytest.mark.parametrize('failure',['stop','rename','run']) def test_partial_deployment_restores_originals(tmp_path,failure): root=tmp_path/'state';root.mkdir() for n in ['runtime.env','livekit.yaml','voice.env']:(root/n).touch() for n in ['accounts','hermes','certs']:(root/n).mkdir() state=root/'fake.json' state.write_text(json.dumps({'failure':failure,'containers':[{'name':'voice','id':'original-voice','running':True},{'name':'hope-control','id':'original-control','running':True}]})) bindir=tmp_path/'bin';bindir.mkdir() for name,text in [('docker',FAKE),('curl','#!/bin/sh\nexit 0\n')]: p=bindir/name;p.write_text(text);p.chmod(0o755) source=(Path(__file__).parents[2]/'scripts/deploy-unraid.sh').read_text() source=source.replace('ROOT=/mnt/user/appdata/hope-voice',f'ROOT={root}').replace('/mnt/user/dev/hope-voice-api/certs',str(root/'certs')) script=tmp_path/'deploy.sh';script.write_text(source) env=dict(os.environ,STATE=str(state),PATH=str(bindir)+os.pathsep+os.environ['PATH']) result=subprocess.run(['bash',str(script)],env=env,capture_output=True,text=True) assert result.returncode!=0,result.stdout+result.stderr data=json.loads(state.read_text()) assert sorted((x['name'],x['id'],x['running']) for x in data['containers'])==[('hope-control','original-control',True),('voice','original-voice',True)]