Expand description
§Light Program Test
A fast local test environment for Solana programs using compressed accounts and tokens.
§Features
- Fast in-memory indexer and SVM via LiteSVM
- Supports custom programs
- Built-in prover
Use light-program-test
when:
- You need fast test execution
- You write unit/integration tests for your program or client code
Use solana-test-validator
when:
- You need RPC methods or external tools that are incompatible with LiteSVM
- Testing against real validator behavior
§Configuration Options
§with_prover: bool
true
: Starts a prover server in the background for generating validity proofsfalse
: Runs without prover (faster for tests that don’t need proofs, or repeated test runs to reduce startup time)
§additional_programs: Option<Vec<(&str, Pubkey)>>
- Specify custom programs to deploy alongside the default Light Protocol programs
- Format:
vec![("program_name", program_id)]
- Programs are loaded from built artifacts
§Prerequisites
-
ZK Compression CLI: Required to start the prover server and download Light Protocol programs
npm i -g @lightprotocol/zk-compression-cli
- If programs are missing after CLI installation, run
light test-validator
once to download them
- If programs are missing after CLI installation, run
-
Build programs: Run
cargo test-sbf
to build program binaries and set the required environment variables for locating program artifacts
§Prover Server
The prover server runs on port 3001 when enabled. To manually stop it:
# Find the process ID
lsof -i:3001
# Kill the process
kill <pid>
§Examples
§V1 Trees
use light_program_test::{LightProgramTest, ProgramTestConfig};
use solana_sdk::signer::Signer;
#[tokio::test]
async fn test_v1_compressed_account() {
// Initialize with v1 trees
let config = ProgramTestConfig::default();
let mut rpc = LightProgramTest::new(config).await.unwrap();
let payer = Keypair::new();
// Get v1 tree info
let address_tree_info = rpc.get_address_tree_v1();
let state_tree_info = rpc.get_random_state_tree_info();
// Airdrop for testing
rpc.airdrop_lamports(&payer.pubkey(), 1_000_000_000).await.unwrap();
// Query compressed accounts using Indexer trait
let accounts = rpc.indexer().unwrap()
.get_compressed_accounts_by_owner(&payer.pubkey())
.await
.unwrap();
println!("Found {} compressed accounts", accounts.len());
}
§V2 Trees
use light_program_test::{LightProgramTest, ProgramTestConfig};
use solana_sdk::signer::Signer;
#[tokio::test]
async fn test_v2_compressed_account() {
// Initialize with v2 batched trees and custom program
let config = ProgramTestConfig::new_v2(
true, // with_prover
Some(vec![("my_program", my_program::ID)])
);
let mut rpc = LightProgramTest::new(config).await.unwrap();
let payer = Keypair::new();
// Get v2 tree pubkeys
let address_tree_info = rpc.get_address_tree_v2();
let state_tree_info = rpc.get_random_state_tree_info();
rpc.airdrop_lamports(&payer.pubkey(), 1_000_000_000).await.unwrap();
// Query using Indexer trait methods
let accounts = rpc.indexer().unwrap()
.get_compressed_accounts_by_owner(&payer.pubkey())
.await
.unwrap();
println!("Found {} compressed accounts with v2 trees", accounts.len());
}
Re-exports§
pub use program_test::config::ProgramTestConfig;
pub use program_test::LightProgramTest;