"""Opt-in acceptance against a disposable PostgreSQL database, never production.""" import unittest from concurrent.futures import ThreadPoolExecutor from threading import Barrier from test_web import FakeProvisioning from user_engine.adapters import LocalAuthorizationCheckPort from user_engine.adapters.postgres import PostgresUserEngineStore from user_engine.domain import AccountStatus, User from user_engine.errors import ConflictError from user_engine.service import UserEngineService from user_engine.testing.fixtures import FixtureIdentityClaimsAdapter, human_actor_claims from user_engine.testing.postgres_provider import postgres_provider_test_config, connect_postgres_provider, reset_user_engine_postgres_tables from user_engine.web import PortalApplication class PostgresJourneyTests(unittest.TestCase): def setUp(self): self.config,reason=postgres_provider_test_config() if reason:self.skipTest(reason) self.connections=[] self.seed=self.connect() reset_user_engine_postgres_tables(self.seed) self.tenant='tenant:trial:concurrency' claims=human_actor_claims(subject='operator',tenant='tenant:platform:root') claims['roles']=['platform-operator'] self.actor=FixtureIdentityClaimsAdapter().normalize(claims) self.provider=FakeProvisioning() def connect(self): connection=connect_postgres_provider(self.config.dsn) self.connections.append(connection) return connection def service(self,connection): return UserEngineService(store=PostgresUserEngineStore(connection),identity_adapter=FixtureIdentityClaimsAdapter(),authorization=LocalAuthorizationCheckPort()) def tearDown(self): for connection in self.connections:connection.close() def test_two_connections_cannot_disable_both_admins(self): service=self.service(self.seed) users=[] for name in ['first','second']: u=service.create_user(self.actor,display_name=name,primary_email=name+'@example.test') service.set_tenant_account_status(self.actor,u.user_id,AccountStatus.ACTIVE,tenant=self.tenant) service.add_membership(self.actor,u.user_id,tenant=self.tenant,scope_type='tenant',scope_id=self.tenant,kind='tenant-admin') service.link_identity(self.actor,u.user_id,issuer='urn:netkingdom:directory',subject=name,provider='netkingdom-lldap') users.append(u) apps=[PortalApplication(self.service(self.connect()),trusted_proxy_secret='disposable-test-marker-only',login_url='https://test.example',provisioning=self.provider) for _ in users] barrier=Barrier(2) def disable(pair): app,u=pair barrier.wait(timeout=5) try: app._change_status(self.actor,self.tenant,u.user_id,AccountStatus.SUSPENDED,idempotency_key='test-'+u.user_id,correlation_id='concurrent-test') return 'changed' except ConflictError:return 'conflict' with ThreadPoolExecutor(max_workers=2) as pool: results=list(pool.map(disable,zip(apps,users))) self.assertEqual(['changed','conflict'],sorted(results)) self.assertEqual(1,len(self.provider.actions)) self.assertEqual(1,sum(service.store.tenant_account(self.tenant,u.user_id).status==AccountStatus.ACTIVE for u in users)) def test_nested_bootstrap_rolls_back_all_local_records(self): service=self.service(self.seed) user_id=None with self.assertRaises(RuntimeError): with service.store.tenant_lifecycle_guard(self.tenant), service.store.transaction(): user=service.create_user(self.actor,display_name='Partial',primary_email='partial@example.test') user_id=user.user_id service.set_tenant_account_status(self.actor,user_id,AccountStatus.INVITED,tenant=self.tenant) raise RuntimeError('failure before first-admin membership') self.assertIsNone(service.store.user(user_id)) self.assertIsNone(service.store.tenant_account(self.tenant,user_id)) def test_guard_releases_after_exception(self): first=PostgresUserEngineStore(self.seed) second=PostgresUserEngineStore(self.connect()) with self.assertRaises(RuntimeError): with first.tenant_lifecycle_guard(self.tenant):raise RuntimeError('simulated provider failure') cursor=second.connection.cursor() cursor.execute("SET statement_timeout = '2s'") with second.tenant_lifecycle_guard(self.tenant):pass cursor.close() def test_successful_guard_does_not_commit_or_discard_caller_work(self): first=PostgresUserEngineStore(self.seed) second=PostgresUserEngineStore(self.connect()) u=User(user_id='pending-user',display_name='Pending') first.save_user(u) with first.tenant_lifecycle_guard(self.tenant):pass self.assertIsNone(second.user(u.user_id)) self.seed.commit() self.assertEqual(u,second.user(u.user_id))