mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-24 19:44:21 +01:00
Add fault type that reopens the DB and reconnects the connections. It purposefully does not call conn.close(), as the default behavior of that method is to checkpoint the database. This easily exposes multiple manifestations of DB/WAL corruption caused by this issue: https://github.com/tursodatabase/limbo/issues/1725 in fact, in my testing, every run fails when this fault is enabled. Hence I've added the --disable-reopen-database flag if you want to try to find some other bugs.
147 lines
4.9 KiB
Rust
147 lines
4.9 KiB
Rust
use clap::{command, Parser};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Parser, Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord)]
|
|
#[command(name = "limbo-simulator")]
|
|
#[command(author, version, about, long_about = None)]
|
|
pub struct SimulatorCLI {
|
|
#[clap(short, long, help = "set seed for reproducible runs", default_value = None)]
|
|
pub seed: Option<u64>,
|
|
#[clap(
|
|
short,
|
|
long,
|
|
help = "enable doublechecking, run the simulator with the plan twice and check output equality"
|
|
)]
|
|
pub doublecheck: bool,
|
|
#[clap(
|
|
short = 'n',
|
|
long,
|
|
help = "change the maximum size of the randomly generated sequence of interactions",
|
|
default_value_t = 5000
|
|
)]
|
|
pub maximum_tests: usize,
|
|
#[clap(
|
|
short = 'k',
|
|
long,
|
|
help = "change the minimum size of the randomly generated sequence of interactions",
|
|
default_value_t = 1000
|
|
)]
|
|
pub minimum_tests: usize,
|
|
#[clap(
|
|
short = 't',
|
|
long,
|
|
help = "change the maximum time of the simulation(in seconds)",
|
|
default_value_t = 60 * 60 // default to 1 hour
|
|
)]
|
|
pub maximum_time: usize,
|
|
#[clap(short = 'l', long, help = "load plan from the bug base")]
|
|
pub load: Option<String>,
|
|
#[clap(
|
|
short = 'w',
|
|
long,
|
|
help = "enable watch mode that reruns the simulation on file changes"
|
|
)]
|
|
pub watch: bool,
|
|
#[clap(long, help = "run differential testing between sqlite and Limbo")]
|
|
pub differential: bool,
|
|
#[clap(subcommand)]
|
|
pub subcommand: Option<SimulatorCommand>,
|
|
#[clap(long, help = "disable BugBase", default_value_t = false)]
|
|
pub disable_bugbase: bool,
|
|
#[clap(long, help = "disable UPDATE Statement", default_value_t = false)]
|
|
pub disable_update: bool,
|
|
#[clap(long, help = "disable DELETE Statement", default_value_t = false)]
|
|
pub disable_delete: bool,
|
|
#[clap(long, help = "disable CREATE Statement", default_value_t = false)]
|
|
pub disable_create: bool,
|
|
#[clap(long, help = "disable CREATE INDEX Statement", default_value_t = false)]
|
|
pub disable_create_index: bool,
|
|
#[clap(long, help = "disable DROP Statement", default_value_t = false)]
|
|
pub disable_drop: bool,
|
|
#[clap(
|
|
long,
|
|
help = "disable Insert-Values-Select Property",
|
|
default_value_t = false
|
|
)]
|
|
pub disable_insert_values_select: bool,
|
|
#[clap(
|
|
long,
|
|
help = "disable Double-Create-Failure Property",
|
|
default_value_t = false
|
|
)]
|
|
pub disable_double_create_failure: bool,
|
|
#[clap(long, help = "disable Select-Limit Property", default_value_t = false)]
|
|
pub disable_select_limit: bool,
|
|
#[clap(long, help = "disable Delete-Select Property", default_value_t = false)]
|
|
pub disable_delete_select: bool,
|
|
#[clap(long, help = "disable Drop-Select Property", default_value_t = false)]
|
|
pub disable_drop_select: bool,
|
|
#[clap(
|
|
long,
|
|
help = "disable Select-Select-Optimizer Property",
|
|
default_value_t = false
|
|
)]
|
|
pub disable_select_optimizer: bool,
|
|
#[clap(long, help = "disable Reopen-Database fault", default_value_t = false)]
|
|
pub disable_reopen_database: bool,
|
|
}
|
|
|
|
#[derive(Parser, Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord)]
|
|
pub enum SimulatorCommand {
|
|
#[clap(about = "run the simulator in a loop")]
|
|
Loop {
|
|
#[clap(
|
|
short = 'n',
|
|
long,
|
|
help = "number of iterations to run the simulator",
|
|
default_value_t = 5
|
|
)]
|
|
n: usize,
|
|
#[clap(
|
|
short = 's',
|
|
long,
|
|
help = "short circuit the simulator, stop on the first failure",
|
|
default_value_t = false
|
|
)]
|
|
short_circuit: bool,
|
|
},
|
|
#[clap(about = "list all the bugs in the base")]
|
|
List,
|
|
#[clap(about = "run the simulator against a specific bug")]
|
|
Test {
|
|
#[clap(
|
|
short = 'b',
|
|
long,
|
|
help = "run the simulator with previous buggy runs for the specific filter"
|
|
)]
|
|
filter: String,
|
|
},
|
|
}
|
|
|
|
impl SimulatorCLI {
|
|
pub fn validate(&mut self) -> anyhow::Result<()> {
|
|
if self.minimum_tests < 1 {
|
|
anyhow::bail!("minimum size must be at least 1");
|
|
}
|
|
if self.maximum_tests < 1 {
|
|
anyhow::bail!("maximum size must be at least 1");
|
|
}
|
|
|
|
if self.minimum_tests > self.maximum_tests {
|
|
tracing::warn!(
|
|
"minimum size '{}' is greater than '{}' maximum size, setting both to '{}'",
|
|
self.minimum_tests,
|
|
self.maximum_tests,
|
|
self.maximum_tests
|
|
);
|
|
self.minimum_tests = self.maximum_tests - 1;
|
|
}
|
|
|
|
if self.seed.is_some() && self.load.is_some() {
|
|
anyhow::bail!("Cannot set seed and load plan at the same time");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|