# Copyright (c) 2026 Patrick Motsch # All rights reserved. """T6 — PWG-Pilot demo bootstrap & idempotency tests. Covers AC 11 + AC 12 of the PWG-Pilot plan: - ``PwgDemo2026.load()`` is idempotent (twice → no errors). - All expected objects exist after load (mandate, demo user, 4 feature instances, trustee seed data, imported pilot workflow with ``active=False``). - ``remove()`` cleans up cleanly and a subsequent ``load()`` rebuilds the demo without error (idempotency over the full lifecycle). Mirrors the structure of ``tests/demo/test_demo_bootstrap.py`` and reuses its session-scoped ``db`` fixture from ``tests/demo/conftest.py``. Marked ``expensive + live`` because they hit the real Postgres databases (``poweron_app``, ``poweron_trustee``, ``poweron_graphicaleditor``); run them explicitly with:: pytest -m "expensive or live" tests/demo/test_pwg_demo_bootstrap.py """ import pytest from modules.datamodels.datamodelFeatures import FeatureInstance from modules.datamodels.datamodelMembership import UserMandate from modules.datamodels.datamodelUam import Mandate, UserInDB from tests.demo.conftest import _getFeatureInstances pytestmark = [pytest.mark.expensive, pytest.mark.live] # --------------------------------------------------------------------------- # Fixtures (function-scoped so they always reflect current DB state) # --------------------------------------------------------------------------- @pytest.fixture(scope="session") def pwgDemoConfig(): """Auto-discovered ``PwgDemo2026`` instance.""" from modules.demoConfigs import getDemoConfigByCode cfg = getDemoConfigByCode("pwg-demo-2026") assert cfg is not None, ( "Demo config 'pwg-demo-2026' not found — check modules/demoConfigs/pwgDemo2026.py" ) return cfg @pytest.fixture def mandatePwg(db): records = db.getRecordset(Mandate, recordFilter={"name": "stiftung-pwg"}) assert records, "Mandate 'stiftung-pwg' not found — run pwgDemoConfig.load() first" return records[0] @pytest.fixture def pwgUser(db): records = db.getRecordset(UserInDB, recordFilter={"username": "pwg.demo"}) assert records, "User 'pwg.demo' not found — run pwgDemoConfig.load() first" return records[0] # --------------------------------------------------------------------------- # Bootstrap idempotency # --------------------------------------------------------------------------- class TestPwgDemoBootstrap: def test_loadIsIdempotent(self, db, pwgDemoConfig): """Loading the PWG demo twice in a row must not raise errors.""" s1 = pwgDemoConfig.load(db) assert len(s1.get("errors", [])) == 0, f"First load errors: {s1['errors']}" s2 = pwgDemoConfig.load(db) assert len(s2.get("errors", [])) == 0, f"Second load errors: {s2['errors']}" def test_credentialsAreSurfacedFromLoadSummary(self, db, pwgDemoConfig): s = pwgDemoConfig.load(db) creds = s.get("credentials") or [] assert any(c.get("username") == "pwg.demo" for c in creds), ( "PWG demo must surface 'pwg.demo' credentials so the SysAdmin " "doesn't have to grep source code for the password." ) def test_mandateStiftungPwgExists(self, db): records = db.getRecordset(Mandate, recordFilter={"name": "stiftung-pwg"}) assert len(records) == 1 assert records[0].get("label") == "Stiftung PWG" assert records[0].get("enabled") is True def test_pwgDemoUserExists(self, db): records = db.getRecordset(UserInDB, recordFilter={"username": "pwg.demo"}) assert len(records) == 1 user = records[0] assert user.get("email") == "pwg.demo@poweron.swiss" assert user.get("isSysAdmin") is True assert user.get("language") == "de" def test_pwgUserMembership(self, db, pwgUser, mandatePwg): memberships = db.getRecordset(UserMandate, recordFilter={ "userId": pwgUser.get("id"), "mandateId": mandatePwg.get("id"), }) assert len(memberships) >= 1, "PWG demo user not a member of Stiftung PWG" @pytest.mark.parametrize( "featureCode", ["workspace", "trustee", "graphicalEditor", "neutralization"], ) def test_pwgFeaturesExist(self, db, mandatePwg, featureCode): instances = _getFeatureInstances(db, mandatePwg.get("id"), featureCode) assert len(instances) >= 1, f"Feature '{featureCode}' missing in Stiftung PWG" def test_pwgFourFeatureInstances(self, db, mandatePwg): instances = db.getRecordset(FeatureInstance, recordFilter={ "mandateId": mandatePwg.get("id"), }) or [] codes = sorted({i.get("featureCode") for i in instances}) assert codes == ["graphicalEditor", "neutralization", "trustee", "workspace"], ( f"Expected exactly 4 feature instances, got {codes}" ) # --------------------------------------------------------------------------- # Trustee seed data — 5 fictitious tenants × 12 monthly bookings each # --------------------------------------------------------------------------- class TestPwgTrusteeSeed: def test_trusteeRentAccountExists(self, db, mandatePwg): from modules.features.trustee.datamodelFeatureTrustee import TrusteeDataAccount instances = _getFeatureInstances(db, mandatePwg.get("id"), "trustee") assert instances, "No trustee instance for PWG" instId = instances[0].get("id") from modules.demoConfigs.pwgDemo2026 import _openTrusteeDb trusteeDb = _openTrusteeDb() accounts = trusteeDb.getRecordset(TrusteeDataAccount, recordFilter={ "featureInstanceId": instId, "accountNumber": "6000", }) or [] assert len(accounts) == 1, f"Expected exactly 1 rent account 6000, got {len(accounts)}" assert accounts[0].get("isActive") is True def test_trusteeFiveTenants(self, db, mandatePwg): from modules.features.trustee.datamodelFeatureTrustee import TrusteeDataContact instances = _getFeatureInstances(db, mandatePwg.get("id"), "trustee") instId = instances[0].get("id") from modules.demoConfigs.pwgDemo2026 import _openTrusteeDb trusteeDb = _openTrusteeDb() contacts = trusteeDb.getRecordset(TrusteeDataContact, recordFilter={ "featureInstanceId": instId, }) or [] # Some installations may already have other trustee contacts, but the # 5 PWG seed tenants must be present. names = {c.get("name") for c in contacts} for expected in ( "Anna Müller", "Beat Schneider", "Carla Weber", "Daniel Frey", "Eva Lang", ): assert expected in names, f"PWG seed tenant '{expected}' missing" def test_trusteeMonthlyBookingsForTenant(self, db, mandatePwg): """Every tenant gets 12 monthly journal entries.""" from modules.features.trustee.datamodelFeatureTrustee import TrusteeDataJournalEntry instances = _getFeatureInstances(db, mandatePwg.get("id"), "trustee") instId = instances[0].get("id") from modules.demoConfigs.pwgDemo2026 import _openTrusteeDb trusteeDb = _openTrusteeDb() entries = trusteeDb.getRecordset(TrusteeDataJournalEntry, recordFilter={ "featureInstanceId": instId, }) or [] # 5 tenants × 12 months = 60; >= so reload doesn't false-fail. pwgEntries = [e for e in entries if (e.get("reference") or "").startswith("PWG-")] assert len(pwgEntries) >= 60, ( f"Expected >=60 PWG journal entries (5 tenants × 12 months), got {len(pwgEntries)}" ) # --------------------------------------------------------------------------- # Pilot workflow — imported envelope, must be active=False # --------------------------------------------------------------------------- class TestPwgPilotWorkflow: def test_pilotWorkflowImported(self, db, mandatePwg): from modules.features.graphicalEditor.datamodelFeatureGraphicalEditor import AutoWorkflow from modules.demoConfigs.pwgDemo2026 import _openGraphicalEditorDb instances = _getFeatureInstances(db, mandatePwg.get("id"), "graphicalEditor") assert instances, "No graphicalEditor instance for PWG" instId = instances[0].get("id") geDb = _openGraphicalEditorDb() wfs = geDb.getRecordset(AutoWorkflow, recordFilter={ "mandateId": mandatePwg.get("id"), "featureInstanceId": instId, "label": "PWG Pilot: Jahresmietzinsbestätigung", }) or [] assert len(wfs) == 1, f"Expected exactly 1 PWG pilot workflow, got {len(wfs)}" wf = wfs[0] # AC 10: imports must be inactive by default assert wf.get("active") is False, "PWG pilot workflow must be imported with active=false" graph = wf.get("graph") or {} assert (graph.get("nodes") or []), "PWG pilot workflow has no nodes" # --------------------------------------------------------------------------- # Lifecycle: remove + reload (mirrors investor demo TestDemoRemoveAndReload) # --------------------------------------------------------------------------- class TestPwgRemoveAndReload: def test_removeAndReload(self, db, pwgDemoConfig): """Remove the PWG demo, verify it is gone, then reload it.""" rs = pwgDemoConfig.remove(db) assert len(rs.get("errors", [])) == 0, f"Remove errors: {rs['errors']}" mandates = db.getRecordset(Mandate, recordFilter={"name": "stiftung-pwg"}) assert len(mandates) == 0, "Stiftung PWG mandate should be gone after remove" users = db.getRecordset(UserInDB, recordFilter={"username": "pwg.demo"}) assert len(users) == 0, "pwg.demo user should be gone after remove" ls = pwgDemoConfig.load(db) assert len(ls.get("errors", [])) == 0, f"Reload errors: {ls['errors']}" mandates = db.getRecordset(Mandate, recordFilter={"name": "stiftung-pwg"}) assert len(mandates) == 1, "Stiftung PWG must exist after reload"