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

feat(fuzz): add fuzz test with delete rows #3867

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
7 changes: 7 additions & 0 deletions tests-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ test = false
bench = false
doc = false

[[bin]]
name = "fuzz_delete"
path = "targets/fuzz_delete.rs"
test = false
bench = false
doc = false

[[bin]]
name = "fuzz_insert_logical_table"
path = "targets/fuzz_insert_logical_table.rs"
Expand Down
5 changes: 5 additions & 0 deletions tests-fuzz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ cargo fuzz list --fuzz-dir tests-fuzz
cargo fuzz run fuzz_create_table --fuzz-dir tests-fuzz
```

> Note: if you meet the error, you may need to run :
> ```bash
> cargo fuzz run fuzz_create_table --fuzz-dir tests-fuzz -D -s none
> ```

## Crash Reproduction
If you want to reproduce a crash, you first need to obtain the Base64 encoded code, which usually appears at the end of a crash report, and store it in a file.

Expand Down
1 change: 1 addition & 0 deletions tests-fuzz/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod alter_expr;
pub mod create_expr;
pub mod insert_expr;
pub mod select_expr;
pub mod delete_expr;

use std::fmt;

Expand Down
64 changes: 64 additions & 0 deletions tests-fuzz/src/generator/delete_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::marker::PhantomData;

use derive_builder::Builder;
use rand::seq::SliceRandom;
use rand::Rng;

use crate::context::TableContextRef;
use crate::error::{Error, Result};
use crate::generator::Generator;
use crate::ir::delete_expr::{DeleteExpr, WhereExpr};
use crate::ir::generate_random_value;
use crate::ir::insert_expr::RowValue;

#[derive(Builder)]
#[builder(pattern = "owned")]
pub struct DeleteExprGenerator<R: Rng + 'static> {
table_ctx: TableContextRef,
#[builder(default)]
_phantom: PhantomData<R>,
}

impl<R: Rng + 'static> Generator<DeleteExpr, R> for DeleteExprGenerator<R> {
type Error = Error;

fn generate(&self, rng: &mut R) -> Result<DeleteExpr> {
let filter_columns = self
.table_ctx
.columns
.iter()
.filter(|col| !col.is_nullable() && !col.has_default_value())
.cloned()
.collect::<Vec<_>>();
if filter_columns.is_empty() {
return Ok(DeleteExpr::default());
}
let selection = if filter_columns.len() > 1 {
rng.gen_range(1..filter_columns.len())
} else {
1
};
let mut selected_columns = filter_columns
.choose_multiple(rng, selection)
.cloned()
.collect::<Vec<_>>();
selected_columns.shuffle(rng);

let mut where_clause = Vec::with_capacity(selected_columns.len());

for column in selected_columns.iter() {
let value = generate_random_value(rng, &column.column_type, None);
let condition = WhereExpr {
column: column.name.to_string(),
value: RowValue::Value(value),
};
where_clause.push(condition);
}

Ok(DeleteExpr {
table_name: self.table_ctx.name.to_string(),
columns: selected_columns,
where_clause,
})
}
}
2 changes: 2 additions & 0 deletions tests-fuzz/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub(crate) mod alter_expr;
pub(crate) mod create_expr;
pub(crate) mod insert_expr;
pub(crate) mod select_expr;
pub(crate) mod delete_expr;

use core::fmt;

Expand All @@ -29,6 +30,7 @@ use datatypes::types::TimestampType;
use datatypes::value::Value;
use derive_builder::Builder;
pub use insert_expr::InsertIntoExpr;
pub use delete_expr::DeleteExpr;
use lazy_static::lazy_static;
use rand::seq::SliceRandom;
use rand::Rng;
Expand Down
28 changes: 28 additions & 0 deletions tests-fuzz/src/ir/delete_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::insert_expr::RowValue;
use crate::ir::Column;

pub struct WhereExpr {
pub column: String,
pub value: RowValue,
}

#[derive(Default)]
pub struct DeleteExpr {
pub table_name: String,
pub columns: Vec<Column>,
pub where_clause: Vec<WhereExpr>,
}
1 change: 1 addition & 0 deletions tests-fuzz/src/translator/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ pub mod alter_expr;
pub mod create_expr;
pub mod insert_expr;
pub mod select_expr;
pub mod delete_expr;
73 changes: 73 additions & 0 deletions tests-fuzz/src/translator/mysql/delete_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::error::{Error, Result};
use crate::ir::delete_expr::DeleteExpr;
use crate::translator::DslTranslator;

pub struct DeleteExprTranslator;

impl DslTranslator<DeleteExpr, String> for DeleteExprTranslator {
type Error = Error;

fn translate(&self, input: &DeleteExpr) -> Result<String> {
// Generating WHERE clause if exists
let where_clause = if !input.where_clause.is_empty() {
input
.where_clause
.iter()
.map(|where_expr| format!("{} = {}", where_expr.column, where_expr.value))
.collect::<Vec<_>>()
.join(" AND ")
} else {
"1".to_string()
};

Ok(format!(
"DELETE FROM {} WHERE {};",
input.table_name, where_clause,
))
}
}

#[cfg(test)]
mod tests {
use std::sync::Arc;

use rand::SeedableRng;

use super::DeleteExprTranslator;
use crate::generator::delete_expr::DeleteExprGeneratorBuilder;
use crate::generator::Generator;
use crate::test_utils;
use crate::translator::DslTranslator;

#[test]
fn test_delete_expr_translator() {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0);

let test_ctx = test_utils::new_test_ctx();
let delete_expr_generator = DeleteExprGeneratorBuilder::default()
.table_ctx(Arc::new(test_ctx))
.build()
.unwrap();

let delete_expr = delete_expr_generator.generate(&mut rng).unwrap();
let output = DeleteExprTranslator.translate(&delete_expr).unwrap();
// println!("output: {}", output);

let expected_output = "DELETE FROM test WHERE ts = '+104408-01-06 12:42:54.931+0000'";
assert_eq!(output, expected_output);
}
}
Loading
Loading