import subprocess from application_harness import Application,PHP,ROOT app=Application();checks=[] def check(ok,message): if not ok:raise AssertionError(message) checks.append(message);print('PASS: '+message) try: ids=app.fixture('tenantSeed');app.fixture('legacyTenantSchema') before=app.fixture('inspect');env=app.env.copy();env['HCR_SUPER_ADMIN_EMAIL']='admina@example.test' result=subprocess.run(PHP+['bin/migrate-tenants.php'],cwd=ROOT,env=env,capture_output=True,text=True);check(result.returncode==0,'Tenant migration upgrades the legacy membership schema') after=app.fixture('inspect');selected=next(x for x in after['users'] if x['user_serial']==ids['admina']);old=next(x for x in before['users'] if x['user_serial']==ids['admina']) check(selected['user_role']=='Super System Administrator' and selected['user_auth_version']==old['user_auth_version']+1,'Only the explicitly designated account is promoted and its sessions are revoked') check(next(x for x in after['users'] if x['user_serial']==ids['adminb'])['user_role']=='Administrator','Another legacy Administrator is not promoted') check(all(x['membership_role']=='member' for x in after['club_memberships']),'Migration never guesses club administrator assignments for legacy memberships') check([{k:v for k,v in x.items() if k!='membership_role'} for x in after['club_memberships']]==before['club_memberships'] and after['clubs']==before['clubs'],'Club data and existing memberships are preserved') fingerprints=app.fixture('fingerprints');subprocess.run(PHP+['bin/migrate-tenants.php'],cwd=ROOT,env=env,capture_output=True,check=True);check(app.fixture('fingerprints')==fingerprints,'Rerunning explicit promotion leaves rows, sessions and audit unchanged') env['HCR_SUPER_ADMIN_EMAIL']='missing-owner@example.test';result=subprocess.run(PHP+['bin/migrate-tenants.php'],cwd=ROOT,env=env,capture_output=True);check(result.returncode!=0 and app.fixture('fingerprints')==fingerprints,'Missing designated account fails without promoting another account') app.login();response=app.post('Roster.workspace',step='club',club_serial=0,club_name='Tenant Alpha');check(response[0]==200 and len(app.fixture('inspect')['clubs'])==3,'Independent clubs may use the same display name after migration') finally:app.close() print(str(len(checks))+' tenant migration checks passed.')