diff --git a/tests-fuzz/README.md b/tests-fuzz/README.md index 99786c5d42..6807e19a1c 100644 --- a/tests-fuzz/README.md +++ b/tests-fuzz/README.md @@ -50,8 +50,19 @@ Print the `std::fmt::Debug` output for an input. cargo fuzz fmt fuzz_target .crash --fuzz-dir tests-fuzz -D -s none ``` Rerun the fuzz test with the input. +You can override fuzz input with environment variables. For example, to override fuzz input like: + +``` +FuzzInput { + seed: 6666, + actions: 175 +} +``` + +you can run with `GT_FUZZ_OVERRIDE_SEED=6666` and `GT_FUZZ_OVERRIDE_ACTIONS=175`: ```bash -cargo fuzz run fuzz_target .crash --fuzz-dir tests-fuzz -D -s none +GT_FUZZ_OVERRIDE_SEED=6666 GT_FUZZ_OVERRIDE_ACTIONS=175 cargo fuzz run fuzz_target .crash --fuzz-dir tests-fuzz -D -s none ``` + For more details, visit [cargo fuzz](https://rust-fuzz.github.io/book/cargo-fuzz/tutorial.html) or run the command `cargo fuzz --help`. diff --git a/tests-fuzz/src/utils.rs b/tests-fuzz/src/utils.rs index ec7f1d8b27..0780f6c93d 100644 --- a/tests-fuzz/src/utils.rs +++ b/tests-fuzz/src/utils.rs @@ -125,6 +125,17 @@ pub const GT_FUZZ_INPUT_MAX_TABLES: &str = "GT_FUZZ_INPUT_MAX_TABLES"; pub const GT_FUZZ_INPUT_MAX_COLUMNS: &str = "GT_FUZZ_INPUT_MAX_COLUMNS"; pub const GT_FUZZ_INPUT_MAX_ALTER_ACTIONS: &str = "GT_FUZZ_INPUT_MAX_ALTER_ACTIONS"; pub const GT_FUZZ_INPUT_MAX_INSERT_ACTIONS: &str = "GT_FUZZ_INPUT_MAX_INSERT_ACTIONS"; +pub const FUZZ_OVERRIDE_PREFIX: &str = "GT_FUZZ_OVERRIDE_"; + +/// Reads an override value for a fuzz parameter from env `GT_FUZZ_OVERRIDE_`. +pub fn get_fuzz_override(name: &str) -> Option +where + T: std::str::FromStr, +{ + let _ = dotenv::dotenv(); + let key = format!("{}{}", FUZZ_OVERRIDE_PREFIX, name.to_ascii_uppercase()); + env::var(&key).ok().and_then(|v| v.parse().ok()) +} macro_rules! make_get_from_env_helper { ($key:expr, $default: expr) => { diff --git a/tests-fuzz/targets/ddl/fuzz_alter_logical_table.rs b/tests-fuzz/targets/ddl/fuzz_alter_logical_table.rs index 7157af4748..c7542a4623 100644 --- a/tests-fuzz/targets/ddl/fuzz_alter_logical_table.rs +++ b/tests-fuzz/targets/ddl/fuzz_alter_logical_table.rs @@ -44,7 +44,8 @@ use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::alter_expr::AlterTableExprTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::utils::{ - Connections, get_gt_fuzz_input_max_alter_actions, init_greptime_connections_via_env, + Connections, get_fuzz_override, get_gt_fuzz_input_max_alter_actions, + init_greptime_connections_via_env, }; use tests_fuzz::validator; @@ -66,10 +67,11 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_actions = get_gt_fuzz_input_max_alter_actions(); - let actions = rng.random_range(1..max_actions); + let actions = get_fuzz_override::("ACTIONS") + .unwrap_or_else(|| rng.random_range(1..max_actions)); Ok(FuzzInput { seed, actions }) } diff --git a/tests-fuzz/targets/ddl/fuzz_alter_table.rs b/tests-fuzz/targets/ddl/fuzz_alter_table.rs index 22e5d254e8..5289cebb3f 100644 --- a/tests-fuzz/targets/ddl/fuzz_alter_table.rs +++ b/tests-fuzz/targets/ddl/fuzz_alter_table.rs @@ -46,7 +46,8 @@ use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::alter_expr::AlterTableExprTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::utils::{ - Connections, get_gt_fuzz_input_max_columns, init_greptime_connections_via_env, + Connections, get_fuzz_override, get_gt_fuzz_input_max_alter_actions, + get_gt_fuzz_input_max_columns, init_greptime_connections_via_env, }; use tests_fuzz::validator; struct FuzzContext { @@ -209,9 +210,11 @@ fn generate_alter_table_expr( impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); - let actions = rng.random_range(1..256); + let max_actions = get_gt_fuzz_input_max_alter_actions(); + let actions = get_fuzz_override::("ACTIONS") + .unwrap_or_else(|| rng.random_range(1..max_actions)); Ok(FuzzInput { seed, actions }) } diff --git a/tests-fuzz/targets/ddl/fuzz_create_database.rs b/tests-fuzz/targets/ddl/fuzz_create_database.rs index 2e9c7e45f7..a6b2071cac 100644 --- a/tests-fuzz/targets/ddl/fuzz_create_database.rs +++ b/tests-fuzz/targets/ddl/fuzz_create_database.rs @@ -31,7 +31,7 @@ use tests_fuzz::generator::create_expr::CreateDatabaseExprGeneratorBuilder; use tests_fuzz::ir::CreateDatabaseExpr; use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::create_expr::CreateDatabaseExprTranslator; -use tests_fuzz::utils::{Connections, init_greptime_connections_via_env}; +use tests_fuzz::utils::{Connections, get_fuzz_override, init_greptime_connections_via_env}; struct FuzzContext { greptime: Pool, @@ -50,7 +50,7 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); Ok(FuzzInput { seed }) } } diff --git a/tests-fuzz/targets/ddl/fuzz_create_logical_table.rs b/tests-fuzz/targets/ddl/fuzz_create_logical_table.rs index 1535f6d6b1..e36b578209 100644 --- a/tests-fuzz/targets/ddl/fuzz_create_logical_table.rs +++ b/tests-fuzz/targets/ddl/fuzz_create_logical_table.rs @@ -38,7 +38,7 @@ use tests_fuzz::generator::create_expr::{ use tests_fuzz::ir::{Column, primary_key_and_not_null_column_options_generator}; use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; -use tests_fuzz::utils::{Connections, init_greptime_connections_via_env}; +use tests_fuzz::utils::{Connections, get_fuzz_override, init_greptime_connections_via_env}; use tests_fuzz::validator; struct FuzzContext { @@ -58,7 +58,7 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); Ok(FuzzInput { seed }) } } diff --git a/tests-fuzz/targets/ddl/fuzz_create_table.rs b/tests-fuzz/targets/ddl/fuzz_create_table.rs index 32d0d3c9eb..71171cb076 100644 --- a/tests-fuzz/targets/ddl/fuzz_create_table.rs +++ b/tests-fuzz/targets/ddl/fuzz_create_table.rs @@ -34,7 +34,8 @@ use tests_fuzz::ir::CreateTableExpr; use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::utils::{ - Connections, get_gt_fuzz_input_max_columns, init_greptime_connections_via_env, + Connections, get_fuzz_override, get_gt_fuzz_input_max_columns, + init_greptime_connections_via_env, }; use tests_fuzz::validator; @@ -56,10 +57,11 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_columns = get_gt_fuzz_input_max_columns(); - let columns = rng.random_range(2..max_columns); + let columns = get_fuzz_override::("COLUMNS") + .unwrap_or_else(|| rng.random_range(2..max_columns)); Ok(FuzzInput { columns, seed }) } } diff --git a/tests-fuzz/targets/failover/fuzz_failover_metric_regions.rs b/tests-fuzz/targets/failover/fuzz_failover_metric_regions.rs index 58ff07de87..edfadf4f4f 100644 --- a/tests-fuzz/targets/failover/fuzz_failover_metric_regions.rs +++ b/tests-fuzz/targets/failover/fuzz_failover_metric_regions.rs @@ -50,7 +50,8 @@ use tests_fuzz::utils::partition::{ use tests_fuzz::utils::pod_failure::{inject_datanode_pod_failure, recover_pod_failure}; use tests_fuzz::utils::{ Connections, GT_FUZZ_CLUSTER_NAME, GT_FUZZ_CLUSTER_NAMESPACE, compact_table, flush_memtable, - get_gt_fuzz_input_max_rows, get_gt_fuzz_input_max_tables, init_greptime_connections_via_env, + get_fuzz_override, get_gt_fuzz_input_max_rows, get_gt_fuzz_input_max_tables, + init_greptime_connections_via_env, }; use tests_fuzz::validator::row::count_values; @@ -76,12 +77,14 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_rows = get_gt_fuzz_input_max_rows(); - let rows = rng.random_range(2..max_rows); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(2..max_rows)); let max_tables = get_gt_fuzz_input_max_tables(); - let tables = rng.random_range(1..max_tables); + let tables = + get_fuzz_override::("TABLES").unwrap_or_else(|| rng.random_range(1..max_tables)); Ok(FuzzInput { rows, seed, tables }) } } diff --git a/tests-fuzz/targets/failover/fuzz_failover_mito_regions.rs b/tests-fuzz/targets/failover/fuzz_failover_mito_regions.rs index c4a8564f36..d7c1aa831b 100644 --- a/tests-fuzz/targets/failover/fuzz_failover_mito_regions.rs +++ b/tests-fuzz/targets/failover/fuzz_failover_mito_regions.rs @@ -53,7 +53,7 @@ use tests_fuzz::utils::partition::{ use tests_fuzz::utils::pod_failure::{inject_datanode_pod_failure, recover_pod_failure}; use tests_fuzz::utils::{ Connections, GT_FUZZ_CLUSTER_NAME, GT_FUZZ_CLUSTER_NAMESPACE, compact_table, flush_memtable, - get_gt_fuzz_input_max_columns, get_gt_fuzz_input_max_insert_actions, + get_fuzz_override, get_gt_fuzz_input_max_columns, get_gt_fuzz_input_max_insert_actions, get_gt_fuzz_input_max_rows, get_gt_fuzz_input_max_tables, init_greptime_connections_via_env, }; use tests_fuzz::validator::row::count_values; @@ -83,16 +83,20 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_columns = get_gt_fuzz_input_max_columns(); - let columns = rng.random_range(2..max_columns); + let columns = get_fuzz_override::("COLUMNS") + .unwrap_or_else(|| rng.random_range(2..max_columns)); let max_rows = get_gt_fuzz_input_max_rows(); - let rows = rng.random_range(2..max_rows); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(2..max_rows)); let max_tables = get_gt_fuzz_input_max_tables(); - let tables = rng.random_range(2..max_tables); + let tables = + get_fuzz_override::("TABLES").unwrap_or_else(|| rng.random_range(2..max_tables)); let max_inserts = get_gt_fuzz_input_max_insert_actions(); - let inserts = rng.random_range(2..max_inserts); + let inserts = get_fuzz_override::("INSERTS") + .unwrap_or_else(|| rng.random_range(2..max_inserts)); Ok(FuzzInput { columns, rows, diff --git a/tests-fuzz/targets/fuzz_insert.rs b/tests-fuzz/targets/fuzz_insert.rs index 61fac8c50f..bc690a4877 100644 --- a/tests-fuzz/targets/fuzz_insert.rs +++ b/tests-fuzz/targets/fuzz_insert.rs @@ -42,8 +42,8 @@ use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::translator::mysql::insert_expr::InsertIntoExprTranslator; use tests_fuzz::utils::{ - Connections, flush_memtable, get_gt_fuzz_input_max_columns, get_gt_fuzz_input_max_rows, - init_greptime_connections_via_env, + Connections, flush_memtable, get_fuzz_override, get_gt_fuzz_input_max_columns, + get_gt_fuzz_input_max_rows, init_greptime_connections_via_env, }; use tests_fuzz::validator; @@ -66,12 +66,14 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_columns = get_gt_fuzz_input_max_columns(); - let columns = rng.random_range(2..max_columns); + let columns = get_fuzz_override::("COLUMNS") + .unwrap_or_else(|| rng.random_range(2..max_columns)); let max_row = get_gt_fuzz_input_max_rows(); - let rows = rng.random_range(1..max_row); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(1..max_row)); Ok(FuzzInput { columns, rows, diff --git a/tests-fuzz/targets/fuzz_insert_logical_table.rs b/tests-fuzz/targets/fuzz_insert_logical_table.rs index cb87f07c87..289856f771 100644 --- a/tests-fuzz/targets/fuzz_insert_logical_table.rs +++ b/tests-fuzz/targets/fuzz_insert_logical_table.rs @@ -44,7 +44,7 @@ use tests_fuzz::translator::DslTranslator; use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::translator::mysql::insert_expr::InsertIntoExprTranslator; use tests_fuzz::utils::{ - Connections, compact_table, flush_memtable, get_gt_fuzz_input_max_rows, + Connections, compact_table, flush_memtable, get_fuzz_override, get_gt_fuzz_input_max_rows, get_gt_fuzz_input_max_tables, init_greptime_connections_via_env, }; use tests_fuzz::validator; @@ -67,12 +67,14 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_tables = get_gt_fuzz_input_max_tables(); - let tables = rng.random_range(1..max_tables); + let tables = + get_fuzz_override::("TABLES").unwrap_or_else(|| rng.random_range(1..max_tables)); let max_row = get_gt_fuzz_input_max_rows(); - let rows = rng.random_range(1..max_row); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(1..max_row)); Ok(FuzzInput { tables, seed, rows }) } } diff --git a/tests-fuzz/targets/migration/fuzz_migrate_metric_regions.rs b/tests-fuzz/targets/migration/fuzz_migrate_metric_regions.rs index 834e30c5d6..dc2e47fcc7 100644 --- a/tests-fuzz/targets/migration/fuzz_migrate_metric_regions.rs +++ b/tests-fuzz/targets/migration/fuzz_migrate_metric_regions.rs @@ -51,7 +51,7 @@ use tests_fuzz::utils::partition::{fetch_partition, fetch_partitions, region_dis use tests_fuzz::utils::procedure::procedure_state; use tests_fuzz::utils::wait::wait_condition_fn; use tests_fuzz::utils::{ - Connections, compact_table, flush_memtable, get_gt_fuzz_input_max_rows, + Connections, compact_table, flush_memtable, get_fuzz_override, get_gt_fuzz_input_max_rows, get_gt_fuzz_input_max_tables, init_greptime_connections_via_env, }; use tests_fuzz::validator::row::count_values; @@ -75,12 +75,14 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_rows = get_gt_fuzz_input_max_rows(); - let rows = rng.random_range(2..max_rows); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(2..max_rows)); let max_tables = get_gt_fuzz_input_max_tables(); - let tables = rng.random_range(1..max_tables); + let tables = + get_fuzz_override::("TABLES").unwrap_or_else(|| rng.random_range(1..max_tables)); Ok(FuzzInput { rows, seed, tables }) } diff --git a/tests-fuzz/targets/migration/fuzz_migrate_mito_regions.rs b/tests-fuzz/targets/migration/fuzz_migrate_mito_regions.rs index 882a79bfb5..6629151006 100644 --- a/tests-fuzz/targets/migration/fuzz_migrate_mito_regions.rs +++ b/tests-fuzz/targets/migration/fuzz_migrate_mito_regions.rs @@ -50,7 +50,9 @@ use tests_fuzz::utils::partition::{fetch_partition, fetch_partitions, region_dis use tests_fuzz::utils::procedure::procedure_state; use tests_fuzz::utils::wait::wait_condition_fn; use tests_fuzz::utils::{ - Connections, compact_table, flush_memtable, init_greptime_connections_via_env, + Connections, compact_table, flush_memtable, get_fuzz_override, get_gt_fuzz_input_max_columns, + get_gt_fuzz_input_max_insert_actions, get_gt_fuzz_input_max_rows, + init_greptime_connections_via_env, }; use tests_fuzz::validator; @@ -75,12 +77,19 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); - let partitions = rng.random_range(3..32); - let columns = rng.random_range(2..30); - let rows = rng.random_range(128..1024); - let inserts = rng.random_range(2..8); + let partitions = + get_fuzz_override::("PARTITIONS").unwrap_or_else(|| rng.random_range(3..32)); + let max_columns = get_gt_fuzz_input_max_columns(); + let columns = get_fuzz_override::("COLUMNS") + .unwrap_or_else(|| rng.random_range(2..max_columns)); + let max_rows = get_gt_fuzz_input_max_rows(); + let rows = + get_fuzz_override::("ROWS").unwrap_or_else(|| rng.random_range(128..max_rows)); + let max_inserts = get_gt_fuzz_input_max_insert_actions(); + let inserts = get_fuzz_override::("INSERTS") + .unwrap_or_else(|| rng.random_range(2..max_inserts)); Ok(FuzzInput { seed, columns, diff --git a/tests-fuzz/targets/unstable/fuzz_create_table_standalone.rs b/tests-fuzz/targets/unstable/fuzz_create_table_standalone.rs index 8e95cc920c..76f978e313 100644 --- a/tests-fuzz/targets/unstable/fuzz_create_table_standalone.rs +++ b/tests-fuzz/targets/unstable/fuzz_create_table_standalone.rs @@ -44,7 +44,9 @@ use tests_fuzz::translator::mysql::create_expr::CreateTableExprTranslator; use tests_fuzz::utils::config::{get_conf_path, write_config_file}; use tests_fuzz::utils::health::HttpHealthChecker; use tests_fuzz::utils::process::{ProcessManager, ProcessState, UnstableProcessController}; -use tests_fuzz::utils::{get_gt_fuzz_input_max_tables, load_unstable_test_env_variables}; +use tests_fuzz::utils::{ + get_fuzz_override, get_gt_fuzz_input_max_tables, load_unstable_test_env_variables, +}; use tests_fuzz::{error, validator}; use tokio::sync::watch; @@ -66,10 +68,11 @@ struct FuzzInput { impl Arbitrary<'_> for FuzzInput { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { - let seed = u.int_in_range(u64::MIN..=u64::MAX)?; + let seed = get_fuzz_override::("SEED").unwrap_or(u.int_in_range(u64::MIN..=u64::MAX)?); let mut rng = ChaChaRng::seed_from_u64(seed); let max_tables = get_gt_fuzz_input_max_tables(); - let tables = rng.random_range(1..max_tables); + let tables = + get_fuzz_override::("TABLES").unwrap_or_else(|| rng.random_range(1..max_tables)); Ok(FuzzInput { seed, tables }) } }