Skip to main content
The privora-test-utils crate provides shared utilities for testing Privora applications in Rust.

Installation

[dev-dependencies]
privora-test-utils = { path = "path/to/privora-test-utils" }
tokio = { version = "1", features = ["full"] }

Quick Start

use privora_test_utils::{
    get_rpc_url,
    ensure_sequencer_healthy,
    create_funded_keypair,
};

#[tokio::test]
#[ignore] // Requires running sequencer
async fn test_example() {
    let rpc_url = get_rpc_url();

    // Ensure sequencer is running
    ensure_sequencer_healthy(&rpc_url).await;

    // Create a funded keypair
    let (keypair, balance) = create_funded_keypair(&rpc_url, None).await.unwrap();

    // Your test code here...
}

Constants

use privora_test_utils::{
    DEFAULT_RPC_URL,                  // "http://localhost:18899"
    DEFAULT_AIRDROP_AMOUNT,           // 2_000_000_000 (2 SOL)
    MIN_BALANCE_THRESHOLD,            // 1_000_000_000 (1 SOL)
    DEFAULT_CONFIRMATION_TIMEOUT_SECS, // 30
    DEFAULT_AIRDROP_WAIT_MS,          // 1000
    get_rpc_url,                      // Returns RPC_URL env var or default
    get_airdrop_amount,               // Returns AIRDROP_AMOUNT env var or default
};

get_rpc_url

pub fn get_rpc_url() -> String
Returns the RPC URL from the RPC_URL environment variable, or falls back to DEFAULT_RPC_URL.

get_airdrop_amount

pub fn get_airdrop_amount() -> u64
Returns the airdrop amount from the AIRDROP_AMOUNT environment variable, or falls back to DEFAULT_AIRDROP_AMOUNT.

Sequencer Utilities

ensure_sequencer_healthy

pub async fn ensure_sequencer_healthy(rpc_url: &str)
Ensure the sequencer is healthy. Panics if not healthy. Useful for test setup where you want to fail fast.
#[tokio::test]
async fn test_with_sequencer() {
    ensure_sequencer_healthy(&get_rpc_url()).await;
    // Test code...
}

check_sequencer_health

pub async fn check_sequencer_health(rpc_url: &str) -> SequencerStatus

pub struct SequencerStatus {
    pub healthy: bool,
    pub status: Option<String>,
    pub version: Option<String>,
    pub error: Option<String>,
}
Check if the sequencer is healthy without panicking.
let status = check_sequencer_health("http://localhost:8899").await;
if status.healthy {
    println!("Sequencer is running");
} else {
    println!("Sequencer error: {:?}", status.error);
}

wait_for_sequencer

pub async fn wait_for_sequencer(
    rpc_url: &str,
    max_retries: u32,
    retry_delay_ms: u64,
) -> Result<()>
Wait for the sequencer to become healthy with retries.
// Wait up to 30 seconds (30 retries * 1000ms)
wait_for_sequencer(&rpc_url, 30, 1000).await?;

HealthResponse

#[derive(Debug, Deserialize)]
pub struct HealthResponse {
    pub status: String,
    pub version: Option<String>,
}

Funded Account Utilities

create_funded_keypair

pub async fn create_funded_keypair(
    rpc_url: &str,
    amount: Option<u64>,
) -> Result<(Keypair, u64)>
Create a new keypair and fund it with an airdrop.
// Create with default amount (2 SOL)
let (keypair, balance) = create_funded_keypair(&rpc_url, None).await?;

// Create with custom amount
let (keypair, balance) = create_funded_keypair(&rpc_url, Some(5_000_000_000)).await?;

simple_airdrop

pub async fn simple_airdrop(
    rpc_url: &str,
    pubkey: &Pubkey,
    amount: u64,
) -> Result<u64>
Simple airdrop helper that doesn’t require implementing Fundable.
let keypair = Keypair::new();
let balance = simple_airdrop(&rpc_url, &keypair.pubkey(), 2_000_000_000).await?;

request_airdrop

pub async fn request_airdrop<T: Fundable>(
    client: &T,
    amount: u64,
) -> Result<Signature>
Request an airdrop for a client implementing the Fundable trait.

fund_and_verify

pub async fn fund_and_verify<T: Fundable>(
    client: &T,
    amount: Option<u64>,
    wait_ms: Option<u64>,
) -> Result<u64>
Request an airdrop and wait for confirmation, then verify the balance.

Fundable Trait

pub trait Fundable {
    /// Get the client's public key
    fn pubkey(&self) -> Pubkey;

    /// Get an RPC client for the network
    fn rpc_client(&self) -> &RpcClient;
}
Implement this trait for your client to use request_airdrop and fund_and_verify.

Unit Conversion Helpers

lamports_to_sol

pub fn lamports_to_sol(lamports: u64) -> f64
Format lamports as SOL for display.
let sol = lamports_to_sol(2_000_000_000); // 2.0

sol_to_lamports

pub fn sol_to_lamports(sol: f64) -> u64
Parse SOL to lamports.
let lamports = sol_to_lamports(2.0); // 2_000_000_000

Example Test Setup

use anyhow::Result;
use privora_sdk_client::prelude::*;
use privora_test_utils::{
    get_rpc_url,
    ensure_sequencer_healthy,
    create_funded_keypair,
    DEFAULT_AIRDROP_AMOUNT,
};

#[tokio::test]
#[ignore] // Requires running sequencer
async fn test_fhe_workflow() -> Result<()> {
    let rpc_url = get_rpc_url();

    // Ensure sequencer is running
    ensure_sequencer_healthy(&rpc_url).await;

    // Create funded test account
    let (payer, balance) = create_funded_keypair(&rpc_url, None).await?;
    println!("Payer funded with {} lamports", balance);

    // Connect to Privora
    let privora = PrivoraClient::new(&rpc_url).await?;

    // Encrypt and submit data
    let encrypted = privora.encryptor().encrypt(100u8)?;
    let hash = privora.submit(&encrypted).await?;

    println!("Submitted encrypted data: {:?}", hash);

    Ok(())
}

Running Tests

Tests that require a running sequencer should be marked with #[ignore]:
#[tokio::test]
#[ignore] // Requires running sequencer
async fn test_requires_sequencer() {
    // ...
}
Run ignored tests with:
cargo test -- --ignored
Or run all tests including ignored:
cargo test -- --include-ignored