Skip to content

Commit

Permalink
Merge pull request #6 from solana-developers/local-test
Browse files Browse the repository at this point in the history
Add tests for `examples/hello_world`
  • Loading branch information
ngundotra authored Nov 11, 2024
2 parents 64a6129 + 3a75a2a commit 0654db3
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 91 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ solana-verify verify-from-repo -um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV
Final Output:

```
Executable Program Hash from repo: 7b37482dd6b2159932b5c2595bc6ce62cf6e587ae67f237c8152b802bf7d7bb8
On-chain Program Hash: 7b37482dd6b2159932b5c2595bc6ce62cf6e587ae67f237c8152b802bf7d7bb8
Executable Program Hash from repo: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5
On-chain Program Hash: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5
Program hash matches ✅
```

Expand Down
94 changes: 5 additions & 89 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::{anyhow, Context};
use anyhow::anyhow;
use cargo_lock::Lockfile;
use cargo_toml::Manifest;
use clap::{App, Arg, SubCommand};
Expand All @@ -13,7 +13,7 @@ use solana_sdk::{
pubkey::Pubkey,
};
use std::{
io::{Read, Write},
io::Read,
path::PathBuf,
process::{exit, Stdio},
sync::{
Expand All @@ -28,6 +28,9 @@ pub mod image_config;
pub mod solana_program;
use image_config::IMAGE_MAP;

#[cfg(test)]
mod test;

use crate::{
api::send_job_to_remote,
solana_program::{process_close, upload_program},
Expand Down Expand Up @@ -1001,90 +1004,3 @@ pub fn get_pkg_name_from_cargo_toml(cargo_toml_file: &str) -> Option<String> {
let pkg = manifest.package?;
Some(pkg.name)
}

fn test_verify_program_hash_helper(expected_hash: &str, args: &[&str]) -> anyhow::Result<()> {
let mut child = std::process::Command::new("./target/debug/solana-verify")
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.context("Failed to execute solana-verify command")?;

if let Some(mut stdin) = child.stdin.take() {
stdin.write_all(b"n")?;
}

let output = child
.wait_with_output()
.context("Failed to wait for solana-verify command")?;

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("Command failed: {}", error);
}

// Print the last 10 lines of the output
let output_str = String::from_utf8_lossy(&output.stdout);
let lines: Vec<&str> = output_str.split('\n').collect();
let last_10_lines: Vec<String> = lines.iter().rev().take(10).map(|s| s.to_string()).collect();
println!("Last 10 lines of output:\n{}", last_10_lines.join("\n"));

let re = regex::Regex::new(r"Executable Program Hash from repo: ([a-f0-9]{64})")
.context("Failed to compile regex")?;

let program_hash = re
.captures(&output_str)
.context("Could not find program hash in output")?
.get(1)
.context("Invalid capture group")?
.as_str();

assert_eq!(
program_hash, expected_hash,
"Program hash {} does not match expected value {}",
program_hash, expected_hash
);

Ok(())
}

#[test]
fn test_phoenix_v1() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9";

let args = &[
"verify-from-repo",
"-um",
"--program-id",
"PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY",
"https://github.com/Ellipsis-Labs/phoenix-v1",
];

test_verify_program_hash_helper(EXPECTED_HASH, args)?;
Ok(())
}

#[test]
fn test_squads_v3() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c";
let args: Vec<&str> = "verify-from-repo https://github.com/Squads-Protocol/squads-mpl --commit-hash c95b7673d616c377a349ca424261872dfcf8b19d --program-id SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu -um --library-name squads_mpl --bpf".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_drift_v2() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828";
let args: Vec<&str> = "verify-from-repo -um --program-id dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH https://github.com/drift-labs/protocol-v2 --commit-hash 110d3ff4f8ba07c178d69f9bfc7b30194fac56d6 --library-name drift".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_marginfi_v2() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "7b37482dd6b2159932b5c2595bc6ce62cf6e587ae67f237c8152b802bf7d7bb8";
let args: Vec<&str> = "verify-from-repo -um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA https://github.com/mrgnlabs/marginfi-v2 --commit-hash d33e649e415c354cc2a1e3c49131725552d69ba0 --library-name marginfi".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}
155 changes: 155 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
mod tests {
use anyhow::Context;
use regex::Regex;
use std::io::Write;
use std::process::Stdio;

fn test_verify_program_hash_helper(expected_hash: &str, args: &[&str]) -> anyhow::Result<()> {
let mut child = std::process::Command::new("./target/debug/solana-verify")
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.context("Failed to execute solana-verify command")?;

if let Some(mut stdin) = child.stdin.take() {
stdin.write_all(b"n")?;
}

let output = child
.wait_with_output()
.context("Failed to wait for solana-verify command")?;

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("Command failed: {}", error);
}

// Print the last 10 lines of the output
let output_str = String::from_utf8_lossy(&output.stdout);
let lines: Vec<&str> = output_str.split('\n').collect();
let last_10_lines: Vec<String> = lines.iter().rev().take(10).map(|s| s.to_string()).collect();
println!("Last 10 lines of output:\n{}", last_10_lines.join("\n"));

let re = Regex::new(r"Executable Program Hash from repo: ([a-f0-9]{64})")
.context("Failed to compile regex")?;

let program_hash = re
.captures(&output_str)
.context("Could not find program hash in output")?
.get(1)
.context("Invalid capture group")?
.as_str();

assert_eq!(
program_hash, expected_hash,
"Program hash {} does not match expected value {}",
program_hash, expected_hash
);

Ok(())
}

