From 692d57f093019038efcafe0cba8356143b757ca2 Mon Sep 17 00:00:00 2001 From: thlpkee20-wq Date: Tue, 28 Jul 2026 18:58:09 +0530 Subject: [PATCH] test(settlement): cover the settle_all MAX_SETTLE_ALL boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit record_usage caps the per-agent service index at MAX_AGENT_SERVICE_INDEX (== MAX_SETTLE_ALL), so settle_all's SettleAllTooLarge guard had zero test coverage: it can't be reached through the public API alone (it exists to protect a future migration that could write a larger index). Added two tests that write an oversized index directly via `as_contract`, mirroring the existing `..._via_storage_helper` pattern: - exactly-at-boundary (256 services): succeeds, settles all of them. - one-over-boundary (257 services): panics with SettleAllTooLarge (#19). Note: the exactly-at-boundary test needs env.budget().reset_unlimited() — settling 256 services in one call (2 storage reads + 2 writes + 1 event each) exceeds the default test budget around service #178. This is a test-harness-only accommodation, but it's a real signal: a settle_all call anywhere near the configured MAX_SETTLE_ALL would likely also exceed real network resource limits on-chain. Worth a follow-up look at whether MAX_SETTLE_ALL should be tightened, separate from this test-coverage change. --- contracts/escrow/src/test.rs | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/contracts/escrow/src/test.rs b/contracts/escrow/src/test.rs index 485cad5..25d0bf7 100644 --- a/contracts/escrow/src/test.rs +++ b/contracts/escrow/src/test.rs @@ -1902,6 +1902,64 @@ fn test_settle_all_panics_paused_via_shared_helper() { client.settle_all(&admin, &agent); } +// ── settle_all MAX_SETTLE_ALL boundary ───────────────────────────────────── +// +// record_usage caps the per-agent service index at MAX_AGENT_SERVICE_INDEX, +// which equals MAX_SETTLE_ALL, so the SettleAllTooLarge guard in settle_all +// can never fire through the public API alone — it exists to protect a +// future migration that could write a larger index. These tests exercise +// the guard directly by writing an oversized index via `as_contract`, +// bypassing the normal write path the way the existing +// `..._via_storage_helper` tests already do for other invariants. + +#[test] +fn test_settle_all_at_exactly_max_settle_all_succeeds() { + let env = Env::default(); + let (client, admin) = setup_initialized(&env); + let agent = Address::generate(&env); + // Settling 256 services in one call is exactly the kind of large batch + // the default test budget isn't sized for; this only relaxes the test + // harness's metering, not the contract's own MAX_SETTLE_ALL guard. + env.budget().reset_unlimited(); + + env.as_contract(&contract_address_from_client(&client), || { + let mut index: Vec = Vec::new(&env); + let mut buf = [0u8; 8]; + for i in 0..MAX_SETTLE_ALL { + index.push_back(Symbol::new(&env, svc_name(&mut buf, i))); + } + assert_eq!(index.len(), MAX_SETTLE_ALL); + env.storage() + .persistent() + .set(&DataKey::AgentServiceIndex(agent.clone()), &index); + }); + + let results = client.settle_all(&admin, &agent); + assert_eq!(results.len(), MAX_SETTLE_ALL); +} + +#[test] +#[should_panic(expected = "Error(Contract, #19)")] +fn test_settle_all_one_over_max_settle_all_panics() { + let env = Env::default(); + let (client, admin) = setup_initialized(&env); + let agent = Address::generate(&env); + env.budget().reset_unlimited(); + + env.as_contract(&contract_address_from_client(&client), || { + let mut index: Vec = Vec::new(&env); + let mut buf = [0u8; 8]; + for i in 0..(MAX_SETTLE_ALL + 1) { + index.push_back(Symbol::new(&env, svc_name(&mut buf, i))); + } + env.storage() + .persistent() + .set(&DataKey::AgentServiceIndex(agent.clone()), &index); + }); + + client.settle_all(&admin, &agent); +} + #[test] fn test_list_open_disputes_returns_empty_for_agent_without_disputes() { let env = Env::default();