Testing & Reproducibility
Every core behaviour of OhShii — creating a Liquidity Generation Event (LGE), buying into one, creating and voting on governance proposals, upgrading a canister by vote, and the identity-verification gate — is covered by an automated end-to-end test suite that anyone in the DAO can run from a clone of the repository. The tests exercise the real production code paths inside a faithful local replica of the network, so a green run is meaningful evidence that a change behaves the way it will on mainnet.
This page explains what the suites verify, how to reproduce each one, how to drive the same flows interactively, and — importantly — the guarantees that keep the test-only tooling from ever reaching a mainnet build.
The local world the tests run against
Section titled “The local world the tests run against”The tests boot a PocketIC world (a deterministic, in-process replica of the Internet Computer) that installs the launcher and locker canisters at their real mainnet ids, alongside real system canisters (the ICP ledger, the Cycles Minting Canister, Internet Identity) and the real ICPSwap V3 stack. See Local Test Environment for standing the world up interactively; this page is about the automated suites and the simulator that run on top of it.
The harness lives in test-env/harness/ and is a standalone Rust workspace,
deliberately separate from the production workspace so the reproducible build is
never affected by test dependencies.
Running the suites
Section titled “Running the suites”The one-command form builds the canisters and runs the whole suite:
npm run testenv:testTo run an individual suite (from test-env/harness/), and rebuild the canister
WASMs first when you have changed canister code:
cd test-env/harness
# Rebuild WASMs before running (needed after any canister change):OHSHII_TESTENV_BUILD=1 cargo test --test lge_participation -- --nocapture
# Reuse the already-built WASMs (faster, no rebuild):cargo test --test ons_proposal_lifecycle -- --nocapturecargo test --test sons_proposal_lifecycle -- --nocapturecargo test --test verification_gating -- --nocaptureEach suite boots its own isolated world and takes roughly one to two minutes.
What each suite verifies
Section titled “What each suite verifies”LGE participation — lge_participation
Section titled “LGE participation — lge_participation”Drives the real purchase flow (an ICRC-2 approval followed by the backend’s
purchase_tokens_icrc2) across the Voter Benefit Protocol tiers, and checks
that:
- verified buyers in each tier receive tokens and a contribution is recorded;
- the OHSHII guest fee for unverified buyers is charged at most once per campaign — including the real-world edge where, at the start of the bonding curve, the Guest tier’s token cap costs less than the minimum purchase, so a Guest is temporarily unable to participate until the price rises;
- the per-caller payment rate limit engages on a burst and recovers afterwards.
ONS proposal lifecycle — ons_proposal_lifecycle
Section titled “ONS proposal lifecycle — ons_proposal_lifecycle”Exercises the OHSHII (ONS) governance canister end to end:
- a Motion reaches quorum and is finalized by the on-chain timer, while a second Motion without enough voters expires;
- the chunked WASM upload path — a multi-megabyte module is uploaded across many chunks and the canister-reassembled hash is verified against the local hash;
- a canister-upgrade proposal is created, driven to immediate approval, executed, and the target canister’s installed module hash is checked against the proposed WASM.
SONS proposal lifecycle — sons_proposal_lifecycle
Section titled “SONS proposal lifecycle — sons_proposal_lifecycle”The same, for a per-campaign (SONS) governance canister created for an imported DAO or an LGE: a configuration-change proposal that is voted and executed, a child-canister upgrade, and the verification gate — a SONS configured to require verification rejects an unverified proposer, then accepts them after they verify, exercising the cross-canister call from SONS to ONS that checks personhood.
Verification gating — verification_gating
Section titled “Verification gating — verification_gating”Confirms the World ID / DecideID gate behaves correctly: when either method is enabled an unverified voter is rejected and a verified one is accepted (the gate is the logical OR of the two methods), and that a freshly installed governance canister converges on the verification modes currently active on mainnet after an upgrade, while never overriding a configuration an operator or the DAO has deliberately set.
Two further suites cover related surfaces: lge_creation_slot (LGE and
imported-DAO creation, payment-memo and slot-allocation hardening) and the
asset-batch cleanup suites for both governance canisters.
Simulating flows against a live world
Section titled “Simulating flows against a live world”For interactive testing, a live world can be driven with the same real flows. Multi-participant scenarios (many buyers, many voters) cannot come from a single browser wallet, so they are issued through a small command-line tool that talks to the running world directly:
npm run testenv # start the live worldnpm run testenv:sim -- plan dao-0000000012 --to-percent 60npm run testenv:sim -- quote dao-0000000012 --amount-icp 1 --tier humannpm run testenv:sim -- participants dao-0000000012 --n 5 --tier guestnpm run testenv:sim -- participants dao-0000000012 --n 30 --mode burst --freshnpm run testenv:sim -- proposal ons motion "adopt the thing"npm run testenv:sim -- wasm listnpm run testenv:sim -- vote ons 1 --immediatenpm run testenv:sim -- execute ons 1npm run testenv:sim -- status ons 1./test-env/sim.sh help # full command listThe simulator is diagnostic, not just a runner:
planstarts from the goal instead of the knobs: state the completion level the campaign should reach and it resolves that into a concrete cohort — how many participants, which participation tier, and how much ICP each — from the live bonding curve, then previews it. Nothing is bought until the plan is confirmed. It also reports when the participant budget, not the target, is the binding constraint.quoteis a curve-accurate pre-flight. It reads the campaign’s live bonding-curve position and reports how many tokens a chosen ICP amount buys now, the tier’s purchase cap, the remaining headroom, and the maximum ICP that fits the cap — so you choose a valid amount instead of guessing. Purchase caps are denominated in tokens, so at the start of the curve a small tier’s cap can be reached with very little ICP; the quote makes that explicit. Tiers are earned, not bought: the capital tiers also require voting discipline, so a simulated participant is given both the voting power and the ballots that keep it an active voter — otherwise the platform correctly demotes it and enforces the lower cap (the quote reports the demotion when it happens).participantsreports each buyer on its own line, classified as success, tier-cap rejection, rate-limit, high-load (proof-of-work) rejection, or below-minimum, with a summary of counts and total ICP spent. A sequential run paces the buyers; a burst run submits every purchase at once, which is how you exercise the platform’s in-canister rate-limiting and high-load defences under real concurrency.--freshgives each run brand-new participants so earlier runs don’t skew the per-participant cap accounting.wasm listshows the upgrade payloads available for an upgrade-by-vote test. Every payload is read and scanned server-side before it can be attached to a proposal; a payload carrying a development-only method is refused up front (the on-chain governance check would reject it too).
The same commands are also reachable from the launcher UI when it runs against a local world: a small floating bubble in the bottom-left corner opens a development-only panel — participation on a campaign page, proposals and voting on the governance page, environment controls on the wallet page — and closes it again, so the interface otherwise looks exactly like production. None of this tooling is present in a production build.
The no-backdoor guarantee (why the test tooling is safe)
Section titled “The no-backdoor guarantee (why the test tooling is safe)”To make local testing practical, the test build compiles in development-only
methods — most importantly one that lets a caller grant itself admin rights, and
methods that mark a principal as verified without the real proof-of-personhood
flow. These are gated behind a Cargo feature (dev-admin) and are compiled
out of every production build. This matters for a DAO, so the codebase
guards it in four independent layers rather than trusting a single check:
- Build isolation. The development build is written to a separate output directory, never to the path a mainnet deployment installs from.
- Compile-time opt-in. Every affected canister contains a block that fails to compile unless an explicit environment opt-in is set, so the feature flag alone cannot produce a backdoored module.
- Artefact scan.
scripts/check_no_dev_admin.pyreads a compiled WASM’s export section and fails if any development method is present. It runs in the Docker build, the deploy scripts, and the voter-side proposal verification. - On-chain gate. Both governance canisters scan any WASM proposed for upgrade and reject it if it exports a development method — the one layer a proposer cannot bypass, enforced under consensus.
Note that this applies to every OhShii canister that carries the feature,
including sons_governance (the per-campaign governance canister). A test that
proposes a canister upgrade therefore has to use a clean WASM as the payload —
the on-chain gate rejects anything else — which is exactly the discipline the
upgrade suites follow.
Verifying a released canister yourself
Section titled “Verifying a released canister yourself”Anyone can check that a canister running on mainnet was built from a specific, reviewed source, and that its module carries no development methods:
# 1. On-chain module hash equals the local reproducible build:scripts/verify-hash.sh ic <canister-name>
# 2. That same local build carries no development-only methods:python3 scripts/check_no_dev_admin.py <path-to-local-build.wasm>A matching hash proves provenance (the running code was built from the source you reviewed); the scan proves the content carries no test methods. Neither can, on its own, detect a hand-edited authorization check hidden in the source — only a reproducible build bound to a reviewed commit gives that assurance. The Voter Verification Guide and the Docker Deploy Guide cover the reproducible-build chain in full.