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

Tests #112

Merged
merged 20 commits into from
Feb 3, 2024
Merged

Tests #112

Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ runs:
rustup default nightly
rustup component add rustfmt clippy
shell: bash
- name: Install Cargo Expand
run: cargo install cargo-expand
shell: bash
- name: Get rustc version
id: rust-version
run: echo "::set-output name=RUSTC_HASH::$(rustc -V | cut -d " " -f 3 | tail -c +2)"
Expand Down
3 changes: 2 additions & 1 deletion crates/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ shellexpand = { workspace = true }
trdelnik-derive-displayix = { path = "./derive/display_ix" }
trdelnik-derive-fuzz-deserialize = { path = "./derive/fuzz_deserialize" }
trdelnik-derive-fuzz-test-executor = { path = "./derive/fuzz_test_executor" }
pathdiff="0.2.1"
pathdiff = "0.2.1"
macrotest = "1.0.9"
224 changes: 4 additions & 220 deletions crates/client/src/commander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ use tokio::{
signal,
};

pub const PROGRAM_CLIENT_DIRECTORY: &str = ".program_client";
pub const CARGO_TARGET_DIR_DEFAULT: &str = "trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target";
pub const HFUZZ_WORKSPACE_DEFAULT: &str = "trdelnik-tests/fuzz_tests/fuzzing/hfuzz_workspace";
pub use crate::constants::*;

#[derive(Error, Debug)]
pub enum Error {
Expand Down Expand Up @@ -536,7 +534,7 @@ impl Default for Commander {
}
}

fn get_crash_dir_and_ext(
pub fn get_crash_dir_and_ext(
root: &str,
target: &str,
hfuzz_run_args: &str,
Expand Down Expand Up @@ -569,7 +567,7 @@ fn get_crash_dir_and_ext(
(crash_path, extension)
}

fn get_cmd_option_value<'a>(
pub fn get_cmd_option_value<'a>(
hfuzz_run_args: impl Iterator<Item = &'a str>,
short_opt: &str,
long_opt: &str,
Expand Down Expand Up @@ -605,7 +603,7 @@ fn get_cmd_option_value<'a>(
value
}

fn get_crash_files(
pub fn get_crash_files(
dir: &PathBuf,
extension: &str,
) -> Result<Vec<PathBuf>, Box<dyn std::error::Error>> {
Expand All @@ -625,217 +623,3 @@ fn get_crash_files(
.collect::<Vec<_>>();
Ok(paths)
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cmd_options_parsing() {
let mut command = String::from("-Q -v --extension fuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q --extension fuzz -v");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q -e fuzz -v");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q --extension fuzz -v --extension ");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, None);

command = String::from("-Q --extension fuzz -v -e ");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, None);

let mut command = String::from("--extension buzz -e fuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q -v -e fuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q -v -efuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q -v --ext fuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, Some("fuzz".to_string()));

command = String::from("-Q -v --extfuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, None);

command = String::from("-Q -v --workspace");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "--ext");
assert_eq!(extension, None);

command = String::from("-Q -v -e");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "", "--ext");
assert_eq!(extension, None);

command = String::from("-Q -v --ext fuzz");
let args = command.split_whitespace();

let extension = get_cmd_option_value(args, "-e", "");
assert_eq!(extension, None);
}

#[test]
fn test_get_crash_dir_and_ext() {
pub const TARGET: &str = "fuzz_0";
pub const TEST_CRASH_PATH: &str = "/home/fuzz/test-crash-path";

const ROOT: &str = "/home/fuzz/";

let default_crash_path = std::path::Path::new(HFUZZ_WORKSPACE_DEFAULT).join(TARGET);
let env_specified_crash_path = std::path::Path::new(TEST_CRASH_PATH).join(TARGET);

// this is default behavior
let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "", HFUZZ_WORKSPACE_DEFAULT);

assert_eq!(crash_dir, default_crash_path);
assert_eq!(&ext, "fuzz");

// behavior where path is specified within env variable HFUZZ_WORKSPACE, but not within -W HFUZZ_RUN_ARGS
let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "-Q -e", TEST_CRASH_PATH);

assert_eq!(crash_dir, env_specified_crash_path);
assert_eq!(&ext, "fuzz");

// behavior as above
let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "-Q -e crash", TEST_CRASH_PATH);

assert_eq!(crash_dir, env_specified_crash_path);
assert_eq!(&ext, "crash");

// test absolute path
// HFUZZ_WORKSPACE has default value however -W is set
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q -W /home/crash -e crash",
HFUZZ_WORKSPACE_DEFAULT,
);

let expected_crash_path = std::path::Path::new("/home/crash");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// test absolute path
// HFUZZ_WORKSPACE is set and -W is also set
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q --crash /home/crash -e crash",
TEST_CRASH_PATH,
);
let expected_crash_path = std::path::Path::new("/home/crash");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// test absolute path
// HFUZZ_WORKSPACE is set and -W is also set
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q --crash /home/crash/foo/bar/dead/beef -e crash",
TEST_CRASH_PATH,
);

let expected_crash_path = std::path::Path::new("/home/crash/foo/bar/dead/beef");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// test relative path
// HFUZZ_WORKSPACE is set and -W is also set, this time with relative path
let (crash_dir, ext) =
get_crash_dir_and_ext(ROOT, TARGET, "-Q -W ../crash -e crash", TEST_CRASH_PATH);

