9. Testing & Live Verification
9.1 Automated tests added
MultiTenancyApi (11 new tests):
TenantOperationalDefaultItemSeederShould(5) — embedded JSON loads 4 definitions (one per kind); insert-missing byCode; skip whenCodealready exists (never overwrites a non-blank admin value); fill only currently-blank fields; skip and report an invalidKindstring.TenantOperationalDefaultsServiceShould(6, SQLite-backedTenantDbContextfixture) — a Shumoul Starter-entitled tenant receives onlyWarehouse/CashAccount/SalesInvoiceTemplate(neverBankAccount); a Finance Starter-entitled tenant receives onlyCashAccount/BankAccount(neverWarehouse/SalesInvoiceTemplate); zero entitled kinds returns a blocked result and never calls the bridge; an unresolvable tenant returns blocked;Previewnever writes an apply log;Applywrites exactly one.
BackEnd (14 new tests):
TenantOperationalDefaultsProvisioningServiceTests(8) — creates all four kinds when none exist; skips existing and creates zero duplicates on a second apply; never creates a second default when an admin already created their own row of that kind (preserves the admin's value);DryRunwrites nothing;CashierAppsSettingsis only ever filled when currently null (an admin-set value is never overwritten);UserCashierSettingis seeded exactly once for the admin + first branch, never a second row on a later apply; tenant-resolution mismatch fails safely without writing; a structural guard confirms noCashAccountCurrency/BankAccountCurrency(GL-currency link) row is ever created.TenantOperationalDefaultsApplyInternalControllerTests(6) — the standard 401/403/400/200/502 sequence, mirroring every sibling internal-endpoint test suite.
9.2 Build/test results
| Repo | Command | Result |
|---|---|---|
| MultiTenancyApi | dotnet build (full solution) | 0 errors |
| MultiTenancyApi | dotnet test | 1152 total (was 1141), 1146 passed, 6 failed — identical pre-existing baseline, zero regressions |
| BackEnd | dotnet restore + dotnet build | 0 errors |
| BackEnd | dotnet test | 806 total (was 792), 771 passed, 35 failed — identical pre-existing baseline, zero regressions |
One transient regression was caught and fixed during this pass: adding
TenancyPermissions.TenantOperationalDefaults.{View,Apply} initially broke
MenuClaimsPermissionSyncTests.MenuClaimsJson_ContainsEveryTenancyPermissionsValue (a real regression
test that checks every TenancyPermissions constant has a corresponding MenuClaims.json entry) — fixed
by adding the matching Permissions.TenantOperationalDefaults controller/action entries to
MenuClaims.json, restoring the exact 35-failure baseline.
9.3 Live manual verification (dev, this phase)
A fresh Shumoul Starter tenant was registered, activated, logged in, and taken through onboarding
(RestaurantCafe profile) with both OnboardingApplyBridgeSettings and
TenantOperationalDefaultsApplyBridgeSettings enabled via dev-only environment variables (matching the
Onboarding Apply Bridge
guide's setup pattern):
| Step | Result |
|---|---|
| First apply attempt | Package version mismatch caught the local NuGet package hadn't been re-released after the last MultiTenancyApi source edit — re-released (Shumoul.Framework.MultiTenancy.Api 1.0.121), BackEnd rebuilt, retried |
apply (real, first time) | 200 — bridge called, TotalRequestedKinds=3 (Starter: no BankAccount), CreatedCount=2 (CashAccount, SalesInvoiceTemplate — zero prior seed logic), SkippedExistingCount=1 (Warehouse — already existed from SeedWarehousesAsync), FailedCount=0 |
| Warning returned | "BankAccount default was skipped — tenant does not have any of the required subscription feature entitlements (Features.AccountManagement)." — exact, specific, non-vague |
GET api/v1/AppSettings/GetCashierApps | warehouseId, cashAccountId, salesInvoiceTemplateId all populated with the exact Ids from the apply log; bankAccountId correctly absent |
GET api/v1/onboarding/status | isRequired: false, status: "Applied" — dashboard-ready |
| Second apply (regenerate + apply again) | 200 — CreatedCount=0, SkippedExistingCount=3 — zero duplicates, confirmed via the TenantOperationalDefaultApplyLogs history |
| Reference-data de-gating side effect | Observed running (insert-missing, Inserted=0) against several pre-existing tenant databases at the same host startup, with zero errors — see Chapter 8 §8.3 |
No stock quantities, opening balances, inventory transactions, stock movements, GL accounts, vouchers, or journal entries were created at any point — confirmed both structurally (the provisioning service's code never references those entities) and by the automated guard test in §9.1.
9.4 Incident note — test phone number safety
During this verification, an incorrectly-assumed-safe phone number (chosen by incrementing a previously-used test number, not confirmed unused) turned out to belong to a real person, who received a real WhatsApp/SMS registration notification and complained. The affected tenant was immediately deactivated (not deleted — a reversible status flag). Lesson for future sessions: dev-environment notification credentials can be genuinely live and deliver real messages — never guess or increment a test phone number; always use an explicitly confirmed-safe number.