#[test]
fn test_phoenix_v1() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9";
let args: Vec<&str> =
"verify-from-repo -um --program-id PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY https://github.com/Ellipsis-Labs/phoenix-v1".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_squads_v3() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c";
let args: Vec<&str> = "verify-from-repo https://github.com/Squads-Protocol/squads-mpl --commit-hash c95b7673d616c377a349ca424261872dfcf8b19d --program-id SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu -um --library-name squads_mpl --bpf".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_drift_v2() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828";
let args: Vec<&str> = "verify-from-repo -um --program-id dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH https://github.com/drift-labs/protocol-v2 --commit-hash 110d3ff4f8ba07c178d69f9bfc7b30194fac56d6 --library-name drift".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_marginfi_v2() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5";
let args: Vec<&str> = "verify-from-repo -um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA https://github.com/mrgnlabs/marginfi-v2 --commit-hash d33e649e415c354cc2a1e3c49131725552d69ba0 --library-name marginfi".split(" ").collect();
test_verify_program_hash_helper(EXPECTED_HASH, &args)?;
Ok(())
}

#[test]
fn test_local_example() -> anyhow::Result<()> {
const EXPECTED_HASH: &str = "08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760";

let args: Vec<&str> = "build ./examples/hello_world".split(" ").collect();
let child = std::process::Command::new("./target/debug/solana-verify")
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.context("Failed to execute solana-verify command")?;

let output = child
.wait_with_output()
.context("Failed to wait for solana-verify command")?;

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("Command failed: {}", error);
}


let args: Vec<&str> = "get-executable-hash ./examples/hello_world/target/deploy/hello_world.so".split(" ").collect();
let child = std::process::Command::new("./target/debug/solana-verify")
.args(&args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.context("Failed to execute solana-verify command")?;

let output = child
.wait_with_output()
.context("Failed to wait for solana-verify command")?;

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr).trim().to_string();
anyhow::bail!("Command failed: {}", error);
}

let hash = String::from_utf8_lossy(&output.stdout).trim().to_string();
assert_eq!(hash, EXPECTED_HASH, "Program hash {} does not match expected value {}", hash, EXPECTED_HASH);
Ok(())
}


#[test]
fn test_verify_from_image() -> anyhow::Result<()> {
let args: Vec<&str> = "verify-from-image -e examples/hello_world/target/deploy/hello_world.so -i ellipsislabs/hello_world_verifiable_build:latest -p 2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn".split(" ").collect();
let child = std::process::Command::new("./target/debug/solana-verify")
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.context("Failed to execute solana-verify command")?;

let output = child
.wait_with_output()
.context("Failed to wait for solana-verify command")?;

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("Command failed: {}", error);
}
Ok(())
}
}

0 comments on commit 0654db3

Please sign in to comment.