Skip to content

Commit

Permalink
feat(tests-fuzz): add CreateTableExprGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
WenyXu committed Jan 17, 2024
1 parent 7a1b856 commit 4f5b660
Show file tree
Hide file tree
Showing 9 changed files with 460 additions and 1 deletion.
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/partition/src/partition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub enum PartitionBound {
MaxValue,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct PartitionDef {
partition_columns: Vec<String>,
partition_bounds: Vec<PartitionBound>,
Expand Down
10 changes: 10 additions & 0 deletions tests-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,13 @@ license.workspace = true

[dependencies]
async-trait = { workspace = true }
common-error = { workspace = true }
common-macro = { workspace = true }
datatypes = { workspace = true }
derive_builder = { workspace = true }
faker_rand = "0.1"
lazy_static = { workspace = true }
partition = { workspace = true }
rand = { workspace = true }
snafu = { workspace = true }
sql = { workspace = true }
24 changes: 24 additions & 0 deletions tests-fuzz/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use common_macro::stack_trace_debug;
use snafu::{Location, Snafu};

use crate::ir::create_expr::CreateTableExprBuilderError;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Snafu)]
#[snafu(visibility(pub))]
#[stack_trace_debug]
pub enum Error {
#[snafu(display("Unexpected, violated: {violated}"))]
Unexpected {
violated: String,
location: Location,
},

#[snafu(display("Failed to build create table expr"))]
BuildCreateTableExpr {
#[snafu(source)]
error: CreateTableExprBuilderError,
location: Location,
},
}
7 changes: 7 additions & 0 deletions tests-fuzz/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod create_expr;
use std::fmt;

use crate::error::Error;
use crate::ir::CreateTableExpr;

pub type CreateTableExprGenerator =
Box<dyn Generator<CreateTableExpr, Error = Error> + Sync + Send>;

#[async_trait::async_trait]
pub(crate) trait Generator<T> {
type Error: Sync + Send + fmt::Debug;
Expand Down
192 changes: 192 additions & 0 deletions tests-fuzz/src/generator/create_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// 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 faker_rand::lorem::Word;
use partition::partition::{PartitionBound, PartitionDef};
use rand::seq::SliceRandom;
use rand::Rng;
use snafu::{ensure, ResultExt};

use super::Generator;
use crate::error::{self, Error, Result};
use crate::ir::create_expr::{
generate_random_value, Column, ColumnOption, CreateTableExprBuilder, PartibleColumn, TsColumn,
PARTIBLE_DATA_TYPES,
};
use crate::ir::{self, CreateTableExpr};

pub struct CreateTableExprGenerator {
columns: usize,
engine: String,
partition: usize,
if_not_exists: bool,
}

const DEFAULT_ENGINE: &str = "mito";

impl Default for CreateTableExprGenerator {
fn default() -> Self {
Self {
columns: 0,
engine: DEFAULT_ENGINE.to_string(),
if_not_exists: false,
partition: 0,
}
}
}

impl CreateTableExprGenerator {
/// Sets column num.
pub fn columns(mut self, columns: usize) -> Self {
self.columns = columns;
self
}

/// Sets the `if_not_exists`.
pub fn create_is_not_exists(mut self, v: bool) -> Self {
self.if_not_exists = v;
self
}

/// Sets the `engine`.
pub fn engine(mut self, engine: &str) -> Self {
self.engine = engine.to_string();
self
}

/// Sets the partition num.
/// If there is no primary key column,
/// it appends a primary key atomically.
pub fn partitions(mut self, partition: usize) -> Self {
self.partition = partition;
self
}

/// Generates the [CreateTableExpr].
fn generate_inner(&self) -> Result<CreateTableExpr> {
ensure!(
self.columns != 0,
error::UnexpectedSnafu {
violated: "The columns must larger than zero"
}
);

let mut builder = CreateTableExprBuilder::default();
let mut columns = Vec::with_capacity(self.columns + 1);
let mut primary_keys = vec![];
let mut rng = rand::thread_rng();

// Generates columns.
for i in 0..self.columns {
let mut column = rng.gen::<Column>();
// Removes the primary key option.
let options = column
.options
.extract_if(|option| option == &ColumnOption::PrimaryKey)
.collect::<Vec<_>>();
if !options.is_empty() {
primary_keys.push(i);
}
columns.push(column);
}

// Shuffles the primary keys.
primary_keys.shuffle(&mut rng);
let partitions = if self.partition > 1 {
// Finds a partible primary keys.
let partible_primary_keys = primary_keys
.iter()
.flat_map(|i| {
if PARTIBLE_DATA_TYPES.contains(&columns[*i].column_type) {
Some(*i)
} else {
None
}
})
.collect::<Vec<_>>();

// Generates the partitions.
if partible_primary_keys.is_empty() {
columns.push(rng.gen::<PartibleColumn>().0);
primary_keys.push(columns.len() - 1);
}
let primary_key_idx = primary_keys[rng.gen_range(0..primary_keys.len())];
let primary_column = &columns[primary_key_idx];

// Generates partition bounds.
let mut partition_bounds = Vec::with_capacity(self.partition);
for _ in 0..self.partition - 1 {
partition_bounds.push(PartitionBound::Value(generate_random_value(
&primary_column.column_type,
)));
partition_bounds.sort();
}
partition_bounds.push(PartitionBound::MaxValue);

vec![PartitionDef::new(
vec![primary_column.name.to_string()],
partition_bounds,
)]
} else {
vec![]
};
// Generates ts column.
columns.push(rng.gen::<TsColumn>().0);

builder.columns(columns);
builder.primary_keys(primary_keys);
builder.engine(self.engine.to_string());
builder.if_not_exists(self.if_not_exists);
builder.name(rng.gen::<Word>().to_string());
builder.partitions(partitions);
builder.build().context(error::BuildCreateTableExprSnafu)
}
}

#[async_trait::async_trait]
impl Generator<CreateTableExpr> for CreateTableExprGenerator {
type Error = Error;

async fn generate(&self) -> Result<CreateTableExpr> {
self.generate_inner()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_create_table_expr_generator() {
let expr = CreateTableExprGenerator::default()
.columns(10)
.partitions(3)
.create_is_not_exists(true)
.engine("mito2")
.generate_inner()
.unwrap();
assert_eq!(expr.engine, "mito2");
assert!(expr.if_not_exists);
assert!(expr.columns.len() >= 11);
assert_eq!(expr.partitions[0].partition_bounds().len(), 3);

let expr = CreateTableExprGenerator::default()
.columns(10)
.partitions(1)
.generate_inner()
.unwrap();
assert_eq!(expr.columns.len(), 11);
assert_eq!(expr.partitions.len(), 0);
}
}
19 changes: 19 additions & 0 deletions tests-fuzz/src/ir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

//! The intermediate representation
pub(crate) mod create_expr;

pub use create_expr::CreateTableExpr;
Loading

0 comments on commit 4f5b660

Please sign in to comment.