import json,subprocess from application_harness import Application,PHP,ROOT for operation in ['activate','deactivate']: app=Application();workers=[] try: ids=app.fixture('tenantSeed');env=app.env.copy();env['HCR_TENANT_IDS']=json.dumps(ids) record=app.fixture('repairConcurrencySeed',str(ids['clubA']),str(ids['invitee']),str(ids['admina'])) for mode,ident,ready in [(operation,record['membership'],'LOCKED'),('accept',record['invitation'],'WAITING')]: p=subprocess.Popen(PHP+['tests/tenant_repair_worker.php',mode,str(ident)],cwd=ROOT,env=env,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True);workers.append(p) assert p.stdout.readline().strip()==ready,p.stderr.read() workers[0].stdin.write('go\n');workers[0].stdin.flush();results=[] for p in workers: output,error=p.communicate(timeout=20);assert p.returncode==0,error+output;results.append(json.loads(output)) if operation=='activate': assert all(x['ok'] for x in results),results assert sum(x['user_serial']==ids['invitee'] and x['club_serial']==ids['clubA'] for x in app.fixture('inspect')['club_memberships'])==1 print('PASS: Invitation acceptance racing membership activation completes both requests without duplicate membership.') else: assert results[0]['ok'] and not results[1]['ok'] and results[1]['status']==404,results member=next(x for x in app.fixture('inspect')['club_memberships'] if x['membership_serial']==record['membership']);assert member['membership_status']=='inactive' print('PASS: Membership deactivation racing acceptance revokes the invitation and preserves denied access.') finally: for p in workers: if p.poll() is None:p.terminate();p.wait(timeout=10) app.close() print('2 tenant repair concurrency scenarios passed.')