let expected_crash_path = std::path::Path::new(ROOT).join("../crash");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// test relative path
// HFUZZ_WORKSPACE is set and -W is also set, this time with relative path
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q -W ../../dead/beef/crash -e crash",
TEST_CRASH_PATH,
);

let expected_crash_path = std::path::Path::new(ROOT).join("../../dead/beef/crash");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// test relative path
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q --crash ../crash -e crash",
HFUZZ_WORKSPACE_DEFAULT,
);

let expected_crash_path = std::path::Path::new(ROOT).join("../crash");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// crash directory has precedence before workspace option , which have precedence before
// HFUZZ_WORKSPACE
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q --crash ../bitcoin/to/the/moon -W /workspace -e crash",
TEST_CRASH_PATH,
);

let expected_crash_path = std::path::Path::new(ROOT).join("../bitcoin/to/the/moon");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");

// crash directory has precedence before workspace HFUZZ_WORKSPACE
let (crash_dir, ext) = get_crash_dir_and_ext(
ROOT,
TARGET,
"-Q --crash /home/crashes/we/like/solana -e crash",
TEST_CRASH_PATH,
);

// If path is specified as absolute, the join will replace whole path.
let expected_crash_path = std::path::Path::new("/home/crashes/we/like/solana");

// let expected_crash_path = root.join("/home/crashes/we/like/solana");
assert_eq!(crash_dir, expected_crash_path);
assert_eq!(&ext, "crash");
}
}
54 changes: 1 addition & 53 deletions crates/client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl FuzzArg {
}
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, Default)]
pub struct Config {
pub test: Test,
pub fuzz: Fuzz,
Expand Down Expand Up @@ -234,55 +234,3 @@ impl Config {
args.join(" ")
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_merge_and_precedence1() {
let config = Config {
test: Test::default(),
fuzz: Fuzz::default(),
};

let env_var_string = config.get_fuzz_args(String::default());
assert_eq!(env_var_string, "-t 10 -N 0 ");
}
#[test]
fn test_merge_and_precedence2() {
let config = Config {
test: Test::default(),
fuzz: Fuzz::default(),
};

let env_var_string = config.get_fuzz_args("-t 0 -N10 --exit_upon_crash".to_string());

assert_eq!(env_var_string, "-t 10 -N 0 -t 0 -N10 --exit_upon_crash");
}
#[test]
fn test_merge_and_precedence3() {
let config = Config {
test: Test::default(),
fuzz: Fuzz::default(),
};
let env_var_string =
config.get_fuzz_args("-t 100 -N 5000 -Q -v --exit_upon_crash".to_string());
assert_eq!(
env_var_string,
"-t 10 -N 0 -t 100 -N 5000 -Q -v --exit_upon_crash"
);
}
#[test]
fn test_merge_and_precedence4() {
let config = Config {
test: Test::default(),
fuzz: Fuzz::default(),
};

let env_var_string = config.get_fuzz_args("-t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666".to_string());
assert_eq!(
env_var_string,
"-t 10 -N 0 -t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666"
);
}
}
46 changes: 20 additions & 26 deletions crates/client/src/fuzzer/fuzzer_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,31 +173,25 @@ pub fn generate_source_code(idl: &Idl) -> String {
)
.into_iter();

let fuzz_accounts = idl_program
.instruction_account_pairs
.iter()
.fold(
HashMap::new(),
|mut fuzz_accounts, (_idl_instruction, idl_account_group)| {
idl_account_group.accounts.iter().fold(
&mut fuzz_accounts,
|fuzz_accounts, (name, _ty)| {
let name = format_ident!("{name}");
fuzz_accounts.entry(name).or_insert_with(|| "".to_string());
fuzz_accounts
},
);

fuzz_accounts
},
)
.into_iter()
.map(|fuzz_accounts| {
// TODO find out the type of the account and remember it as Keypair, PdaStore, TokenStore, MintStore, ProgramStore etc.
fuzz_accounts.0
})
.collect::<Vec<_>>()
.into_iter();
let fuzz_accounts = idl_program.instruction_account_pairs.iter().fold(
HashMap::new(),
|mut fuzz_accounts, (_idl_instruction, idl_account_group)| {
idl_account_group.accounts.iter().fold(
&mut fuzz_accounts,
|fuzz_accounts, (name, _ty)| {
let name = format_ident!("{name}");
fuzz_accounts.entry(name).or_insert_with(|| "".to_string());
fuzz_accounts
},
);

fuzz_accounts
},
);
// this ensures that the order of accounts is deterministic
// so we can use expected generated template within tests
let mut sorted_fuzz_accounts: Vec<_> = fuzz_accounts.keys().collect();
sorted_fuzz_accounts.sort();

let fuzzer_module: syn::ItemMod = parse_quote! {
pub mod #fuzz_instructions_module_name {
Expand All @@ -218,7 +212,7 @@ pub fn generate_source_code(idl: &Idl) -> String {
/// Keypair, PdaStore, TokenStore, MintStore, ProgramStore
#[derive(Default)]
pub struct FuzzAccounts {
#(#fuzz_accounts: AccountsStorage<todo!()>),*
#(#sorted_fuzz_accounts: AccountsStorage<todo!()>),*
}

impl FuzzAccounts {
Expand Down
Loading
Loading