test(cketh): give the PocketIC server a longer lifetime than the suites - #11123
Draft
gregorydemay wants to merge 44 commits into
Draft
test(cketh): give the PocketIC server a longer lifetime than the suites#11123gregorydemay wants to merge 44 commits into
gregorydemay wants to merge 44 commits into
Conversation
Add a PocketIC-based test fixture (LedgerSuiteOrchestrator, AddErc20TokenFlow, ManagedCanistersAssert, UniversalCanister, new_pocket_ic()) alongside the existing StateMachine one in test_utils, and migrate tests/tests.rs to it. The StateMachine fixture stays untouched at its current paths since rs/ethereum/cketh still consumes it; it will be deleted once cketh migrates to PocketIC in a later PR of this stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
LedgerSuiteOrchestrator and ManagedCanistersAssert each carried an AsRef<PocketIc> impl left over from porting the StateMachine fixture, where it satisfied `T: AsRef<StateMachine>` bounds on stop_canister/ out_of_band_upgrade and a manual CanisterHttpQuery impl. Those call sites now take `&PocketIc` directly and go through PocketIcHttpQuery, so neither impl has a caller left (G9/G12). Addresses review comments: #10949 (comment) #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- mod.rs: replace 13 inline `crate::` paths (default_init_arg, the wasm
loaders, GIT_COMMIT_HASH, MAX_TICKS) with a single `use crate::{...}`
block, matching the plain `use crate::MINTER_PRINCIPAL;` style already used
in the sibling flow.rs. This also lets wait_for's panic message go back to
inline-capture ("...{MAX_TICKS} ticks...") instead of a positional arg.
- mod.rs: alias `ic_cdk::management_canister::CanisterStatusResult` as
`CdkCanisterStatusResult` to disambiguate it from the
`ic_management_canister_types::CanisterStatusResult` imported in the same
file, instead of spelling out the full path twice.
- flow.rs: import `ic_management_canister_types::CanisterId` instead of
fully qualifying it once, for the same reason mod.rs already imports it.
Addresses review comments:
#10949 (comment)
#10949 (comment)
#10949 (comment)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ledger_canister_status() returns an owned CanisterStatusResult temporary, so module_hash can be moved straight out of it instead of being cloned first (R3). Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment was carried over verbatim from the StateMachine fixture and still referenced "10ms per transfer with state machine tests" inside the module that specifically does not use StateMachine (C2). Dropping the parenthetical rather than guessing a PocketIC-specific number. Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
//:pocket-ic-server was listed in both `data` (needed for the $(rootpath //:pocket-ic-server) used by POCKET_IC_BIN) and `deps`. It's a runtime binary reached only through that env var, not linked, so `data` alone is the accurate declaration -- matching rs/ledger_suite/icp/BUILD.bazel (data only), as opposed to rs/bitcoin/checker and rs/dogecoin/ckdoge/minter (deps only, where the binary is invoked differently). Verified bazel test //rs/ethereum/ledger-suite-orchestrator:integration_tests still passes (POCKET_IC_BIN resolves fine from data alone). Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inline raw-transaction and transaction-hash string literals in minter/tests/cketh.rs were byte-identical to the DEFAULT_WITHDRAWAL_TRANSACTION and DEFAULT_WITHDRAWAL_TRANSACTION_HASH constants already exported by cketh/test_utils. Replace them with the constants so the upcoming PocketIC migration only needs to regenerate the signature in one place. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ocketIC Swap ic-state-machine-tests (and its transitive management-canister-types /ic-types/ic-cdk deps) for the sync pocket-ic client in rs/ethereum/cketh/test_utils and the minter's integration_tests target, and wire up the pocket-ic-server binary as test data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flip CkEthSetup and its helpers (mock.rs, flow.rs, ckerc20.rs) onto the
sync PocketIC client: builder uses with_fiduciary_subnet() with canister
execution rate limiting disabled, canisters are funded with
add_cycles(id, u128::MAX), and the minter is initialized with the
fiduciary subnet's "key_1" ECDSA key instead of the StateMachine-only
"master_ecdsa_public_key".
The ECDSA key change means the minter's Ethereum address changes, so
every signature-derived constant is regenerated: MINTER_ADDRESS,
DEFAULT_WITHDRAWAL_TRANSACTION(_HASH), DEFAULT_CKERC20_WITHDRAWAL_
TRANSACTION(_HASH), and the r/s of the default ERC20 signed transaction
in response.rs.
Canister-http mocking is rebuilt around PocketIC's get_canister_http() +
mock_canister_http_response() (replacing the StateMachine-specific manual
cleanup_response/transform dance), while preserving the legacy
"Http body exceeds size limit of {n} bytes." reject the minter's
is_response_too_large matches on. Polling for a specific outcall now also
tolerates ic-cdk-timers' per-timer concurrent-call cap: the block-height-
refresh timer and the log-scraping timer compete for it, and once hit, the
loser defers by a full REFRESH_LATEST_BLOCK_HEIGHT_INTERVAL that
nanosecond-granularity ticking alone can never cross.
Awaiting an update call now goes through a manual ingress_status polling
loop instead of PocketIC's own await_call, since the latter ticks up to
100 rounds with no opportunity to inject mock canister-http responses in
between.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adapt cketh.rs and ckerc20.rs to the PocketIC-backed test_utils API (error_code/reject_message instead of code()/description(), get_canister_ http() instead of canister_http_request_contexts(), stop_canister(id, None), Principal-based canister ids), and regenerate the few remaining signature/key-derivation-dependent literals inline in these test files: the per-account deposit-address in should_record_address_to_deposit and the resubmitted-transaction literal in should_resubmit_new_transaction_with_same_max_fee_per_gas_when_price_increased. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…odes Addresses review comments on PR #10955: - mock.rs:187 (medium, G5) - the fallback in `matches()` reimplemented `is_latest_block_refresh`, with a different malformed-body behaviour (`.expect(...)` vs. `Err(_) => false`). Collapse to `!is_latest_block_refresh(request)` and make the predicate `pub(crate)` so `lib.rs` can reuse the same implementation. - mock.rs:152 (medium) - `find_rpc_call_retrying`'s retry budget was 10 * REFRESH_LATEST_BLOCK_HEIGHT_INTERVAL (300s), more than SCRAPING_ETH_LOGS_INTERVAL (180s), so it could itself trigger an unrelated log scrape. Capped at 180s (6 attempts): 150s (5 attempts) was tried and left several tests unable to find their target call within budget, so the cap sits at the interval's exact boundary rather than strictly under it. - mock.rs:125 (nit, G25) - named the SysFatal/SysTransient reject-code literals instead of repeating a comment at each site. - poll_for_request's inline SysTransient reject block now calls the shared `reject_stray_http_outcall` (see next commit) instead of duplicating it (nit, G5). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses review comments on PR #10955: - lib.rs:885 (medium) - the single `await_call` bundled two policies: "await the message" and "answer every pending outcall with HTTP 500". `stop_minter` needs the draining; `WithdrawalFlow::minter_response`, `Erc20WithdrawalFlow::expect_trap` and `DepositErc20Flow::expect_trap` do not, since the drain could silently swallow an outcall one of those tests intended to stub itself. Split into `await_call` (which only clears stray latest-block-refresh outcalls - never a test-owned stub, see `mock::is_latest_block_refresh` - so it cannot swallow anything a test cares about) and `await_call_draining_outcalls` (the old blanket-500 behaviour), used only by `stop_minter`. - lib.rs:570 (medium) - `stop_ongoing_https_outcalls` returned as if it had succeeded even when it never managed to drain the pending outcalls. Panic instead, with the still-pending requests attached. - lib.rs:576 (medium, C2) - the comment on the same function pointed at `mock::tick_until_next_http_request`, which no longer exists (renamed to `JsonRpcRequestMatcher::poll_for_request` / `find_rpc_call_retrying`). Retargeted. - lib.rs:851 (medium, G5) - `drain_stray_latest_block_refresh_calls` had its own copy of the latest-block-refresh predicate, parsed as a raw `serde_json::Value` and `.unwrap()`-ed. Reuse `mock::is_latest_block_refresh` instead. - lib.rs:837 (nit) - `drain_startup_http_outcalls` and `drain_stray_latest_block_refresh_calls` burned their full tick budget even once the outcall queue was already empty. Added an early exit. - lib.rs:584 (nit, G5) - the HTTP-500 reply block in `drain_pending_https_outcalls` was byte-for-byte the one inside `await_call`. Extracted a shared `reply_500` helper. - lib.rs:881 (nit, C4) - the doc comment said "keeps rejecting" pending outcalls, but the code replies with an HTTP 500 (a different path through the minter than a canister-http reject). Reworded. - lib.rs:889 (nit, G25/G16) - `100 * MAX_TICKS` expressed 1000 as a multiple of an unrelated constant. Wrote the literal with a one-line rationale (this is a 100x relaxation of the `await_ingress(id, MAX_TICKS)` bound it replaces, needed because DTS can slice a large log-response over many more rounds than that). - lib.rs:538 (nit, G12) - `try_stop_minter_without_stopping_ongoing_ https_outcalls`'s 10-iteration loop was dead on the passing path (the first check returns immediately) and re-read a terminal status 9 more times on the failing path. Collapsed to a single tick + assert. - lib.rs:562 (Copilot) - `tick_until_minter_canister_status` re-read `minter_status()` without ever advancing a round itself, relying on `canister_status`'s own update-call processing to make progress. Added an explicit `tick()` so the loop doesn't depend on that incidental side effect. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses review comment on PR #10955: - ckerc20.rs:114 (nit, G11) - this is the only await in the suite that uses pocket-ic's built-in `await_call` instead of `ic_cketh_test_utils::await_call`. It is correct (the preceding `stop_ongoing_https_outcalls()` already guarantees, by panicking otherwise, that no outcall is left pending), but the asymmetry could otherwise lead the next reader to copy the wrong one. Added a comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…an enum Addresses re-review comments on PR #10955: - lib.rs:900 (nit) - the doc comment claimed no test-owned stub ever targets a latest-block-refresh outcall, but two stubs do (with an explicit `["latest", false]` param: tests/cketh.rs:842, tests/ckerc20.rs:258). They're safe because they're built and consumed synchronously before any await runs, not because of any exclusion. Reworded to say so, so a future test that interleaves such a stub with an awaited call doesn't get its request silently rejected out from under it. - lib.rs:925 (nit, F3/G15) - `poll_for_call`'s `drain_outcalls: bool` was a flag argument. Replaced with a two-variant `OutcallPolicy` enum (`RejectRefreshOnly` / `DrainAll`), matching the two named public wrappers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nothing in rs/ethereum consumes the old StateMachine-based fixture (lib.rs's LedgerSuiteOrchestrator, flow.rs, universal_canister.rs) now that both LSO and cketh integration tests run on PocketIC. Delete it and the now-unused ic-state-machine-tests, ic-types, and ic-management-canister-types-private dependencies, keeping only the environment-agnostic helpers (wasm loaders, init-arg builders, supported_erc20_tokens/usdc/usdt, constants) that the pocket_ic module and cketh still import at their existing paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the helpers PR #10955 added on top of the mechanical StateMachine -> PocketIC port that have no equivalent in the pre-migration fixture: drain_startup_http_outcalls, drain_stray_latest_block_refresh_calls, is_latest_block_refresh, the OutcallPolicy/await_call_draining_outcalls split, and find_rpc_call_retrying. Call sites fall back to the plain StateMachine-era equivalents (a single-pass stop_ongoing_https_outcalls, PocketIc::await_call, a 10-tick find_rpc_call poll). Integration test failures are expected and intentionally left unfixed: this branch is an analysis instrument to catalog which tests implicitly depended on the removed machinery, ahead of deciding whether to reintroduce explicit mocks instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CkEthSetup::new ended with an update call backing the MINTER_ADDRESS assertion. That call executes the rounds which let the minter's genesis timers fire, so every fixture-built test inherited eight canister-http outcalls pending at genesis time. Those requests cross PocketIC's 60s outcall timeout as soon as a test advances time, which is what the stripped fixture machinery was compensating for. Moving the assertion into its own test takes this branch from 3/26 to 20/27 passing without reintroducing any fixture machinery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
stop_minter answered the pending HTTPS outcalls in the same round it submitted the stop request, so the drain ran before the minter had left the Running state. The outcalls its timers issue in that last running round only become visible afterwards, and await_call offers no point at which a test can answer them, so the stop waited on eight call contexts that nobody could close. Ticking once between the two lets the stop take effect first. The minter issues no further outcalls while stopping, so a single drain pass then suffices. cketh_test goes from 20/27 to 24/27 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…calls Advancing time past CANISTER_HTTP_TIMEOUT_INTERVAL kills the outcalls still in flight, but get_canister_http keeps listing them until a round processes the timeouts. A stub could therefore bind to a request that is already dead and see its response discarded, leaving the request issued by the next scraping cycle unanswered. Ticking once before polling settles those requests first. The two block number stubs in should_panic_when_last_finalized_block_in _the_past also went unconstrained, so they could answer the block height refresh timer's query for the latest block instead of the finalized block the scraping cycle waits for. cketh_test goes from 24/27 to 25/27 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The minter derives its Ethereum address from a timer scheduled at install, so the address is only known once the canister has executed a few rounds. A freshly built fixture has executed none, which is what the deposit flow relies on: it expects to trigger the first scraping cycle itself. Ticking to derive the address beforehand costs that cycle to TimerGuard AlreadyProcessing and breaks the flow. Assert instead what holds at each point: no address before the minter has run, and the derived address after the deposit. The value itself stays covered by should_derive_minter_address. cketh_test goes from 25/27 to 26/27 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two block number stubs went unconstrained, so they could answer the block height refresh timer's query for the latest block and leave the finalized block the scraping cycle waits for unanswered. The scrape then never reached eth_getLogs. cketh_test is now fully green at 27/27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The deposit flow's block number stub went unconstrained, so it could answer the block height refresh timer's query for the latest block and leave the finalized block the scraping cycle waits for unanswered. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registering the ERC-20 tokens drives the minter through several rounds, so unlike the ckETH fixture the ckERC20 one hands over a minter that has a scraping cycle in flight. Advancing time then leaves that cycle holding the scraping TimerGuard, so the firing due at the new time is dropped as AlreadyProcessing and the expected block number query is never issued. Answering the query the pending cycle waits for lets it finish and release the guard. Responding with the block number already scraped keeps it from scraping logs nobody mocked. The block number stub that follows also went unconstrained and could answer the block height refresh timer's query instead of the finalized one. ckerc20_test goes from 22/40 to 37/40 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…line should_scrape_from_last_scraped_after_upgrade drives the scraping cycles itself instead of going through the deposit flow, so it needs the same handling: answer the query the cycle left in flight by the ckERC20 fixture before advancing time, otherwise that cycle still holds the scraping TimerGuard and the firing due at the new time is dropped. Its block number stubs also went unconstrained and could answer the block height refresh timer's query for the latest block. ckerc20_test goes from 37/40 to 38/40 passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ckETH fixture hands over a minter that has executed no round, so the deposit flow triggers the first scraping cycle itself and nothing is in flight when it advances time. The ckERC20 fixture registers its tokens through the orchestrator and therefore hands over a minter with a cycle already running, which still holds the scraping TimerGuard when the flow advances time, so the firing due then is dropped as AlreadyProcessing. Answer the query such a cycle waits for, and only then, so that flows starting from a fixture with nothing in flight keep expecting to trigger the first cycle themselves. ckerc20_test goes from 38/40 to 40/40 passing, cketh_test stays at 27/27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The PocketIC harness times out canister http requests and keeps listing them until a round processes the timeouts, and a scraping cycle left in flight holds the TimerGuard the next firing needs. Neither is visible from the code that works around them, so state the reasoning next to each tick, each settled cycle and each constrained block number stub. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…info should_derive_minter_address was inserted between the waiver and the test it belongs to, leaving the deprecated MinterInfo field that should_retrieve_minter_info asserts on uncovered. Cargo Lint Linux builds the test targets with -D warnings and rejected it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…meout Advancing time past the canister http timeout fails every outcall in flight, but the requests stay listed until a round processes the failures, and the cycle awaiting them keeps holding the scraping TimerGuard until it learns of them. A stub could therefore bind to a request that was already dead and see its response discarded, and the firing due at the new time was dropped as AlreadyProcessing. Route the advances through the fixture and do to those outcalls up front, and deterministically, what the advance would have done to them anyway. This replaces the three places that each answered the pending query on their own before advancing. Two details the flows depend on: nothing happens when no outcall is in flight, since a fixture that has executed no round expects to trigger the first scraping cycle itself; and a single round delivers the failures, where a second would let the timers fire before the advance. The block number stubs keep matching on the finalized block, which is what the scraping cycle actually queries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ching Advancing time now fails the outcalls in flight before it happens, so no dead request survives to be listed when a stub looks for its match and the poll no longer has anything to settle first. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-drop-state-machine
The StateMachine fixture had to address the management canister itself to upgrade a canister as its controller. PocketIc exposes that directly and builds the very same install_code argument, down to the install mode, so call it instead of assembling the argument by hand. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-drop-state-machine
…cket-ic # Conflicts: # Cargo.lock # rs/ethereum/cketh/test_utils/Cargo.toml # rs/ethereum/cketh/test_utils/src/ckerc20.rs
…-drop-state-machine
…-drop-state-machine
The server exits hard 10 minutes after it starts whatever the traffic, and every fixture in a test binary shares one server, so the clock runs against the whole suite rather than a single test. A single-threaded run of the ckERC20 suite takes about 8 of those 10 minutes, and losing the server mid-suite fails every test that follows instead of the one that is actually slow. PocketIcBuilder does not expose the lifetime, so start the server here and hand the builder its URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ixture" This reverts commit 00eaec4.
…fixture" This reverts commit 6e2ba6d.
…the suites" This reverts commit 191da42.
The server exits hard 10 minutes after it starts whatever the traffic, and every fixture in a test binary shares one server, so the clock runs against the whole suite rather than a single test. A single-threaded run of the ckERC20 suite takes about 8 of those 10 minutes, and losing the server mid-suite fails every test that follows instead of the one that is actually slow. PocketIcBuilder does not expose the lifetime, so start the server here and hand the builder its URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 12, 2026
pull Bot
pushed a commit
to bit-cook/ic
that referenced
this pull request
Aug 13, 2026
## 📚 PR stack 1. ~~dfinity#10949~~ — test(ledger-suite-orchestrator): migrate integration tests to PocketIC (merged) 2. ~~dfinity#10950~~ — test(cketh): deduplicate signed-transaction and transaction-hash literals (merged) 3. **dfinity#10955 — test(cketh): migrate integration tests to PocketIC** 👈 you are here 4. ~~dfinity#10956~~ — test(ledger-suite-orchestrator): drop the StateMachine test fixture — **its content is part of this PR**, see below Follow-up, based on this PR: dfinity#11123 (PocketIC server lifetime). ## Summary Flips `rs/ethereum/cketh/test_utils` and the minter's `cketh.rs`/`ckerc20.rs` integration tests from `ic-state-machine-tests` onto the sync `pocket_ic` client, following the pattern established for the ledger-suite-orchestrator in dfinity#10949. The minter is now initialized against the fiduciary subnet's `"key_1"` ECDSA key (StateMachine's `"master_ecdsa_public_key"` isn't available on PocketIC's fiduciary subnet), which changes the minter's derived Ethereum address. Every signature-derived constant is regenerated as a consequence: `MINTER_ADDRESS`, `DEFAULT_WITHDRAWAL_TRANSACTION(_HASH)`, `DEFAULT_CKERC20_WITHDRAWAL_TRANSACTION(_HASH)`, the r/s of the default ERC20 signed transaction, the per-account deposit address in `should_record_address_to_deposit`, and the resubmitted-transaction literal in `should_resubmit_new_transaction_with_same_max_fee_per_gas_when_price_increased`. Canister-http mocking is rebuilt around PocketIC's `get_canister_http()` / `mock_canister_http_response()`, preserving the legacy `"Http body exceeds size limit of {n} bytes."` reject that the minter's response-size check matches on. `tests/dump_stable_memory.rs` and `tests/deposit_from_cex_demo.rs` are untouched. ## Also included: dropping the StateMachine fixture from the orchestrator This was meant to be a separate PR (dfinity#10956) reviewed on top of this one. It was marked merged by mistake — see [the note there](dfinity#10956 (comment)) — and since GitHub cannot reopen a merged PR, its content stays here rather than being shuffled again. With the ckETH minter's tests on PocketIC, nothing in `rs/ethereum` uses the orchestrator's StateMachine-based fixture, so it is deleted along with the now-unused `ic-state-machine-tests`, `ic-types`, `ic-management-canister-types-private` and `assert_matches` dependencies. The environment-agnostic helpers the `pocket_ic` module and cketh still import (wasm loaders, init-arg builders, `usdc()`/`usdt()`, constants) stay at their existing paths. After this PR, no Rust target under `rs/ethereum` compiles against `ic-state-machine-tests`. ## Behavioural differences PocketIC forces, and how they are handled PocketIC differs from StateMachine in two ways the tests are sensitive to. Both are handled in the fixture, in one place each, rather than worked around per test. **Time advances kill the outcalls in flight.** PocketIC fails canister-http requests once they cross `CANISTER_HTTP_TIMEOUT_INTERVAL`; StateMachine left them pending indefinitely. The requests also stay listed until a round processes the failures, so a stub could bind to a request that was already dead and see its response discarded. Worse, a scraping cycle awaiting such a request keeps holding its `TimerGuard`, so the firing due at the new time is dropped as `AlreadyProcessing` and the query the test expects is never issued. `CkEthSetup::advance_time` therefore fails those outcalls up front and deterministically, doing what the advance would have done anyway. It is a no-op when nothing is in flight, because a fixture that has executed no round is expected to trigger the first scraping cycle itself. **A stop request takes effect only in the following round.** The outcalls the minter's timers issue in that last running round become visible after it, so `stop_minter` ticks once before draining them. The block number stubs also now match on `["finalized", false]`, which is what the scraping cycle actually queries — unconstrained, they could be consumed by the block height refresh timer's query for the latest block. ## Runtime Measured against master with identical in-test instrumentation on both sides: **+5% (ckETH) and +11% (ckERC20)** of wall-clock at default parallelism (+15%/+20% single-threaded). Fixture-light tests are indistinguishable from master; the difference tracks the number of IC rounds a test drives, since PocketIC runs out of process. The dominant cost in both harnesses is tests that rebuild the whole fixture several times within one `#[test]`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #10955, addressing this review comment.
Summary
The PocketIC server exits hard 10 minutes after it starts, whatever the traffic, and
PocketIcBuilderdoes not expose that lifetime. Since the builder starts the server withreuse: true, every fixture in a test binary shares one server, so the clock runs against the whole suite rather than a single test. A single-threaded run of the ckERC20 suite takes about 8 of those 10 minutes, and losing the server mid-suite fails every test that follows instead of the one that is actually slow.Start the server explicitly with a longer lifetime and hand the builder its URL.
Notes
The 600s default is
hard_ttl, notttl:ttlis an idle timeout that activity keeps resetting, whereashard_ttlis measured from launch and ignores traffic.This follows the approach of #11086, which adds an equivalent
long_lived_server_url()helper to this same crate for the sweeper tests. The shape and name here are deliberately identical so the two can be collapsed into one helper once that lands.🤖 Generated with Claude Code