Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 37 additions & 31 deletions .github/workflows/native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ jobs:
# that by construction — no substring matching, no path-segment trickery,
# so siblings like "alternative/" can never enter the build list.
function get_projects() {
find . -type d -name "native" | grep -vE "$ignore_pattern" | sort
# An empty .ghaignore makes ignore_pattern empty, and `grep -vE ""`
# matches everything, silently emptying the project list - only
# filter when there is actually a pattern.
if [[ -n "$ignore_pattern" ]]; then
find . -type d -name "native" | grep -vE "$ignore_pattern" | sort
else
find . -type d -name "native" | sort
fi
}

# Filter the full project list down to projects touched by the given
Expand Down Expand Up @@ -158,12 +165,6 @@ jobs:
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v5
with:
node-version: 'lts/*'
check-latest: true
- name: Setup build environment
id: setup
run: |
Expand All @@ -175,40 +176,45 @@ jobs:
echo "Building and Testing $project with Solana $solana_version"
cd "$project" || return 1

# Install dependencies
if ! pnpm install --frozen-lockfile; then
echo "::error::pnpm install failed for $project"
echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
# Collect program manifests: single-program projects use program/,
# multi-program projects (e.g. cross-program-invocation) use programs/*/.
local manifests=()
if [ -d "program" ]; then
manifests=("./program/Cargo.toml")
elif [ -d "programs" ]; then
for manifest in programs/*/Cargo.toml; do
manifests+=("./$manifest")
done
fi

# Build
if ! pnpm build; then
echo "::error::build failed for $project"
echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
if [ ${#manifests[@]} -eq 0 ]; then
echo "::error::no program manifest found for $project"
echo "$project: no program manifest found with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi

# Test
if ! pnpm build-and-test; then
echo "::error::tests failed for $project"
echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
# Build the .so files first: the Rust + LiteSVM tests embed them
# at compile time via include_bytes!, so the tests cannot even
# compile without a build, and a stale .so would test old code.
for manifest in "${manifests[@]}"; do
if ! cargo build-sbf --manifest-path="$manifest"; then
echo "::error::build failed for $project ($manifest)"
echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
done

# Run Rust unit tests
if [ -d "program" ]; then
echo "Running Rust unit tests for $project"
if ! cargo test --manifest-path=./program/Cargo.toml; then
echo "::error::Rust unit tests failed for $project"
echo "$project: Rust unit tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
# Run the Rust + LiteSVM tests
for manifest in "${manifests[@]}"; do
if ! cargo test --manifest-path="$manifest"; then
echo "::error::tests failed for $project ($manifest)"
echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
fi
done

echo "Build and tests succeeded for $project with $solana_version version."
cd - > /dev/null
Expand Down
68 changes: 37 additions & 31 deletions .github/workflows/pinocchio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ jobs:
# trickery, so siblings like "pinocchio-example/" can never enter the
# build list.
function get_projects() {
find . -type d -name "pinocchio" | grep -vE "$ignore_pattern" | sort
# An empty .ghaignore makes ignore_pattern empty, and `grep -vE ""`
# matches everything, silently emptying the project list - only
# filter when there is actually a pattern.
if [[ -n "$ignore_pattern" ]]; then
find . -type d -name "pinocchio" | grep -vE "$ignore_pattern" | sort
else
find . -type d -name "pinocchio" | sort
fi
}

# Filter the full project list down to projects touched by the given
Expand Down Expand Up @@ -159,12 +166,6 @@ jobs:
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock') }}
restore-keys: |
cargo-${{ runner.os }}-
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
check-latest: true
- name: Setup build environment
id: setup
run: |
Expand All @@ -176,40 +177,45 @@ jobs:
echo "Building and Testing $project with Solana $solana_version"
cd "$project" || return 1

# Install dependencies
if ! pnpm install --frozen-lockfile; then
echo "::error::pnpm install failed for $project"
echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
# Collect program manifests: single-program projects use program/,
# multi-program projects (e.g. cross-program-invocation) use programs/*/.
local manifests=()
if [ -d "program" ]; then
manifests=("./program/Cargo.toml")
elif [ -d "programs" ]; then
for manifest in programs/*/Cargo.toml; do
manifests+=("./$manifest")
done
fi

# Build
if ! pnpm build; then
echo "::error::build failed for $project"
echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
if [ ${#manifests[@]} -eq 0 ]; then
echo "::error::no program manifest found for $project"
echo "$project: no program manifest found with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi

# Test
if ! pnpm build-and-test; then
echo "::error::tests failed for $project"
echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
# Build the .so files first: the Rust + LiteSVM tests embed them
# at compile time via include_bytes!, so the tests cannot even
# compile without a build, and a stale .so would test old code.
for manifest in "${manifests[@]}"; do
if ! cargo build-sbf --manifest-path="$manifest"; then
echo "::error::build failed for $project ($manifest)"
echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
done

# Run Rust unit tests
if [ -d "program" ]; then
echo "Running Rust unit tests for $project"
if ! cargo test --manifest-path=./program/Cargo.toml; then
echo "::error::Rust unit tests failed for $project"
echo "$project: Rust unit tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
# Run the Rust + LiteSVM tests
for manifest in "${manifests[@]}"; do
if ! cargo test --manifest-path="$manifest"; then
echo "::error::tests failed for $project ($manifest)"
echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
fi
done

echo "Build and tests succeeded for $project with $solana_version version."
cd - > /dev/null
Expand Down
52 changes: 18 additions & 34 deletions .github/workflows/solana-asm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ jobs:
# anything containing the substring "asm" (e.g. "wasm/", "plasma/") can
# never enter the build list.
function get_projects() {
find . -type d -name "asm" | grep -vE "$ignore_pattern" | sort
# An empty .ghaignore makes ignore_pattern empty, and `grep -vE ""`
# matches everything, silently emptying the project list - only
# filter when there is actually a pattern.
if [[ -n "$ignore_pattern" ]]; then
find . -type d -name "asm" | grep -vE "$ignore_pattern" | sort
else
find . -type d -name "asm" | sort
fi
}

# Filter the full project list down to projects touched by the given
Expand Down Expand Up @@ -129,17 +136,6 @@ jobs:
failed_projects: ${{ steps.set-failed.outputs.failed_projects }}
steps:
- uses: actions/checkout@v4
# The previous `npm install --global pnpm` step picked up a pnpm release that
# treats ignored build scripts (bufferutil, utf-8-validate) as a hard error and
# fails `pnpm install --frozen-lockfile`. The other workflows (anchor, native,
# pinocchio, typescript) use pnpm/action-setup@v4, which pins a known-good pnpm
# release (10.33.0 at time of writing) that only warns. Match that here.
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
check-latest: true
- name: Setup build environment
id: setup
run: |
Expand All @@ -151,33 +147,24 @@ jobs:
echo "Building and Testing $project with Solana $solana_version"
cd "$project" || return 1

# Install dependencies
if ! pnpm install --frozen-lockfile; then
echo "::error::pnpm install failed for $project"
echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
# Build the .so into deploy/: the Rust + LiteSVM tests embed it at
# compile time via include_bytes!, so the tests cannot even compile
# without a build, and a stale .so would test old code.
if ! sbpf build; then
echo "::error::sbpf build failed for $project"
echo "$project: sbpf build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi

# Build and Test
if ! pnpm build-and-test; then
echo "::error::build-and-test failed for $project"
echo "$project: build-and-test failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
# Run the Rust + LiteSVM tests (inline in src/lib.rs)
if ! cargo test --manifest-path=./Cargo.toml; then
echo "::error::tests failed for $project"
echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi

# Run Rust unit tests
if [ -d "program" ]; then
echo "Running Rust unit tests for $project"
if ! cargo test --manifest-path=./program/Cargo.toml; then
echo "::error::Rust unit tests failed for $project"
echo "$project: Rust unit tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
cd - > /dev/null
return 1
fi
fi

echo "Build and tests succeeded for $project with $solana_version version."
cd - > /dev/null
return 0
Expand Down Expand Up @@ -212,9 +199,6 @@ jobs:
# Make the script executable
chmod +x build_and_test.sh

# pnpm is installed by pnpm/action-setup@v4 above. Avoid `npm install --global pnpm`
# here because that resolves to pnpm 10+, which errors on ignored build scripts.

# Install sbpf assembler
cargo install --git https://github.com/blueshift-gg/sbpf.git
- name: Setup Solana Stable
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ All notable changes to this repository are documented here.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [2026-06-12] - Rust + LiteSVM tests everywhere

### Changed

- All native, Pinocchio, and ASM examples are now tested exclusively with Rust + LiteSVM. The web3.js v1 / solana-bankrun / ts-mocha TypeScript test suites (which duplicated existing Rust tests) were removed, along with their `package.json`, `pnpm-lock.yaml`, and `tsconfig.json` files and the `ts/` client directories.
- Rust tests now load the program binary from the workspace `target/deploy/` (built with `cargo build-sbf --manifest-path=./program/Cargo.toml`) instead of per-project `tests/fixtures` directories. Committed foreign-program fixtures (e.g. `mpl_token_metadata.so`) stay where they were.
- ASM examples standardized on `sbpf build`'s default `deploy/` output directory; their inline LiteSVM tests load from there.
- `tools/shank-and-codama` now generates a Rust client (`@codama/renderers-rust`) instead of a TypeScript one, wrapped in the `car-rental-service-client` crate, and its tests are Rust + LiteSVM under `program/tests/`.
- `transfer-hook/block-list` gained a Rust + LiteSVM lifecycle test (`program/tests/`) driving the program through its Codama-generated Rust SDK; the mocha/web3.js test was removed. Its `package.json` now only covers SDK generation.
- CI (`native.yml`, `pinocchio.yml`, `solana-asm.yml`) no longer installs Node/pnpm; it builds with `cargo build-sbf` (or `sbpf build`) and tests with `cargo test`.

### Added

- `basics/hello-solana/pinocchio` Rust + LiteSVM test (it previously had only a TypeScript test).

## [2026-04-08] - Quicknode fork modernization (Mike MacCana)

Mike MacCana led the Quicknode fork of the [Solana Foundation program examples](https://github.com/solana-developers/program-examples) from late 2025. The first commits on this repository lineage are dated **8 April 2026**; the summary below covers that work through the initial merge.
Expand Down
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ Optional helpers come from the [`solana-kite`](https://crates.io/crates/solana-k

**Quasar examples** are tested in Rust with QuasarSVM. Run `quasar build` (which also generates the Rust client crate under `target/client/rust/` that the tests import), then `quasar test` or `cargo test`.

**Native and Pinocchio examples** use `litesvm` directly from Rust, except for a few that keep TypeScript tests (`tsx --test` with [`solana-kite`](https://solanakite.org) and [`@solana/kit`](https://solanakit.com)) where the example is specifically about client-side tooling.
**Native and Pinocchio examples** use `litesvm` directly from Rust. Tests live in `program/tests/`, load the compiled program with `include_bytes!` from the workspace `target/deploy/`, and run with `cargo test --manifest-path=./program/Cargo.toml` (build the `.so` first with `cargo build-sbf --manifest-path=./program/Cargo.toml`).

Do not write TypeScript tests for Anchor or Quasar programs, and do not use `anchor.workspace` or `program.methods.X().rpc()`.
**ASM examples** keep their LiteSVM tests inline in `src/lib.rs`; build with `sbpf build`, test with `cargo test`.

Do not write TypeScript tests for any program, and do not use `anchor.workspace` or `program.methods.X().rpc()`. All tests are Rust + LiteSVM (QuasarSVM for Quasar).

Tests must exercise the program for real: initialize accounts, send transactions through the program's instruction handlers, and assert resulting state and balances. Placeholder tests (`assert!(true)`, build-only checks) don't count.

Expand Down
Loading
Loading