Sails Gtest
Goal
Run the Sails-first test loop with generated clients and explicit gtest evidence before any live-node smoke step.
Inputs
../../assets/gtest-report-template.md— report format for gtest results../../references/gtest-cheatsheet.md— quick reference for gtest APIs../../references/gtest-patterns.md— common test patterns../../references/sails-cheatsheet.md— Sails patterns and APIs../../references/sails-gtest-and-local-validation.md— full gtest and validation guide../../references/gear-gas-reservations-and-waitlist.md— gas reasoning for tests../../references/scale-binary-decoding-guide.md— decoding raw reply bytes../../references/sails-syscall-mapping.md—Syscall::*API for gas, message, and execution context
Write the result to docs/plans/YYYY-MM-DD-<topic>-gtest.md.
Expected Loop
- Confirm the implementation target is ready for verification.
- Use generated clients or
GtestEnvinstead of hand-built payloads where the workspace supports them. - If the test must go below generated clients, first decide whether the payload or reply bytes are Sails-routed, plain SCALE, or metadata-driven state output; then apply the raw mental model:
send_bytes*returns aMessageId,run_next_blockreturns theBlockRunResult, and the reply evidence lives in the block result. - Pick the right
BlockRunModeand advance blocks explicitly when replies or deferred effects depend on progression. - Use
run_to_blockwhen delayed work or timeout behavior spans multiple blocks. - Assert behavior, replies, events, or accounting in the test result, not just compilation.
- Record failure mode, fix, and passing command output in the gtest note.
- Route to
../sails-local-smoke/SKILL.mdonly after the suite is green.
Common Pitfalls
Rust 2024 listener lifetime: Under edition 2024 capture rules, chaining generated-client calls into
listen()can fail with "temporary value dropped while borrowed". In Sails 1.0 the service client implementsListenerdirectly, so bind the service client before listening:let client = program.service_name(); let mut events = client.listen().await.unwrap();Program balance accounting in gtest: The deployed program account has an existential deposit. Absolute balance assertions like
== wageror== 0will fail even when the contract accounting logic is correct. Capture the initial balance after deploy and assert deltas relative to that baseline:let initial_balance = env.balance_of(program_id); // ... perform actions ... let final_balance = env.balance_of(program_id); assert_eq!(final_balance - initial_balance, expected_delta);Missing block advancement: Forgetting to call
run_next_blockafter sending a message means the reply is never processed. Always advance at least one block after send operations that expect replies.
Guardrails
- Do not use green
cargo testoutput without Sails-appropriate assertions as proof. - Do not start local-node smoke while
gtestis still red. - Do not skip gas or value reasoning when tests depend on it.
- Do not decode raw reply or event bytes as a bare business DTO until you have checked whether Sails routing framing is present.
- Use
#[sails_type]for test-only types that mirror service types, ensuring encoding/decoding matches on-chain behavior exactly.