Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for examples/hello_world #6

Merged
merged 3 commits into from
Nov 11, 2024
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
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(())
}
}