diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99127c4..4e4c797 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: branches: [main] pull_request: branches: [main] + schedule: + # Nightly fork tests against testnet (issue #88). + - cron: '0 3 * * *' env: CARGO_TERM_COLOR: always @@ -259,3 +262,24 @@ jobs: with: name: coverage-lcov path: lcov.info + + # Scheduled fork tests against Stellar testnet (issue #88). + # Stubbed pending soroban-sdk ≥ 22.x upgrade; all tests are + # `#[ignore]`-d, so this job passes harmlessly until real fork- + # mode assertions land. + fork-test: + name: Fork Test (testnet nightly) + runs-on: ubuntu-latest + if: github.event_name == 'schedule' + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + target: wasm32-unknown-unknown + - name: Build WASM + run: cargo build --release --target wasm32-unknown-unknown + - name: Run fork tests (--ignored) + run: cargo test --features fork -- --ignored + env: + STELLAR_RPC_URL: https://soroban-testnet.stellar.org diff --git a/CHANGELOG.md b/CHANGELOG.md index 63e2c9c..c74dd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Fork test skeleton: `tests/fork.rs` with stubs for Soroban fork-mode testing against testnet, gated behind `--features fork` and `#[ignore]` until the SDK is upgraded to ≥ 22.x (Issue #88) +- `Cargo.toml`: `[features]` section with `fork = []` flag (Issue #88) +- CI: nightly `fork-test` job that runs `cargo test --features fork -- --ignored` once per night (Issue #88) +- README: fork-test documentation explaining prerequisites and how to run `cargo test --features fork` (Issue #88) - CI: `changelog` job that diffs `src/lib.rs`'s public API surface against the PR base and fails when `CHANGELOG.md` is not updated (Issue #112) - `scripts/check_changelog.sh` – the bash check invoked by the new job; reusable locally via `BASE_REF=origin/main HEAD_REF=HEAD bash scripts/check_changelog.sh` - `make check-changelog` – convenience target for running the check offline diff --git a/Cargo.toml b/Cargo.toml index c63c4ab..a055c80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,11 @@ soroban-sdk = "=21.7.7" soroban-sdk = { version = "=21.7.7", features = ["testutils"] } proptest = "1.4.0" +[features] +# Enable fork tests against Stellar testnet (requires RPC access). +# Usage: cargo test --features fork -- --ignored +fork = [] + [profile.release] opt-level = "z" overflow-checks = true diff --git a/README.md b/README.md index dc54b8a..c698891 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,19 @@ make lint make check # fmt + lint + test + wasm-build ``` +### Fork Tests (against testnet) + +Fork tests validate the contract against a forked snapshot of the Stellar +testnet. They are gated behind the `fork` feature and ignored by default. + +```bash +# Prerequisites: soroban-sdk ≥ 22.x, a testnet RPC endpoint +cargo test --features fork -- --ignored +``` + +These tests currently contain stubs pending the SDK upgrade to 22.x +(see `tests/fork.rs`). A CI job runs them nightly on schedule. + ### Deploy (testnet) ```bash diff --git a/tests/fork.rs b/tests/fork.rs new file mode 100644 index 0000000..070faf7 --- /dev/null +++ b/tests/fork.rs @@ -0,0 +1,87 @@ +//! # Soroban fork tests against Stellar testnet (issue #88) +//! +//! This module runs the same set of invariants as the unit tests in +//! `src/test.rs`, but against a **forked** testnet state rather than an +//! isolated `Env::default()` host. +//! +//! ## Why fork tests matter +//! +//! Soroban's emulated host is deterministic but not exhaustive. Fork tests +//! catch issues that only surface against real RPC behaviour, host-side +//! authorization verification, actual `symbol_short` truncations, and real +//! reclaim gas costs. +//! +//! ## Prerequisites +//! +//! Fork testing requires soroban-sdk ≥ 22.x (`test_snapshot` +//! infrastructure). This project currently pins soroban-sdk 21.7.7 for +//! stability (see `Cargo.toml`). **The fork tests are gated behind the +//! `fork` feature and ignored by default.** +//! +//! When the SDK is upgraded to 22.x (tracked in issue #88), replace the +//! stubs below with real fork-mode assertions. +//! +//! ## Running (post-upgrade) +//! +//! ```bash +//! export STELLAR_RPC_URL=https://soroban-testnet.stellar.org +//! cargo test --features fork -- --ignored +//! ``` + +// --------------------------------------------------------------------------- +// Stubs — TODO: replace with real fork tests after SDK 22.x upgrade +// --------------------------------------------------------------------------- + +/// Entry point: validate the deployed contract WASM against forked testnet +/// state. All concrete assertions live in the helper modules below. +#[test] +#[ignore = "Fork tests require soroban-sdk ≥ 22.x (see module-level docs)"] +#[cfg(feature = "fork")] +fn fork_invariants() { + // TODO(#88): Replace this stub with a real fork-mode test. + // + // Expected structure (soroban-sdk 22.x): + // ```rust,ignore + // let env = Env::from_snapshot_file("testnet-snapshot.json")?; + // env.register_contract_wasm_from_file("target/wasm32-unknown-unknown/release/stellar_tip.wasm"); + // // Replay the full unit-test invariant suite against forked state. + // ``` + // + // Until then, this test is `#[ignore]`-d so CI passes without a + // testnet RPC. +} + +/// Fork-mode test that replays registration invariants against testnet +/// state. +#[test] +#[ignore = "Fork tests require soroban-sdk ≥ 22.x"] +#[cfg(feature = "fork")] +fn fork_registration_invariants() { + // TODO(#88): register → assert profile exists → assert creator count. +} + +/// Fork-mode test that replays tipping invariants against testnet state. +#[test] +#[ignore = "Fork tests require soroban-sdk ≥ 22.x"] +#[cfg(feature = "fork")] +fn fork_tipping_invariants() { + // TODO(#88): tip → assert balance updated → assert tip recorded. +} + +/// Fork-mode test that replays withdrawal invariants against testnet +/// state. +#[test] +#[ignore = "Fork tests require soroban-sdk ≥ 22.x"] +#[cfg(feature = "fork")] +fn fork_withdrawal_invariants() { + // TODO(#88): withdraw → assert tokens transferred → assert balance zero. +} + +/// Fork-mode test that replays admin-rotation invariants against testnet +/// state. +#[test] +#[ignore = "Fork tests require soroban-sdk ≥ 22.x"] +#[cfg(feature = "fork")] +fn fork_admin_invariants() { + // TODO(#88): pause → rotate admin → set fee recipient → unpause → tip. +}