diff --git a/Cargo.lock b/Cargo.lock index 699aa4e96e..1a663a47ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -846,6 +846,7 @@ dependencies = [ "tracing-subscriber", "turso", "turso_core", + "turso_macros", "turso_parser", "twox-hash", "zerocopy 0.8.26", diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 9db89bad28..d787acfde6 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,6 +1,8 @@ -mod ext; extern crate proc_macro; mod atomic_enum; +mod ext; +mod test; + use proc_macro::{token_stream::IntoIter, Group, TokenStream, TokenTree}; use std::collections::HashMap; @@ -492,3 +494,32 @@ pub fn match_ignore_ascii_case(input: TokenStream) -> TokenStream { pub fn derive_atomic_enum(input: TokenStream) -> TokenStream { atomic_enum::derive_atomic_enum_inner(input) } + +/// Test macro for `core_tester` crate +/// +/// Generates a runnable Rust test from the following function signature +/// +/// ```no_run +/// fn test_x(db: TempDatabase) -> Result<()> {} +/// // Or +/// fn test_y(db: TempDatabase) {} +/// ``` +/// +/// Macro accepts the following arguments +/// +/// - `mvcc` flag: creates an additional test that will run the same code with MVCC enabled +/// - `path` arg: specifies the name of the database to be created +/// - `init_sql` arg: specifies the SQL query that will be run by `rusqlite` before initializing the Turso database +/// +/// Example: +/// ```no_run,rust +/// #[turso_macros::test(mvcc, path = "test.db", init_sql = "CREATE TABLE test_rowid (id INTEGER PRIMARY KEY);")] +/// fn test_integer_primary_key(tmp_db: TempDatabase) -> anyhow::Result<()> { +/// // Code goes here to test +/// Ok(()) +/// } +/// ``` +#[proc_macro_attribute] +pub fn test(args: TokenStream, input: TokenStream) -> TokenStream { + test::test_macro_attribute(args, input) +} diff --git a/macros/src/test.rs b/macros/src/test.rs new file mode 100644 index 0000000000..e7ec661e5c --- /dev/null +++ b/macros/src/test.rs @@ -0,0 +1,318 @@ +use std::{collections::HashSet, ops::Deref}; + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{ + parse::{Parse, ParseStream}, + parse_macro_input, + punctuated::Punctuated, + spanned::Spanned, + Expr, Ident, ItemFn, Meta, Pat, ReturnType, Token, Type, +}; + +#[derive(Debug, Clone, Copy)] +struct SpannedType(T, Span); + +impl SpannedType { + fn map(self, func: impl FnOnce(T) -> U) -> SpannedType { + SpannedType(func(self.0), self.1) + } +} + +impl Deref for SpannedType { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl ToTokens for SpannedType { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let span = self.1; + let val = &self.0; + let out_tokens = quote_spanned! {span=> + #val + }; + out_tokens.to_tokens(tokens); + } +} + +#[derive(Debug)] +struct Args { + path: Option>, + mvcc: Option>, + init_sql: Option, +} + +impl Args { + fn get_tmp_db_builder( + &self, + fn_name: &Ident, + tmp_db_ty: &Type, + mvcc: bool, + ) -> proc_macro2::TokenStream { + let mut builder = quote! {#tmp_db_ty::builder()}; + + let db_name = self.path.clone().map_or_else( + || { + let name = format!("{fn_name}.db"); + quote! {#name} + }, + |path| path.to_token_stream(), + ); + + let mut db_opts = quote! { + turso_core::DatabaseOpts::new() + .with_indexes(true) + .with_index_method(true) + .with_encryption(true) + }; + + if let Some(spanned) = self + .mvcc + .filter(|_| mvcc) + .map(|val| val.map(|_| quote! {.with_mvcc(true)})) + { + db_opts = quote! { + #db_opts + #spanned + } + } + + builder = quote! { + #builder + .with_db_name(#db_name) + .with_opts(#db_opts) + }; + + if let Some(expr) = &self.init_sql { + builder = quote! { + #builder + .with_init_sql(#expr) + }; + } + + quote! { + #builder.build() + } + } +} + +impl Parse for Args { + fn parse(input: ParseStream) -> syn::Result { + let args = Punctuated::::parse_terminated(input)?; + let mut seen_args = HashSet::new(); + + let mut path = None; + let mut mvcc = None; + let mut init_sql = None; + + let errors = args + .into_iter() + .filter_map(|meta| { + match meta { + Meta::NameValue(nv) => { + let ident = nv.path.get_ident(); + if let Some(ident) = ident { + let ident_string = ident.to_string(); + match ident_string.as_str() { + "path" => { + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &nv.value + { + path = Some(SpannedType(lit_str.value(), nv.value.span())); + seen_args.insert(ident.clone()); + } else { + return Some(syn::Error::new_spanned( + nv.value, + "argument is not a string literal", + )); + } + } + "init_sql" => { + init_sql = Some(nv.value.clone()); + } + _ => { + return Some(syn::Error::new_spanned( + nv.path, + "unexpected argument", + )) + } + } + } else { + return Some(syn::Error::new_spanned(nv.path, "unexpected argument")); + } + } + Meta::Path(p) => { + let ident = p.get_ident(); + if p.is_ident("mvcc") { + mvcc = Some(SpannedType((), p.span())); + seen_args.insert(ident.unwrap().clone()); + } else { + return Some(syn::Error::new_spanned(p, "unexpected flag")); + } + } + _ => { + return Some(syn::Error::new_spanned(meta, "unexpected argument format")); + } + }; + None + }) + .reduce(|mut accum, err| { + accum.combine(err); + accum + }); + + if let Some(errors) = errors { + return Err(errors); + } + + Ok(Args { + path, + mvcc, + init_sql, + }) + } +} + +struct DatabaseFunction { + input: ItemFn, + tmp_db_fn_arg: (Pat, syn::Type), + args: Args, +} + +impl DatabaseFunction { + fn new(input: ItemFn, tmp_db_fn_arg: (Pat, syn::Type), args: Args) -> Self { + Self { + input, + tmp_db_fn_arg, + args, + } + } + + fn tokens_for_db_type(&self, mvcc: bool) -> proc_macro2::TokenStream { + let ItemFn { + attrs, + vis, + sig, + block, + } = &self.input; + + let fn_name = if mvcc { + Ident::new(&format!("{}_mvcc", sig.ident), sig.ident.span()) + } else { + sig.ident.clone() + }; + let fn_generics = &sig.generics; + + // Check the return type + let is_result = is_result(&sig.output); + + let (arg_name, arg_ty) = &self.tmp_db_fn_arg; + let fn_out = &sig.output; + + let call_func = if is_result { + quote! {(|#arg_name: #arg_ty|#fn_out #block)(#arg_name).unwrap();} + } else { + quote! {(|#arg_name: #arg_ty| #block)(#arg_name);} + }; + + let tmp_db_builder_args = self.args.get_tmp_db_builder(&fn_name, arg_ty, mvcc); + + quote! { + #[test] + #(#attrs)* + #vis fn #fn_name #fn_generics() { + let #arg_name = #tmp_db_builder_args; + + #call_func + } + + } + } +} + +impl ToTokens for DatabaseFunction { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let out = self.tokens_for_db_type(false); + out.to_tokens(tokens); + if self.args.mvcc.is_some() { + let out = self.tokens_for_db_type(true); + out.to_tokens(tokens); + } + } +} + +pub fn test_macro_attribute(args: TokenStream, input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ItemFn); + + let args = parse_macro_input!(args as Args); + + let tmp_db_arg = match check_fn_inputs(&input) { + Ok(fn_arg) => fn_arg, + Err(err) => return err.into_compile_error().into(), + }; + + let db_function = DatabaseFunction::new(input, tmp_db_arg, args); + + db_function.to_token_stream().into() +} + +fn check_fn_inputs(input: &ItemFn) -> syn::Result<(Pat, syn::Type)> { + let msg = "Only 1 function argument can be passed and it must be of type `TempDatabase`"; + let args = &input.sig.inputs; + if args.len() != 1 { + return Err(syn::Error::new_spanned(&input.sig, msg)); + } + let first = args.first().unwrap(); + match first { + syn::FnArg::Receiver(receiver) => Err(syn::Error::new_spanned(receiver, msg)), + syn::FnArg::Typed(pat_type) => { + if let Type::Path(type_path) = pat_type.ty.as_ref() { + // Check if qself is None (not a qualified path like ::Type) + if type_path.qself.is_some() { + return Err(syn::Error::new_spanned(type_path, msg)); + } + + // Get the last segment of the path + // This works for both: + // - Simple: TempDatabase + // - Qualified: crate::TempDatabase, my_module::TempDatabase + if type_path + .path + .segments + .last() + .is_none_or(|segment| segment.ident != "TempDatabase") + { + return Err(syn::Error::new_spanned(type_path, msg)); + } + Ok((*pat_type.pat.clone(), *pat_type.ty.clone())) + } else { + Err(syn::Error::new_spanned(pat_type, msg)) + } + } + } +} + +fn is_result(return_type: &ReturnType) -> bool { + match return_type { + ReturnType::Default => false, // Returns () + ReturnType::Type(_, ty) => { + // Check if the type path contains "Result" + if let syn::Type::Path(type_path) = ty.as_ref() { + type_path + .path + .segments + .last() + .map(|seg| seg.ident == "Result") + .unwrap_or(false) + } else { + false + } + } + } +} diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 9b7ee7f5da..97e6a87777 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -40,6 +40,7 @@ tracing = { workspace = true } [dev-dependencies] test-log = { version = "0.2.17", features = ["trace"] } +turso_macros.workspace = true [features] default = ["test_helper"] diff --git a/tests/fuzz/mod.rs b/tests/fuzz/mod.rs index 95668f00c3..fcca05e2a6 100644 --- a/tests/fuzz/mod.rs +++ b/tests/fuzz/mod.rs @@ -8,7 +8,6 @@ mod fuzz_tests { use rand_chacha::ChaCha8Rng; use rusqlite::{params, types::Value}; use std::{collections::HashSet, io::Write}; - use turso_core::DatabaseOpts; use core_tester::common::{ do_flush, limbo_exec_rows, limbo_exec_rows_fallible, limbo_stmt_get_column_names, @@ -21,9 +20,8 @@ mod fuzz_tests { use super::grammar_generator::SymbolHandle; /// [See this issue for more info](https://github.com/tursodatabase/turso/issues/1763) - #[test] - pub fn fuzz_failure_issue_1763() { - let db = TempDatabase::new_empty(); + #[turso_macros::test(mvcc)] + pub fn fuzz_failure_issue_1763(db: TempDatabase) { let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); let offending_query = "SELECT ((ceil(pow((((2.0))), (-2.0 - -1.0) / log(0.5)))) - -2.0)"; @@ -35,9 +33,8 @@ mod fuzz_tests { ); } - #[test] - pub fn arithmetic_expression_fuzz_ex1() { - let db = TempDatabase::new_empty(); + #[turso_macros::test(mvcc)] + pub fn arithmetic_expression_fuzz_ex1(db: TempDatabase) { let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -54,10 +51,10 @@ mod fuzz_tests { } } - #[test] - pub fn rowid_seek_fuzz() { - let db = - TempDatabase::new_with_rusqlite("CREATE TABLE t (x INTEGER PRIMARY KEY autoincrement)"); // INTEGER PRIMARY KEY is a rowid alias, so an index is not created + // TODO: mvcc fuzz failure + // INTEGER PRIMARY KEY is a rowid alias, so an index is not created + #[turso_macros::test(init_sql = "CREATE TABLE t (x INTEGER PRIMARY KEY autoincrement)")] + pub fn rowid_seek_fuzz(db: TempDatabase) { let sqlite_conn = rusqlite::Connection::open(db.path.clone()).unwrap(); let (mut rng, _seed) = rng_from_time_or_env(); @@ -169,9 +166,9 @@ mod fuzz_tests { values } - #[test] - pub fn index_scan_fuzz() { - let db = TempDatabase::new_with_rusqlite("CREATE TABLE t (x PRIMARY KEY)"); + // TODO: mvcc indexes + #[turso_macros::test(init_sql = "CREATE TABLE t (x PRIMARY KEY)")] + pub fn index_scan_fuzz(db: TempDatabase) { let sqlite_conn = rusqlite::Connection::open(db.path.clone()).unwrap(); let insert = format!( @@ -215,11 +212,16 @@ mod fuzz_tests { } } - #[test] + // TODO: mvcc indexes + #[turso_macros::test()] /// A test for verifying that index seek+scan works correctly for compound keys /// on indexes with various column orderings. - pub fn index_scan_compound_key_fuzz() { + pub fn index_scan_compound_key_fuzz(db: TempDatabase) { let (mut rng, seed) = rng_from_time_or_env(); + + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); let table_defs: [&str; 8] = [ "CREATE TABLE t (x, y, z, nonindexed_col, PRIMARY KEY (x, y, z))", "CREATE TABLE t (x, y, z, nonindexed_col, PRIMARY KEY (x desc, y, z))", @@ -231,16 +233,10 @@ mod fuzz_tests { "CREATE TABLE t (x, y, z, nonindexed_col, PRIMARY KEY (x desc, y desc, z desc))", ]; // Create all different 3-column primary key permutations - let dbs = [ - TempDatabase::new_with_rusqlite(table_defs[0]), - TempDatabase::new_with_rusqlite(table_defs[1]), - TempDatabase::new_with_rusqlite(table_defs[2]), - TempDatabase::new_with_rusqlite(table_defs[3]), - TempDatabase::new_with_rusqlite(table_defs[4]), - TempDatabase::new_with_rusqlite(table_defs[5]), - TempDatabase::new_with_rusqlite(table_defs[6]), - TempDatabase::new_with_rusqlite(table_defs[7]), - ]; + let dbs = table_defs + .iter() + .map(|init_sql| builder.clone().with_init_sql(init_sql).build()) + .collect::>(); let mut pk_tuples = HashSet::new(); while pk_tuples.len() < 100000 { pk_tuples.insert(( @@ -506,12 +502,17 @@ mod fuzz_tests { } } - #[test] - pub fn collation_fuzz() { + // TODO: Mvcc indexes + #[turso_macros::test()] + pub fn collation_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); println!("collation_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + // Build six table variants that assign BINARY/NOCASE/RTRIM across (a,b,c) // and include UNIQUE constraints so that auto-created indexes must honor column collations. let variants: [(&str, &str, &str); 6] = [ @@ -563,7 +564,7 @@ mod fuzz_tests { // Create databases for each variant using rusqlite, then open limbo on the same file. let dbs: Vec = table_defs .iter() - .map(|ddl| TempDatabase::new_with_rusqlite(ddl)) + .map(|ddl| builder.clone().with_init_sql(ddl).build()) .collect(); // Seed data focuses on case and trailing spaces to exercise NOCASE and RTRIM semantics. @@ -649,14 +650,19 @@ mod fuzz_tests { } } - #[test] + // TODO: mvcc indexes + #[turso_macros::test()] #[allow(unused_assignments)] - pub fn fk_deferred_constraints_and_triggers_fuzz() { + pub fn fk_deferred_constraints_and_triggers_fuzz(db: TempDatabase) { let _ = tracing_subscriber::fmt::try_init(); let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); println!("fk_deferred_constraints_and_triggers_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + const OUTER_ITERS: usize = 10; const INNER_ITERS: usize = 100; @@ -667,8 +673,8 @@ mod fuzz_tests { OUTER_ITERS ); - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1087,20 +1093,25 @@ mod fuzz_tests { } } - #[test] - pub fn fk_single_pk_mutation_fuzz() { + // TODO: mvcc state mismatch + #[turso_macros::test()] + pub fn fk_single_pk_mutation_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); println!("fk_single_pk_mutation_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + const OUTER_ITERS: usize = 20; const INNER_ITERS: usize = 100; for outer in 0..OUTER_ITERS { println!("fk_single_pk_mutation_fuzz {}/{}", outer + 1, OUTER_ITERS); - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1389,12 +1400,17 @@ mod fuzz_tests { } } - #[test] - pub fn fk_edgecases_fuzzing() { + // TODO: mvcc does not work + #[turso_macros::test()] + pub fn fk_edgecases_fuzzing(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); println!("fk_edgecases_minifuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + const OUTER_ITERS: usize = 20; const INNER_ITERS: usize = 100; @@ -1424,8 +1440,8 @@ mod fuzz_tests { // parent rowid, child textified integers -> MustBeInt coercion path for outer in 0..OUTER_ITERS { - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1490,8 +1506,8 @@ mod fuzz_tests { // slf-referential rowid FK for outer in 0..OUTER_ITERS { - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1553,8 +1569,8 @@ mod fuzz_tests { // self-referential UNIQUE(u,v) parent (fast-path for composite) for outer in 0..OUTER_ITERS { - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1633,8 +1649,8 @@ mod fuzz_tests { // parent TEXT UNIQUE(u,v), child types differ; rely on parent-index affinities for outer in 0..OUTER_ITERS { - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1744,12 +1760,17 @@ mod fuzz_tests { println!("fk_edgecases_minifuzz complete (seed {seed})"); } - #[test] - pub fn fk_composite_pk_mutation_fuzz() { + // TODO: mvcc indexes + #[turso_macros::test()] + pub fn fk_composite_pk_mutation_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); println!("fk_composite_pk_mutation_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + const OUTER_ITERS: usize = 10; const INNER_ITERS: usize = 100; @@ -1760,8 +1781,8 @@ mod fuzz_tests { OUTER_ITERS ); - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -1954,10 +1975,11 @@ mod fuzz_tests { } } } - #[test] + // TODO: mvcc indexes + #[turso_macros::test()] /// Create a table with a random number of columns and indexes, and then randomly update or delete rows from the table. /// Verify that the results are the same for SQLite and Turso. - pub fn table_index_mutation_fuzz() { + pub fn table_index_mutation_fuzz(db: TempDatabase) { /// Format a nice diff between two result sets for better error messages #[allow(clippy::too_many_arguments)] fn format_rows_diff( @@ -2075,6 +2097,10 @@ mod fuzz_tests { let (mut rng, seed) = rng_from_time_or_env(); println!("table_index_mutation_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + const OUTER_ITERATIONS: usize = 30; for i in 0..OUTER_ITERATIONS { println!( @@ -2082,8 +2108,8 @@ mod fuzz_tests { i + 1, OUTER_ITERATIONS ); - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let num_cols = rng.random_range(1..=10); let mut table_cols = vec!["id INTEGER PRIMARY KEY AUTOINCREMENT".to_string()]; table_cols.extend( @@ -2444,21 +2470,31 @@ mod fuzz_tests { } } - #[test] - pub fn partial_index_mutation_and_upsert_fuzz() { - index_mutation_upsert_fuzz(1.0, 4); + // TODO: mvcc index + #[turso_macros::test()] + pub fn partial_index_mutation_and_upsert_fuzz(db: TempDatabase) { + index_mutation_upsert_fuzz(db, 1.0, 4); } - #[test] - pub fn simple_index_mutation_and_upsert_fuzz() { - index_mutation_upsert_fuzz(0.0, 4); + // TODO: mvcc fails + #[turso_macros::test()] + pub fn simple_index_mutation_and_upsert_fuzz(db: TempDatabase) { + index_mutation_upsert_fuzz(db, 0.0, 4); } - fn index_mutation_upsert_fuzz(partial_index_prob: f64, conflict_chain_max_len: u32) { + fn index_mutation_upsert_fuzz( + db: TempDatabase, + partial_index_prob: f64, + conflict_chain_max_len: u32, + ) { let _ = env_logger::try_init(); const OUTER_ITERS: usize = 5; const INNER_ITERS: usize = 500; + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + let (mut rng, seed) = rng_from_time_or_env(); println!("partial_index_mutation_and_upsert_fuzz seed: {seed}"); // we want to hit unique constraints fairly often so limit the insert values @@ -2476,8 +2512,8 @@ mod fuzz_tests { ); // Columns: id (rowid PK), plus a few data columns we can reference in predicates/keys. - let limbo_db = TempDatabase::new_empty(); - let sqlite_db = TempDatabase::new_empty(); + let limbo_db = builder.clone().build(); + let sqlite_db = builder.clone().build(); let limbo_conn = limbo_db.connect_limbo(); let sqlite = rusqlite::Connection::open(sqlite_db.path.clone()).unwrap(); @@ -2810,8 +2846,9 @@ mod fuzz_tests { } } - #[test] - pub fn compound_select_fuzz() { + // TODO: mvcc fails + #[turso_macros::test()] + pub fn compound_select_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("compound_select_fuzz seed: {seed}"); @@ -2826,7 +2863,6 @@ mod fuzz_tests { const MAX_SELECTS_IN_UNION_EXTRA: usize = 2; const MAX_LIMIT_VALUE: usize = 50; - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -2946,13 +2982,19 @@ mod fuzz_tests { } } - #[test] - pub fn ddl_compatibility_fuzz() { + // TODO: indexes + #[turso_macros::test()] + pub fn ddl_compatibility_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); const ITERATIONS: usize = 1000; + + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for i in 0..ITERATIONS { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let conn = db.connect_limbo(); let num_cols = rng.random_range(1..=5); let col_names: Vec = (0..num_cols).map(|c| format!("c{c}")).collect(); @@ -3070,8 +3112,8 @@ mod fuzz_tests { } } - #[test] - pub fn arithmetic_expression_fuzz() { + #[turso_macros::test(mvcc)] + pub fn arithmetic_expression_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let g = GrammarGenerator::new(); let (expr, expr_builder) = g.create_handle(); @@ -3114,7 +3156,6 @@ mod fuzz_tests { let sql = g.create().concat(" ").push_str("SELECT").push(expr).build(); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3131,10 +3172,9 @@ mod fuzz_tests { } } - #[test] - pub fn fuzz_ex() { + #[turso_macros::test(mvcc)] + pub fn fuzz_ex(db: TempDatabase) { let _ = env_logger::try_init(); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3158,8 +3198,8 @@ mod fuzz_tests { } } - #[test] - pub fn math_expression_fuzz_run() { + #[turso_macros::test(mvcc)] + pub fn math_expression_fuzz_run(db: TempDatabase) { let _ = env_logger::try_init(); let g = GrammarGenerator::new(); let (expr, expr_builder) = g.create_handle(); @@ -3233,7 +3273,6 @@ mod fuzz_tests { let sql = g.create().concat(" ").push_str("SELECT").push(expr).build(); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3260,8 +3299,8 @@ mod fuzz_tests { } } - #[test] - pub fn string_expression_fuzz_run() { + #[turso_macros::test(mvcc)] + pub fn string_expression_fuzz_run(db: TempDatabase) { let _ = env_logger::try_init(); let g = GrammarGenerator::new(); let (expr, expr_builder) = g.create_handle(); @@ -3393,7 +3432,6 @@ mod fuzz_tests { let sql = g.create().concat(" ").push_str("SELECT").push(expr).build(); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3748,8 +3786,8 @@ mod fuzz_tests { handle } - #[test] - pub fn logical_expression_fuzz_run() { + #[turso_macros::test(mvcc)] + pub fn logical_expression_fuzz_run(db: TempDatabase) { let _ = env_logger::try_init(); let g = GrammarGenerator::new(); let builders = common_builders(&g, None); @@ -3762,7 +3800,6 @@ mod fuzz_tests { .push(expr) .build(); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3780,10 +3817,14 @@ mod fuzz_tests { } } - #[test] - pub fn table_logical_expression_fuzz_ex1() { + #[turso_macros::test(mvcc)] + pub fn table_logical_expression_fuzz_ex1(db: TempDatabase) { let _ = env_logger::try_init(); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for queries in [ [ "CREATE TABLE t (x)", @@ -3796,7 +3837,7 @@ mod fuzz_tests { "SELECT * FROM t", ], ] { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); for query in queries.iter() { @@ -3810,20 +3851,24 @@ mod fuzz_tests { } } - #[test] - pub fn min_max_agg_fuzz() { + #[turso_macros::test(mvcc)] + pub fn min_max_agg_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let datatypes = ["INTEGER", "TEXT", "REAL", "BLOB"]; let (mut rng, seed) = rng_from_time_or_env(); log::info!("seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..1000 { // Create table with random datatype let datatype = datatypes[rng.random_range(0..datatypes.len())]; let create_table = format!("CREATE TABLE t (x {datatype})"); - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3866,15 +3911,19 @@ mod fuzz_tests { } } - #[test] - pub fn affinity_fuzz() { + #[turso_macros::test(mvcc)] + pub fn affinity_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("affinity_fuzz seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for iteration in 0..500 { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -3966,16 +4015,20 @@ mod fuzz_tests { } } - #[test] + #[turso_macros::test(mvcc)] // Simple fuzz test for SUM with floats - pub fn sum_agg_fuzz_floats() { + pub fn sum_agg_fuzz_floats(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..100 { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -4012,16 +4065,20 @@ mod fuzz_tests { } } - #[test] + #[turso_macros::test(mvcc)] // Simple fuzz test for SUM with mixed numeric/non-numeric values (issue #2133) - pub fn sum_agg_fuzz() { + pub fn sum_agg_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..100 { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -4057,15 +4114,19 @@ mod fuzz_tests { } } - #[test] - fn concat_ws_fuzz() { + #[turso_macros::test(mvcc)] + fn concat_ws_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..100 { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -4102,16 +4163,20 @@ mod fuzz_tests { } } - #[test] + #[turso_macros::test(mvcc)] // Simple fuzz test for TOTAL with mixed numeric/non-numeric values - pub fn total_agg_fuzz() { + pub fn total_agg_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("seed: {seed}"); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..100 { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -4147,8 +4212,9 @@ mod fuzz_tests { } } - #[test] - pub fn table_logical_expression_fuzz_run() { + // TODO: mvcc indexes + #[turso_macros::test()] + pub fn table_logical_expression_fuzz_run(db: TempDatabase) { let _ = env_logger::try_init(); let g = GrammarGenerator::new(); let tables = vec![TestTable { @@ -4159,7 +4225,6 @@ mod fuzz_tests { let predicate = predicate_builders(&g, Some(&tables)); let expr = build_logical_expr(&g, &builders, Some(&predicate)); - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); for table in tables.iter() { @@ -4248,9 +4313,8 @@ mod fuzz_tests { } } - #[test] - pub fn fuzz_distinct() { - let db = TempDatabase::new_empty(); + #[turso_macros::test(mvcc)] + pub fn fuzz_distinct(db: TempDatabase) { let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); @@ -4314,25 +4378,16 @@ mod fuzz_tests { } } - #[test] - pub fn fuzz_long_create_table_drop_table_alter_table_normal() { - _fuzz_long_create_table_drop_table_alter_table(false); - } - - #[test] - pub fn fuzz_long_create_table_drop_table_alter_table_mvcc() { - _fuzz_long_create_table_drop_table_alter_table(true); - } - - fn _fuzz_long_create_table_drop_table_alter_table(mvcc: bool) { - let db = TempDatabase::new_with_opts( - "fuzz_long_create_table_drop_table_alter_table", - DatabaseOpts::new().with_mvcc(mvcc).with_indexes(!mvcc), - ); + #[turso_macros::test(mvcc)] + fn fuzz_long_create_table_drop_table_alter_table(db: TempDatabase) { let limbo_conn = db.connect_limbo(); let (mut rng, seed) = rng_from_time_or_env(); - tracing::info!("create_table_drop_table_fuzz seed: {seed}, mvcc: {mvcc}"); + let mvcc = db.db_opts.enable_mvcc; + tracing::info!( + "create_table_drop_table_fuzz seed: {seed}, mvcc: {}", + db.db_opts.enable_mvcc + ); // Keep track of current tables and their columns in memory let mut current_tables: std::collections::HashMap> = @@ -4541,9 +4596,9 @@ mod fuzz_tests { ); } - #[test] + #[turso_macros::test()] #[cfg(feature = "test_helper")] - pub fn fuzz_pending_byte_database() -> anyhow::Result<()> { + pub fn fuzz_pending_byte_database(db: TempDatabase) -> anyhow::Result<()> { use core_tester::common::rusqlite_integrity_check; maybe_setup_tracing(); @@ -4558,6 +4613,10 @@ mod fuzz_tests { const MAX_PAGENO: u32 = MAX_DB_SIZE_BYTES / PAGE_SIZE; + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..10 { // generate a random pending page that is smaller than the 100 MB mark @@ -4569,7 +4628,7 @@ mod fuzz_tests { let db_path = tempfile::NamedTempFile::new()?; { - let db = TempDatabase::new_with_existent(db_path.path()); + let db = builder.clone().with_db_path(db_path.path()).build(); let prev_pending_byte = TempDatabase::get_pending_byte(); tracing::debug!(prev_pending_byte); @@ -4599,9 +4658,10 @@ mod fuzz_tests { Ok(()) } - #[test] + // TODO: mvcc indexes + #[turso_macros::test()] /// Tests for correlated and uncorrelated subqueries occurring in the WHERE clause of a SELECT statement. - pub fn table_subquery_fuzz() { + pub fn table_subquery_fuzz(db: TempDatabase) { let _ = env_logger::try_init(); let (mut rng, seed) = rng_from_time_or_env(); log::info!("table_subquery_fuzz seed: {seed}"); @@ -4612,7 +4672,6 @@ mod fuzz_tests { const MIN_ROWS_PER_TABLE: usize = 5; const MAX_SUBQUERY_DEPTH: usize = 4; - let db = TempDatabase::new_empty(); let limbo_conn = db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); diff --git a/tests/integration/common.rs b/tests/integration/common.rs index a8a37077a9..5bc29ea7f5 100644 --- a/tests/integration/common.rs +++ b/tests/integration/common.rs @@ -7,109 +7,162 @@ use tempfile::TempDir; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; use turso_core::{Connection, Database, Row, StepResult, IO}; -#[allow(dead_code)] pub struct TempDatabase { pub path: PathBuf, pub io: Arc, pub db: Arc, + pub db_opts: turso_core::DatabaseOpts, + #[allow(dead_code)] + pub db_flags: turso_core::OpenFlags, } unsafe impl Send for TempDatabase {} -#[allow(dead_code, clippy::arc_with_non_send_sync)] -impl TempDatabase { - pub fn new_empty() -> Self { - Self::new(&format!("test-{}.db", rng().next_u32())) +#[derive(Debug, Default, Clone)] +pub struct TempDatabaseBuilder { + db_name: Option, + db_path: Option, + opts: Option, + flags: Option, + init_sql: Option, +} + +impl TempDatabaseBuilder { + pub const fn new() -> Self { + Self { + db_name: None, + db_path: None, + opts: None, + flags: None, + init_sql: None, + } } - pub fn new(db_name: &str) -> Self { - let mut path = TempDir::new().unwrap().keep(); - path.push(db_name); + /// Db Name is mutually exclusive with Db Path + pub fn with_db_name(mut self, db_name: impl AsRef) -> Self { + assert!( + self.db_path.is_none(), + "DB Name and DB Path are mutually exclusive options" + ); - Self::new_with_existent(&path) + self.db_name = Some(db_name.as_ref().to_string()); + self.db_path = None; + self } - pub fn new_with_opts(db_name: &str, opts: turso_core::DatabaseOpts) -> Self { - let mut path = TempDir::new().unwrap().keep(); - path.push(db_name); - let io: Arc = Arc::new(turso_core::PlatformIO::new().unwrap()); + /// Db Path is mutually exclusive with Db Name + pub fn with_db_path(mut self, db_path: impl AsRef) -> Self { + assert!( + self.db_name.is_none(), + "DB Name and DB Path are mutually exclusive options" + ); + self.db_path = Some(db_path.as_ref().to_path_buf()); + self + } + + pub fn with_opts(mut self, opts: turso_core::DatabaseOpts) -> Self { + self.opts = Some(opts); + self + } + + pub fn with_flags(mut self, flags: turso_core::OpenFlags) -> Self { + self.flags = Some(flags); + self + } + + pub fn with_init_sql(mut self, init_sql: impl AsRef) -> Self { + self.init_sql = Some(init_sql.as_ref().to_string()); + self + } + + pub fn build(self) -> TempDatabase { + let opts = self.opts.unwrap_or_else(|| { + turso_core::DatabaseOpts::new() + .with_indexes(true) + .with_encryption(true) + }); + + let flags = self.flags.unwrap_or_default(); + + let db_path = match self.db_path { + Some(db_path) => db_path, + None => { + let db_name = self + .db_name + .unwrap_or_else(|| format!("test-{}.db", rng().next_u32())); + let mut db_path = TempDir::new().unwrap().keep(); + db_path.push(db_name); + db_path + } + }; + + if let Some(init_sql) = self.init_sql { + let connection = rusqlite::Connection::open(&db_path).unwrap(); + connection + .pragma_update(None, "journal_mode", "wal") + .unwrap(); + connection.execute(&init_sql, ()).unwrap(); + } + + let io = Arc::new(turso_core::PlatformIO::new().unwrap()); let db = Database::open_file_with_flags( io.clone(), - path.to_str().unwrap(), - turso_core::OpenFlags::default(), + db_path.to_str().unwrap(), + flags, opts, None, ) .unwrap(); - Self { - path: path.to_path_buf(), + TempDatabase { + path: db_path, io, db, + db_opts: opts, + db_flags: flags, } } +} + +#[allow(clippy::arc_with_non_send_sync)] +impl TempDatabase { + pub const fn builder() -> TempDatabaseBuilder { + TempDatabaseBuilder::new() + } + + pub fn new_empty() -> Self { + Self::builder().build() + } + + pub fn new(db_name: &str) -> Self { + Self::builder().with_db_name(db_name).build() + } + + pub fn new_with_opts(db_name: &str, opts: turso_core::DatabaseOpts) -> Self { + Self::builder() + .with_db_name(db_name) + .with_opts(opts) + .build() + } pub fn new_with_existent(db_path: &Path) -> Self { - Self::new_with_existent_with_flags(db_path, turso_core::OpenFlags::default()) + Self::builder().with_db_path(db_path).build() } pub fn new_with_existent_with_opts(db_path: &Path, opts: turso_core::DatabaseOpts) -> Self { - let io: Arc = Arc::new(turso_core::PlatformIO::new().unwrap()); - let db = Database::open_file_with_flags( - io.clone(), - db_path.to_str().unwrap(), - turso_core::OpenFlags::default(), - opts, - None, - ) - .unwrap(); - Self { - path: db_path.to_path_buf(), - io, - db, - } + Self::builder() + .with_db_path(db_path) + .with_opts(opts) + .build() } pub fn new_with_existent_with_flags(db_path: &Path, flags: turso_core::OpenFlags) -> Self { - let io: Arc = Arc::new(turso_core::PlatformIO::new().unwrap()); - let db = Database::open_file_with_flags( - io.clone(), - db_path.to_str().unwrap(), - flags, - turso_core::DatabaseOpts::new() - .with_indexes(true) - .with_encryption(true), - None, - ) - .unwrap(); - Self { - path: db_path.to_path_buf(), - io, - db, - } + Self::builder() + .with_db_path(db_path) + .with_flags(flags) + .build() } pub fn new_with_rusqlite(table_sql: &str) -> Self { - let mut path = TempDir::new().unwrap().keep(); - path.push("test.db"); - { - let connection = rusqlite::Connection::open(&path).unwrap(); - connection - .pragma_update(None, "journal_mode", "wal") - .unwrap(); - connection.execute(table_sql, ()).unwrap(); - } - let io: Arc = Arc::new(turso_core::PlatformIO::new().unwrap()); - let db = Database::open_file_with_flags( - io.clone(), - path.to_str().unwrap(), - turso_core::OpenFlags::default(), - turso_core::DatabaseOpts::new() - .with_indexes(true) - .with_index_method(true), - None, - ) - .unwrap(); - - Self { path, io, db } + Self::builder().with_init_sql(table_sql).build() } pub fn connect_limbo(&self) -> Arc { @@ -131,6 +184,7 @@ impl TempDatabase { .unwrap() } + #[allow(dead_code)] #[cfg(feature = "test_helper")] pub fn get_pending_byte() -> u32 { let pending_byte_sqlite = unsafe { @@ -141,6 +195,7 @@ impl TempDatabase { pending_byte_turso } + #[allow(dead_code)] #[cfg(feature = "test_helper")] pub fn set_pending_byte(offset: u32) { unsafe { @@ -149,6 +204,7 @@ impl TempDatabase { Database::set_pending_byte(offset); } + #[allow(dead_code)] #[cfg(feature = "test_helper")] pub fn reset_pending_byte() { // 1 Gib diff --git a/tests/integration/functions/test_cdc.rs b/tests/integration/functions/test_cdc.rs index 25761f5c00..8f21938d6f 100644 --- a/tests/integration/functions/test_cdc.rs +++ b/tests/integration/functions/test_cdc.rs @@ -14,9 +14,8 @@ fn replace_column_with_null(rows: Vec>, column: usize) -> Vec(values: [Value; N]) -> Vec { .to_vec() } -#[test] -fn test_cdc_simple_before() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_cdc_simple_before(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y)") .unwrap(); @@ -147,9 +145,8 @@ fn test_cdc_simple_before() { ); } -#[test] -fn test_cdc_simple_after() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_cdc_simple_after(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y)") .unwrap(); @@ -218,9 +215,8 @@ fn test_cdc_simple_after() { ); } -#[test] -fn test_cdc_simple_full() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_cdc_simple_full(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y)") .unwrap(); @@ -294,9 +290,8 @@ fn test_cdc_simple_full() { ); } -#[test] -fn test_cdc_crud() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_cdc_crud(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y)") .unwrap(); @@ -415,9 +410,9 @@ fn test_cdc_crud() { ); } -#[test] -fn test_cdc_failed_op() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_failed_op(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y UNIQUE)") .unwrap(); @@ -489,9 +484,9 @@ fn test_cdc_failed_op() { ); } -#[test] -fn test_cdc_uncaptured_connection() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_uncaptured_connection(db: TempDatabase) { let conn1 = db.connect_limbo(); conn1 .execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y UNIQUE)") @@ -569,9 +564,9 @@ fn test_cdc_uncaptured_connection() { ); } -#[test] -fn test_cdc_custom_table() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_custom_table(db: TempDatabase) { let conn1 = db.connect_limbo(); conn1 .execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y UNIQUE)") @@ -618,9 +613,9 @@ fn test_cdc_custom_table() { ); } -#[test] -fn test_cdc_ignore_changes_in_cdc_table() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_ignore_changes_in_cdc_table(db: TempDatabase) { let conn1 = db.connect_limbo(); conn1 .execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y UNIQUE)") @@ -658,9 +653,9 @@ fn test_cdc_ignore_changes_in_cdc_table() { ); } -#[test] -fn test_cdc_transaction() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_transaction(db: TempDatabase) { let conn1 = db.connect_limbo(); conn1 .execute("CREATE TABLE t (x INTEGER PRIMARY KEY, y UNIQUE)") @@ -741,9 +736,9 @@ fn test_cdc_transaction() { ); } -#[test] -fn test_cdc_independent_connections() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_independent_connections(db: TempDatabase) { let conn1 = db.connect_limbo(); let conn2 = db.connect_limbo(); conn1 @@ -797,9 +792,9 @@ fn test_cdc_independent_connections() { ); } -#[test] -fn test_cdc_independent_connections_different_cdc_not_ignore() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_independent_connections_different_cdc_not_ignore(db: TempDatabase) { let conn1 = db.connect_limbo(); let conn2 = db.connect_limbo(); conn1 @@ -887,9 +882,9 @@ fn test_cdc_independent_connections_different_cdc_not_ignore() { ); } -#[test] -fn test_cdc_table_columns() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_table_columns(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (a INTEGER PRIMARY KEY, b, c UNIQUE)") .unwrap(); @@ -903,9 +898,8 @@ fn test_cdc_table_columns() { assert_eq!(rows, vec![vec![Value::Text(r#"["a","c"]"#.to_string())]]); } -#[test] -fn test_cdc_bin_record() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_cdc_bin_record(db: TempDatabase) { let conn = db.connect_limbo(); let record = record([ Value::Null, @@ -932,9 +926,9 @@ fn test_cdc_bin_record() { ); } -#[test] -fn test_cdc_schema_changes() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_schema_changes(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("PRAGMA unstable_capture_data_changes_conn('full')") .unwrap(); @@ -1054,9 +1048,9 @@ fn test_cdc_schema_changes() { ); } -#[test] -fn test_cdc_schema_changes_alter_table() { - let db = TempDatabase::new_empty(); +// TODO: cannot use mvcc because of indexes +#[turso_macros::test()] +fn test_cdc_schema_changes_alter_table(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("PRAGMA unstable_capture_data_changes_conn('full')") .unwrap(); diff --git a/tests/integration/functions/test_function_rowid.rs b/tests/integration/functions/test_function_rowid.rs index a5c0851896..4ff3aed762 100644 --- a/tests/integration/functions/test_function_rowid.rs +++ b/tests/integration/functions/test_function_rowid.rs @@ -1,12 +1,12 @@ use crate::common::{do_flush, TempDatabase}; use turso_core::StepResult; -#[test] -fn test_last_insert_rowid_basic() -> anyhow::Result<()> { +#[turso_macros::test( + mvcc, + init_sql = "CREATE TABLE test_rowid (id INTEGER PRIMARY KEY, val TEXT);" +)] +fn test_last_insert_rowid_basic(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite( - "CREATE TABLE test_rowid (id INTEGER PRIMARY KEY, val TEXT);", - ); let conn = tmp_db.connect_limbo(); // Simple insert @@ -86,11 +86,9 @@ fn test_last_insert_rowid_basic() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_integer_primary_key() -> anyhow::Result<()> { +#[turso_macros::test(mvcc, init_sql = "CREATE TABLE test_rowid (id INTEGER PRIMARY KEY);")] +fn test_integer_primary_key(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test_rowid (id INTEGER PRIMARY KEY);"); let conn = tmp_db.connect_limbo(); for query in &[ diff --git a/tests/integration/functions/test_sum.rs b/tests/integration/functions/test_sum.rs index 1df9e71069..1543fb0595 100644 --- a/tests/integration/functions/test_sum.rs +++ b/tests/integration/functions/test_sum.rs @@ -1,11 +1,10 @@ use crate::common::{limbo_exec_rows, limbo_exec_rows_fallible, sqlite_exec_rows, TempDatabase}; use turso_core::LimboError; -#[test] -fn sum_errors_on_integer_overflow() { +#[turso_macros::test(mvcc)] +fn sum_errors_on_integer_overflow(tmp_db: TempDatabase) { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_empty(); let conn = tmp_db.connect_limbo(); let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap(); diff --git a/tests/integration/functions/test_wal_api.rs b/tests/integration/functions/test_wal_api.rs index af1835a063..072220320e 100644 --- a/tests/integration/functions/test_wal_api.rs +++ b/tests/integration/functions/test_wal_api.rs @@ -11,9 +11,9 @@ use turso_core::{ use crate::common::{limbo_exec_rows, rng_from_time, TempDatabase}; -#[test] -fn test_wal_frame_count() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_count(db: TempDatabase) { let conn = db.connect_limbo(); assert_eq!(conn.wal_state().unwrap().max_frame, 0); conn.execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -27,11 +27,15 @@ fn test_wal_frame_count() { assert_eq!(conn.wal_state().unwrap().max_frame, 15); } -#[test] -fn test_wal_frame_transfer_no_schema_changes() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_transfer_no_schema_changes(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -66,11 +70,16 @@ fn test_wal_frame_transfer_no_schema_changes() { ); } -#[test] -fn test_wal_frame_transfer_various_schema_changes() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_transfer_various_schema_changes(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); let conn3 = db2.connect_limbo(); conn1 @@ -125,11 +134,16 @@ fn test_wal_frame_transfer_various_schema_changes() { ); } -#[test] -fn test_wal_frame_transfer_schema_changes() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_transfer_schema_changes(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -164,11 +178,16 @@ fn test_wal_frame_transfer_schema_changes() { ); } -#[test] -fn test_wal_frame_transfer_no_schema_changes_rollback() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_transfer_no_schema_changes_rollback(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -203,11 +222,16 @@ fn test_wal_frame_transfer_no_schema_changes_rollback() { ); } -#[test] -fn test_wal_frame_transfer_schema_changes_rollback() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_transfer_schema_changes_rollback(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -238,11 +262,16 @@ fn test_wal_frame_transfer_schema_changes_rollback() { ); } -#[test] -fn test_wal_frame_conflict() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_conflict(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -257,11 +286,16 @@ fn test_wal_frame_conflict() { assert!(conn2.wal_insert_frame(1, &frame).is_err()); } -#[test] -fn test_wal_frame_far_away_write() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_far_away_write(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.clone().build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -283,13 +317,19 @@ fn test_wal_frame_far_away_write() { assert!(conn2.wal_insert_frame(5, &frame).is_err()); } -#[test] -fn test_wal_frame_api_no_schema_changes_fuzz() { +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_frame_api_no_schema_changes_fuzz(db: TempDatabase) { let (mut rng, _) = rng_from_time(); + + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for _ in 0..4 { - let db1 = TempDatabase::new_empty(); + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.clone().build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -340,9 +380,9 @@ fn test_wal_frame_api_no_schema_changes_fuzz() { } } -#[test] -fn test_wal_api_changed_pages() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_api_changed_pages(db1: TempDatabase) { let conn1 = db1.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -419,9 +459,9 @@ fn revert_to(conn: &Arc, frame_watermark: u64) -> turso_ Ok(()) } -#[test] -fn test_wal_api_revert_pages() { - let db1 = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_api_revert_pages(db1: TempDatabase) { let conn1 = db1.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") @@ -463,9 +503,9 @@ fn test_wal_api_revert_pages() { ); } -#[test] -fn test_wal_upper_bound_passive() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_upper_bound_passive(db: TempDatabase) { let writer = db.connect_limbo(); writer @@ -518,9 +558,9 @@ fn test_wal_upper_bound_passive() { } } -#[test] -fn test_wal_upper_bound_truncate() { - let db = TempDatabase::new_empty(); +// TODO: enable MVCC +#[turso_macros::test()] +fn test_wal_upper_bound_truncate(db: TempDatabase) { let writer = db.connect_limbo(); writer @@ -546,9 +586,9 @@ fn test_wal_upper_bound_truncate() { .unwrap(); } -#[test] -fn test_wal_state_checkpoint_seq() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_state_checkpoint_seq(db: TempDatabase) { let writer = db.connect_limbo(); writer @@ -584,9 +624,9 @@ fn test_wal_state_checkpoint_seq() { ); } -#[test] -fn test_wal_checkpoint_no_work() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_checkpoint_no_work(db: TempDatabase) { let writer = db.connect_limbo(); let reader = db.connect_limbo(); @@ -629,9 +669,9 @@ fn test_wal_checkpoint_no_work() { reader.execute("SELECT * FROM test").unwrap(); } -#[test] -fn test_wal_revert_change_db_size() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_revert_change_db_size(db: TempDatabase) { let writer = db.connect_limbo(); writer.execute("create table t(x, y)").unwrap(); @@ -676,9 +716,9 @@ fn test_wal_revert_change_db_size() { ); } -#[test] -fn test_wal_api_exec_commit() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_api_exec_commit(db: TempDatabase) { let writer = db.connect_limbo(); writer @@ -723,9 +763,8 @@ fn test_wal_api_exec_commit() { ); } -#[test] -fn test_wal_api_exec_rollback() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_wal_api_exec_rollback(db: TempDatabase) { let writer = db.connect_limbo(); writer @@ -758,9 +797,9 @@ fn test_wal_api_exec_rollback() { assert_eq!(rows, vec![] as Vec>); } -#[test] -fn test_wal_api_insert_exec_mix() { - let db = TempDatabase::new_empty(); +// TODO: mvcc +#[turso_macros::test()] +fn test_wal_api_insert_exec_mix(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("create table a(x, y)").unwrap(); @@ -854,6 +893,7 @@ fn test_wal_api_insert_exec_mix() { ); } +// TODO: see later how this test should work with mvcc #[test] fn test_db_share_same_file() { let mut path = TempDir::new().unwrap().keep(); @@ -925,12 +965,16 @@ fn test_db_share_same_file() { ); } -#[test] -fn test_wal_api_simulate_spilled_frames() { +#[turso_macros::test(mvcc)] +fn test_wal_api_simulate_spilled_frames(db: TempDatabase) { let (mut rng, _) = rng_from_time(); - let db1 = TempDatabase::new_empty(); + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + + let db1 = builder.clone().build(); let conn1 = db1.connect_limbo(); - let db2 = TempDatabase::new_empty(); + let db2 = builder.build(); let conn2 = db2.connect_limbo(); conn1 .execute("CREATE TABLE t(x INTEGER PRIMARY KEY, y)") diff --git a/tests/integration/index_method/mod.rs b/tests/integration/index_method/mod.rs index 8285a258f3..2d5e7451f6 100644 --- a/tests/integration/index_method/mod.rs +++ b/tests/integration/index_method/mod.rs @@ -35,10 +35,10 @@ fn sparse_vector(v: &str) -> Value { vector::operations::serialize::vector_serialize(vector) } -#[test] -fn test_vector_sparse_ivf_create_destroy() { +// TODO: cannot use MVCC as we use indexes here +#[turso_macros::test(init_sql = "CREATE TABLE t(name, embedding)")] +fn test_vector_sparse_ivf_create_destroy(tmp_db: TempDatabase) { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t(name, embedding)"); let conn = tmp_db.connect_limbo(); let schema_rows = || { @@ -89,10 +89,10 @@ fn test_vector_sparse_ivf_create_destroy() { assert_eq!(schema_rows(), vec!["t"]); } -#[test] -fn test_vector_sparse_ivf_insert_query() { +// TODO: cannot use MVCC as we use indexes here +#[turso_macros::test(init_sql = "CREATE TABLE t(name, embedding)")] +fn test_vector_sparse_ivf_insert_query(tmp_db: TempDatabase) { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t(name, embedding)"); let conn = tmp_db.connect_limbo(); let index = VectorSparseInvertedIndexMethod; @@ -179,10 +179,10 @@ fn test_vector_sparse_ivf_insert_query() { } } -#[test] -fn test_vector_sparse_ivf_update() { +// TODO: cannot use MVCC as we use indexes here +#[turso_macros::test(init_sql = "CREATE TABLE t(name, embedding)")] +fn test_vector_sparse_ivf_update(tmp_db: TempDatabase) { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t(name, embedding)"); let conn = tmp_db.connect_limbo(); let index = VectorSparseInvertedIndexMethod; @@ -259,10 +259,14 @@ fn test_vector_sparse_ivf_update() { assert!(!run(&tmp_db, || reader.query_next()).unwrap()); } -#[test] -fn test_vector_sparse_ivf_fuzz() { +// TODO: cannot use MVCC as we use indexes here +#[turso_macros::test] +fn test_vector_sparse_ivf_fuzz(tmp_db: TempDatabase) { let _ = env_logger::try_init(); + let opts = tmp_db.db_opts; + let flags = tmp_db.db_flags; + const DIMS: usize = 40; const MOD: u32 = 5; @@ -273,10 +277,12 @@ fn test_vector_sparse_ivf_fuzz() { tracing::info!("======== seed: {} ========", seed); let mut rng = ChaCha8Rng::seed_from_u64(seed); - let simple_db = - TempDatabase::new_with_rusqlite("CREATE TABLE t(key TEXT PRIMARY KEY, embedding)"); - let index_db = - TempDatabase::new_with_rusqlite("CREATE TABLE t(key TEXT PRIMARY KEY, embedding)"); + let builder = TempDatabase::builder() + .with_opts(opts) + .with_flags(flags) + .with_init_sql("CREATE TABLE t(key TEXT PRIMARY KEY, embedding)"); + let simple_db = builder.clone().build(); + let index_db = builder.build(); tracing::info!( "simple_db: {:?}, index_db: {:?}", simple_db.path, diff --git a/tests/integration/pragma.rs b/tests/integration/pragma.rs index c9c7c45240..93652f0e8c 100644 --- a/tests/integration/pragma.rs +++ b/tests/integration/pragma.rs @@ -1,9 +1,8 @@ use crate::common::TempDatabase; use turso_core::{StepResult, Value}; -#[test] -fn test_pragma_module_list_returns_list() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_pragma_module_list_returns_list(db: TempDatabase) { let conn = db.connect_limbo(); let mut module_list = conn.query("PRAGMA module_list;").unwrap(); @@ -19,9 +18,8 @@ fn test_pragma_module_list_returns_list() { assert!(counter > 0) } -#[test] -fn test_pragma_module_list_generate_series() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_pragma_module_list_generate_series(db: TempDatabase) { let conn = db.connect_limbo(); let mut rows = conn @@ -58,10 +56,14 @@ fn test_pragma_module_list_generate_series() { assert!(found, "generate_series should appear in module_list"); } -#[test] -fn test_pragma_page_sizes_without_writes_persists() { +#[turso_macros::test(mvcc)] +fn test_pragma_page_sizes_without_writes_persists(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for test_page_size in [512, 1024, 2048, 4096, 8192, 16384, 32768, 65536] { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); { let conn = db.connect_limbo(); let pragma_query = format!("PRAGMA page_size={test_page_size}"); @@ -81,7 +83,7 @@ fn test_pragma_page_sizes_without_writes_persists() { assert_eq!(*page_size, test_page_size); // Reopen database and verify page size - let db = TempDatabase::new_with_existent(&db.path); + let db = builder.clone().with_db_path(&db.path).build(); let conn = db.connect_limbo(); let mut rows = conn.query("PRAGMA page_size").unwrap().unwrap(); let StepResult::Row = rows.step().unwrap() else { @@ -95,10 +97,14 @@ fn test_pragma_page_sizes_without_writes_persists() { } } -#[test] -fn test_pragma_page_sizes_with_writes_persists() { +#[turso_macros::test(mvcc)] +fn test_pragma_page_sizes_with_writes_persists(db: TempDatabase) { + let opts = db.db_opts; + let flags = db.db_flags; + let builder = TempDatabase::builder().with_flags(flags).with_opts(opts); + for test_page_size in [512, 1024, 2048, 4096, 8192, 16384, 32768, 65536] { - let db = TempDatabase::new_empty(); + let db = builder.clone().build(); { { let conn = db.connect_limbo(); @@ -153,7 +159,7 @@ fn test_pragma_page_sizes_with_writes_persists() { } // Drop the db and reopen it, and verify the same - let db = TempDatabase::new_with_existent(&db.path); + let db = builder.clone().with_db_path(&db.path).build(); let conn = db.connect_limbo(); let mut page_size = conn.pragma_query("page_size").unwrap(); let mut page_size = page_size.pop().unwrap(); diff --git a/tests/integration/query_processing/encryption.rs b/tests/integration/query_processing/encryption.rs index 2a7a90d7a4..9329f7fd5d 100644 --- a/tests/integration/query_processing/encryption.rs +++ b/tests/integration/query_processing/encryption.rs @@ -5,12 +5,12 @@ use turso_core::{DatabaseOpts, Row}; const ENABLE_ENCRYPTION: bool = true; -#[test] -fn test_per_page_encryption() -> anyhow::Result<()> { +// TODO: mvcc does not error here +#[turso_macros::test] +fn test_per_page_encryption(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let db_name = format!("test-{}.db", rng().next_u32()); - let tmp_db = TempDatabase::new(&db_name); let db_path = tmp_db.path.clone(); + let opts = tmp_db.db_opts; { let conn = tmp_db.connect_limbo(); @@ -46,10 +46,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { "file:{}?cipher=aegis256&hexkey=b1bbfda4f589dc9daaf004fe21111e00dc00c98237102f5c7002a5669fc76327", db_path.to_str().unwrap() ); - let (_io, conn) = turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - )?; + let (_io, conn) = turso_core::Connection::from_uri(&uri, opts)?; let mut row_count = 0; run_query_on_row(&tmp_db, &conn, "SELECT * FROM test", |row: &Row| { assert_eq!(row.get::(0).unwrap(), 1); @@ -64,10 +61,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { "file:{}?cipher=aegis256&hexkey=b1bbfda4f589dc9daaf004fe21111e00dc00c98237102f5c7002a5669fc76327", db_path.to_str().unwrap() ); - let (_io, conn) = turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - )?; + let (_io, conn) = turso_core::Connection::from_uri(&uri, opts)?; run_query( &tmp_db, &conn, @@ -81,10 +75,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { "file:{}?cipher=aegis256&hexkey=b1bbfda4f589dc9daaf004fe21111e00dc00c98237102f5c7002a5669fc76327", db_path.to_str().unwrap() ); - let (_io, conn) = turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - )?; + let (_io, conn) = turso_core::Connection::from_uri(&uri, opts)?; run_query( &tmp_db, &conn, @@ -106,10 +97,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { "file:{}?cipher=aegis256&hexkey=b1bbfda4f589dc9daaf004fe21111e00dc00c98237102f5c7002a5669fc76377", db_path.to_str().unwrap() ); - let (_io, conn) = turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - )?; + let (_io, conn) = turso_core::Connection::from_uri(&uri, opts)?; let should_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { run_query_on_row(&tmp_db, &conn, "SELECT * FROM test", |_row: &Row| {}).unwrap(); })); @@ -122,11 +110,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { //test connecting to encrypted db using insufficient encryption parameters in URI.This should panic. let uri = format!("file:{}?cipher=aegis256", db_path.to_str().unwrap()); let should_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { - turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - ) - .unwrap(); + turso_core::Connection::from_uri(&uri, opts).unwrap(); })); assert!( should_panic.is_err(), @@ -139,11 +123,7 @@ fn test_per_page_encryption() -> anyhow::Result<()> { db_path.to_str().unwrap() ); let should_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { - turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - ) - .unwrap(); + turso_core::Connection::from_uri(&uri, opts).unwrap(); })); assert!( should_panic.is_err(), @@ -165,11 +145,9 @@ fn test_per_page_encryption() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_non_4k_page_size_encryption() -> anyhow::Result<()> { +#[turso_macros::test(mvcc)] +fn test_non_4k_page_size_encryption(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let db_name = format!("test-8k-{}.db", rng().next_u32()); - let tmp_db = TempDatabase::new(&db_name); let db_path = tmp_db.path.clone(); { @@ -222,13 +200,14 @@ fn test_non_4k_page_size_encryption() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_corruption_turso_magic_bytes() -> anyhow::Result<()> { +// TODO: mvcc for some reason does not error on corruption here +#[turso_macros::test] +fn test_corruption_turso_magic_bytes(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let db_name = format!("test-corruption-magic-{}.db", rng().next_u32()); - let tmp_db = TempDatabase::new(&db_name); let db_path = tmp_db.path.clone(); + let opts = tmp_db.db_opts; + { let conn = tmp_db.connect_limbo(); run_query( @@ -270,11 +249,7 @@ fn test_corruption_turso_magic_bytes() -> anyhow::Result<()> { ); let should_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { - let (_io, conn) = turso_core::Connection::from_uri( - &uri, - DatabaseOpts::new().with_encryption(ENABLE_ENCRYPTION), - ) - .unwrap(); + let (_io, conn) = turso_core::Connection::from_uri(&uri, opts).unwrap(); run_query_on_row(&tmp_db, &conn, "SELECT * FROM test", |_row: &Row| {}).unwrap(); })); @@ -287,11 +262,9 @@ fn test_corruption_turso_magic_bytes() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_corruption_associated_data_bytes() -> anyhow::Result<()> { +#[turso_macros::test(mvcc)] +fn test_corruption_associated_data_bytes(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let db_name = format!("test-corruption-ad-{}.db", rng().next_u32()); - let tmp_db = TempDatabase::new(&db_name); let db_path = tmp_db.path.clone(); { @@ -377,8 +350,8 @@ fn test_corruption_associated_data_bytes() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_turso_header_structure() -> anyhow::Result<()> { +#[turso_macros::test(mvcc)] +fn test_turso_header_structure(db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); let verify_header = @@ -461,10 +434,14 @@ fn test_turso_header_structure() -> anyhow::Result<()> { "b1bbfda4f589dc9daaf004fe21111e00", ), ]; + let opts = db.db_opts; + let flags = db.db_flags; for (cipher_name, expected_id, description, hexkey) in test_cases { - let db_name = format!("test-header-{}-{}.db", cipher_name, rng().next_u32()); - let tmp_db = TempDatabase::new(&db_name); + let tmp_db = TempDatabase::builder() + .with_opts(opts) + .with_flags(flags) + .build(); let db_path = tmp_db.path.clone(); { diff --git a/tests/integration/query_processing/test_btree.rs b/tests/integration/query_processing/test_btree.rs index 1e972df7ef..8cfde4f4c3 100644 --- a/tests/integration/query_processing/test_btree.rs +++ b/tests/integration/query_processing/test_btree.rs @@ -440,15 +440,20 @@ fn write_at(io: &impl IO, file: &F, offset: usize, data: &[u8] } } -#[test] -fn test_btree() { +// TODO: currently fails with MVCC +#[turso_macros::test] +fn test_btree(tmp_db: TempDatabase) { let _ = env_logger::try_init(); let mut rng = ChaCha8Rng::seed_from_u64(0); + let opts = tmp_db.db_opts; + let flags = tmp_db.db_flags; for depth in 0..4 { for attempt in 0..16 { - let db = TempDatabase::new_with_rusqlite( - "create table test (k INTEGER PRIMARY KEY, b BLOB);", - ); + let db = TempDatabase::builder() + .with_flags(flags) + .with_opts(opts) + .with_init_sql("create table test (k INTEGER PRIMARY KEY, b BLOB);") + .build(); log::info!( "depth: {}, attempt: {}, path: {:?}", depth, diff --git a/tests/integration/query_processing/test_ddl.rs b/tests/integration/query_processing/test_ddl.rs index fcd11192f7..f5bb11eecb 100644 --- a/tests/integration/query_processing/test_ddl.rs +++ b/tests/integration/query_processing/test_ddl.rs @@ -1,9 +1,8 @@ use crate::common::TempDatabase; -#[test] -fn test_fail_drop_indexed_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b);")] +fn test_fail_drop_indexed_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b);"); let conn = tmp_db.connect_limbo(); conn.execute("CREATE INDEX i ON t (a)")?; @@ -12,10 +11,9 @@ fn test_fail_drop_indexed_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_unique_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a UNIQUE, b);")] +fn test_fail_drop_unique_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a UNIQUE, b);"); let conn = tmp_db.connect_limbo(); let res = conn.execute("ALTER TABLE t DROP COLUMN a"); @@ -23,10 +21,9 @@ fn test_fail_drop_unique_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_compound_unique_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b, UNIQUE(a, b));")] +fn test_fail_drop_compound_unique_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b, UNIQUE(a, b));"); let conn = tmp_db.connect_limbo(); let res = conn.execute("ALTER TABLE t DROP COLUMN a"); @@ -37,10 +34,9 @@ fn test_fail_drop_compound_unique_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_primary_key_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a PRIMARY KEY, b);")] +fn test_fail_drop_primary_key_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a PRIMARY KEY, b);"); let conn = tmp_db.connect_limbo(); let res = conn.execute("ALTER TABLE t DROP COLUMN a"); @@ -51,10 +47,9 @@ fn test_fail_drop_primary_key_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_compound_primary_key_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b, PRIMARY KEY(a, b));")] +fn test_fail_drop_compound_primary_key_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b, PRIMARY KEY(a, b));"); let conn = tmp_db.connect_limbo(); let res = conn.execute("ALTER TABLE t DROP COLUMN a"); @@ -65,10 +60,9 @@ fn test_fail_drop_compound_primary_key_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_partial_index_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b);")] +fn test_fail_drop_partial_index_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b);"); let conn = tmp_db.connect_limbo(); conn.execute("CREATE INDEX i ON t (b) WHERE a > 0")?; @@ -80,10 +74,9 @@ fn test_fail_drop_partial_index_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_fail_drop_view_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b);")] +fn test_fail_drop_view_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b);"); let conn = tmp_db.connect_limbo(); conn.execute("CREATE VIEW v AS SELECT a, b FROM t")?; @@ -96,10 +89,9 @@ fn test_fail_drop_view_column() -> anyhow::Result<()> { } // FIXME: this should rewrite the view to reference the new column name -#[test] -fn test_fail_rename_view_column() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (a, b);")] +fn test_fail_rename_view_column(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (a, b);"); let conn = tmp_db.connect_limbo(); conn.execute("CREATE VIEW v AS SELECT a, b FROM t")?; @@ -111,12 +103,11 @@ fn test_fail_rename_view_column() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_allow_drop_unreferenced_columns() -> anyhow::Result<()> { +#[turso_macros::test( + init_sql = "CREATE TABLE t (pk INTEGER PRIMARY KEY, indexed INTEGER, viewed INTEGER, partial INTEGER, compound1 INTEGER, compound2 INTEGER, unused1 INTEGER, unused2 INTEGER, unused3 INTEGER);" +)] +fn test_allow_drop_unreferenced_columns(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite( - "CREATE TABLE t (pk INTEGER PRIMARY KEY, indexed INTEGER, viewed INTEGER, partial INTEGER, compound1 INTEGER, compound2 INTEGER, unused1 INTEGER, unused2 INTEGER, unused3 INTEGER);", - ); let conn = tmp_db.connect_limbo(); conn.execute("CREATE INDEX idx ON t(indexed)")?; diff --git a/tests/integration/query_processing/test_multi_thread.rs b/tests/integration/query_processing/test_multi_thread.rs index 2d3b848dd0..c899ba7a78 100644 --- a/tests/integration/query_processing/test_multi_thread.rs +++ b/tests/integration/query_processing/test_multi_thread.rs @@ -4,9 +4,8 @@ use turso_core::{Statement, StepResult}; use crate::common::{maybe_setup_tracing, TempDatabase}; -#[test] -fn test_schema_reprepare() { - let tmp_db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_schema_reprepare(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); conn1.execute("CREATE TABLE t(x, y, z)").unwrap(); conn1 @@ -49,13 +48,20 @@ fn test_schema_reprepare() { assert_eq!(row, (20, 30)); } -#[test] +#[turso_macros::test(mvcc)] #[ignore] -fn test_create_multiple_connections() -> anyhow::Result<()> { +fn test_create_multiple_connections(tmp_db: TempDatabase) -> anyhow::Result<()> { maybe_setup_tracing(); let tries = 1; + let opts = tmp_db.db_opts; + let flags = tmp_db.db_flags; for _ in 0..tries { - let tmp_db = Arc::new(TempDatabase::new_empty()); + let tmp_db = Arc::new( + TempDatabase::builder() + .with_flags(flags) + .with_opts(opts) + .build(), + ); { let conn = tmp_db.connect_limbo(); conn.execute("CREATE TABLE t (x)").unwrap(); @@ -129,12 +135,19 @@ fn test_create_multiple_connections() -> anyhow::Result<()> { Ok(()) } -#[test] +#[turso_macros::test(mvcc)] #[ignore] -fn test_reader_writer() -> anyhow::Result<()> { +fn test_reader_writer(tmp_db: TempDatabase) -> anyhow::Result<()> { let tries = 10; + let opts = tmp_db.db_opts; + let flags = tmp_db.db_flags; for _ in 0..tries { - let tmp_db = Arc::new(TempDatabase::new_empty()); + let tmp_db = Arc::new( + TempDatabase::builder() + .with_flags(flags) + .with_opts(opts) + .build(), + ); { let conn = tmp_db.connect_limbo(); conn.execute("CREATE TABLE t (x)").unwrap(); @@ -203,10 +216,9 @@ fn test_reader_writer() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_schema_reprepare_write() { +#[turso_macros::test(mvcc)] +fn test_schema_reprepare_write(tmp_db: TempDatabase) { maybe_setup_tracing(); - let tmp_db = TempDatabase::new_empty(); let conn1 = tmp_db.connect_limbo(); conn1.execute("CREATE TABLE t(x, y, z)").unwrap(); let conn2 = tmp_db.connect_limbo(); @@ -250,10 +262,10 @@ fn advance(stmt: &mut Statement) -> anyhow::Result<()> { } /// Regression test detected by whopper -#[test] -fn test_interleaved_transactions() -> anyhow::Result<()> { +// TODO: cannot run with mvcc as we don't support indexes +#[turso_macros::test] +fn test_interleaved_transactions(tmp_db: TempDatabase) -> anyhow::Result<()> { maybe_setup_tracing(); - let tmp_db = TempDatabase::new_empty(); { let bootstrap_conn = tmp_db.connect_limbo(); bootstrap_conn.execute("CREATE TABLE table_0 (id INTEGER,col_1 REAL,col_2 INTEGER,col_3 REAL,col_4 TEXT,col_5 REAL,col_6 TEXT)")?; diff --git a/tests/integration/query_processing/test_read_path.rs b/tests/integration/query_processing/test_read_path.rs index 523597ae17..06918a778f 100644 --- a/tests/integration/query_processing/test_read_path.rs +++ b/tests/integration/query_processing/test_read_path.rs @@ -1,9 +1,8 @@ use crate::common::{limbo_exec_rows, TempDatabase}; use turso_core::{LimboError, StepResult, Value}; -#[test] -fn test_statement_reset_bind() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("create table test (i integer);"); +#[turso_macros::test(mvcc, init_sql = "create table test (i integer);")] +fn test_statement_reset_bind(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let mut stmt = conn.prepare("select ?")?; @@ -45,9 +44,8 @@ fn test_statement_reset_bind() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_statement_bind() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("create table test (i integer);"); +#[turso_macros::test(mvcc, init_sql = "create table test (i integer);")] +fn test_statement_bind(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let mut stmt = conn.prepare("select ?, ?1, :named, ?3, ?4")?; @@ -98,8 +96,11 @@ fn test_statement_bind() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_parameter_remap() -> anyhow::Result<()> { +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b integer, c integer, d integer);" +)] +fn test_insert_parameter_remap(tmp_db: TempDatabase) -> anyhow::Result<()> { // ─────────────────────── schema ────────────────────────────── // Table a b c d // INSERT lists: d , c , a , b @@ -110,9 +111,6 @@ fn test_insert_parameter_remap() -> anyhow::Result<()> { // We bind ?1 = 111 and ?2 = 222 and expect (7,222,111,22). // ─────────────────────────────────────────────────────────────── - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b integer, c integer, d integer);", - ); let conn = tmp_db.connect_limbo(); // prepare INSERT with re-ordered columns and constants @@ -161,8 +159,11 @@ fn test_insert_parameter_remap() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_parameter_remap_all_params() -> anyhow::Result<()> { +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b integer, c integer, d integer);" +)] +fn test_insert_parameter_remap_all_params(tmp_db: TempDatabase) -> anyhow::Result<()> { // ─────────────────────── schema ────────────────────────────── // Table a b c d // INSERT lists: d , a , c , b @@ -174,9 +175,6 @@ fn test_insert_parameter_remap_all_params() -> anyhow::Result<()> { // The row should be (111, 444, 333, 999). // ─────────────────────────────────────────────────────────────── - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b integer, c integer, d integer);", - ); let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (d, a, c, b) values (?, ?, ?, ?);")?; @@ -229,8 +227,11 @@ fn test_insert_parameter_remap_all_params() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_parameter_multiple_remap_backwards() -> anyhow::Result<()> { +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b integer, c integer, d integer);" +)] +fn test_insert_parameter_multiple_remap_backwards(tmp_db: TempDatabase) -> anyhow::Result<()> { // ─────────────────────── schema ────────────────────────────── // Table a b c d // INSERT lists: d , c , b , a @@ -241,9 +242,6 @@ fn test_insert_parameter_multiple_remap_backwards() -> anyhow::Result<()> { // The row should be (111, 222, 333, 444) // ─────────────────────────────────────────────────────────────── - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b integer, c integer, d integer);", - ); let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (d,c,b,a) values (?, ?, ?, ?);")?; @@ -295,8 +293,12 @@ fn test_insert_parameter_multiple_remap_backwards() -> anyhow::Result<()> { assert_eq!(ins.parameters().count(), 4); Ok(()) } -#[test] -fn test_insert_parameter_multiple_no_remap() -> anyhow::Result<()> { + +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b integer, c integer, d integer);" +)] +fn test_insert_parameter_multiple_no_remap(tmp_db: TempDatabase) -> anyhow::Result<()> { // ─────────────────────── schema ────────────────────────────── // Table a b c d // INSERT lists: a , b , c , d @@ -307,9 +309,6 @@ fn test_insert_parameter_multiple_no_remap() -> anyhow::Result<()> { // The row should be (111, 222, 333, 444) // ─────────────────────────────────────────────────────────────── - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b integer, c integer, d integer);", - ); let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (a,b,c,d) values (?, ?, ?, ?);")?; @@ -362,8 +361,11 @@ fn test_insert_parameter_multiple_no_remap() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_parameter_multiple_row() -> anyhow::Result<()> { +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b integer, c integer, d integer);" +)] +fn test_insert_parameter_multiple_row(tmp_db: TempDatabase) -> anyhow::Result<()> { // ─────────────────────── schema ────────────────────────────── // Table a b c d // INSERT lists: b , a , d , c @@ -373,9 +375,6 @@ fn test_insert_parameter_multiple_row() -> anyhow::Result<()> { // The row should be (111, 222, 333, 444), (555, 666, 777, 888) // ─────────────────────────────────────────────────────────────── - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b integer, c integer, d integer);", - ); let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (b,a,d,c) values (?, ?, ?, ?), (?, ?, ?, ?);")?; @@ -438,9 +437,8 @@ fn test_insert_parameter_multiple_row() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_bind_parameters_update_query() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("create table test (a integer, b text);"); +#[turso_macros::test(mvcc, init_sql = "create table test (a integer, b text);")] +fn test_bind_parameters_update_query(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (a, b) values (3, 'test1');")?; loop { @@ -480,11 +478,11 @@ fn test_bind_parameters_update_query() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_bind_parameters_update_query_multiple_where() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite( - "create table test (a integer, b text, c integer, d integer);", - ); +#[turso_macros::test( + mvcc, + init_sql = "create table test (a integer, b text, c integer, d integer);" +)] +fn test_bind_parameters_update_query_multiple_where(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (a, b, c, d) values (3, 'test1', 4, 5);")?; loop { @@ -527,10 +525,11 @@ fn test_bind_parameters_update_query_multiple_where() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_bind_parameters_update_rowid_alias() -> anyhow::Result<()> { - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);"); +#[turso_macros::test( + mvcc, + init_sql = "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);" +)] +fn test_bind_parameters_update_rowid_alias(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let mut ins = conn.prepare("insert into test (id, name) values (1, 'test');")?; loop { @@ -584,11 +583,11 @@ fn test_bind_parameters_update_rowid_alias() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_bind_parameters_update_rowid_alias_seek_rowid() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite( - "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, age integer);", - ); +#[turso_macros::test( + mvcc, + init_sql = "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, age integer);" +)] +fn test_bind_parameters_update_rowid_alias_seek_rowid(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("insert into test (id, name, age) values (1, 'test', 4);")?; conn.execute("insert into test (id, name, age) values (2, 'test', 11);")?; @@ -651,11 +650,13 @@ fn test_bind_parameters_update_rowid_alias_seek_rowid() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_bind_parameters_delete_rowid_alias_seek_out_of_order() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite( - "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, age integer);", - ); +// TODO: mvcc fails with `BTree should have returned rowid after next` +#[turso_macros::test( + init_sql = "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT, age integer);" +)] +fn test_bind_parameters_delete_rowid_alias_seek_out_of_order( + tmp_db: TempDatabase, +) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("insert into test (id, name, age) values (1, 'correct', 4);")?; conn.execute("insert into test (id, name, age) values (5, 'test', 11);")?; @@ -694,10 +695,11 @@ fn test_bind_parameters_delete_rowid_alias_seek_out_of_order() -> anyhow::Result Ok(()) } -#[test] -fn test_cte_alias() -> anyhow::Result<()> { - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);"); +#[turso_macros::test( + mvcc, + init_sql = "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);" +)] +fn test_cte_alias(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO test (id, name) VALUES (1, 'Limbo');")?; conn.execute("INSERT INTO test (id, name) VALUES (2, 'Turso');")?; @@ -739,9 +741,8 @@ fn test_cte_alias() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_avg_agg() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("create table t (x, y);"); +#[turso_macros::test(mvcc, init_sql = "create table t (x, y);")] +fn test_avg_agg(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("insert into t values (1, null), (2, null), (3, null), (null, null), (4, null)")?; let mut rows = Vec::new(); @@ -773,9 +774,8 @@ fn test_avg_agg() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_offset_limit_bind() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (i INTEGER);"); +#[turso_macros::test(mvcc, init_sql = "CREATE TABLE test (i INTEGER);")] +fn test_offset_limit_bind(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO test VALUES (5), (4), (3), (2), (1)")?; @@ -816,10 +816,11 @@ fn test_offset_limit_bind() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_upsert_parameters_order() -> anyhow::Result<()> { - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (k INTEGER PRIMARY KEY, v INTEGER);"); +#[turso_macros::test( + mvcc, + init_sql = "CREATE TABLE test (k INTEGER PRIMARY KEY, v INTEGER);" +)] +fn test_upsert_parameters_order(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO test VALUES (1, 2), (3, 4)")?; @@ -863,10 +864,13 @@ fn test_upsert_parameters_order() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_multiple_connections_visibility() -> anyhow::Result<()> { - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (k INTEGER PRIMARY KEY, v INTEGER);"); +// TODO: mvcc fails with: +// tests/integration/query_processing/test_read_path.rs:883:5: +// assertion `left == right` failed +// left: [[Integer(0)]] +// right: [[Integer(2)]] +#[turso_macros::test(init_sql = "CREATE TABLE test (k INTEGER PRIMARY KEY, v INTEGER);")] +fn test_multiple_connections_visibility(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); conn1.execute("BEGIN")?; @@ -882,9 +886,8 @@ fn test_multiple_connections_visibility() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_stmt_reset() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x);"); +#[turso_macros::test(mvcc, init_sql = "CREATE TABLE test (x);")] +fn test_stmt_reset(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn1 = tmp_db.connect_limbo(); let mut stmt1 = conn1.prepare("INSERT INTO test VALUES (?)").unwrap(); for _ in 0..3 { @@ -925,10 +928,9 @@ fn test_stmt_reset() -> anyhow::Result<()> { Ok(()) } -#[test] +#[turso_macros::test] /// Test that we can only join up to 63 tables, and trying to join more should fail with an error instead of panicing. -fn test_max_joined_tables_limit() { - let tmp_db = TempDatabase::new("test_max_joined_tables_limit"); +fn test_max_joined_tables_limit(tmp_db: TempDatabase) { let conn = tmp_db.connect_limbo(); // Create 64 tables @@ -949,9 +951,9 @@ fn test_max_joined_tables_limit() { assert!(result.contains("Only up to 63 tables can be joined")); } -#[test] +#[turso_macros::test] /// Test that we can create and select from a table with 1000 columns. -fn test_many_columns() { +fn test_many_columns(tmp_db: TempDatabase) { let mut create_sql = String::from("CREATE TABLE test ("); for i in 0..1000 { if i > 0 { @@ -961,7 +963,6 @@ fn test_many_columns() { } create_sql.push(')'); - let tmp_db = TempDatabase::new("test_many_columns"); let conn = tmp_db.connect_limbo(); conn.execute(&create_sql).unwrap(); @@ -1019,9 +1020,8 @@ fn test_many_columns() { ); } -#[test] -fn test_eval_param_only_once() { - let tmp_db = TempDatabase::new("test_eval_param_only_once"); +#[turso_macros::test] +fn test_eval_param_only_once(tmp_db: TempDatabase) { let conn = tmp_db.connect_limbo(); conn.execute("CREATE TABLE t(x)").unwrap(); conn.execute("INSERT INTO t SELECT value FROM generate_series(1, 10000)") diff --git a/tests/integration/query_processing/test_transactions.rs b/tests/integration/query_processing/test_transactions.rs index 540c0d7277..5e44d0cd3b 100644 --- a/tests/integration/query_processing/test_transactions.rs +++ b/tests/integration/query_processing/test_transactions.rs @@ -12,9 +12,8 @@ use crate::common::TempDatabase; // 4. T1 commits // 5. T2 attempts to write again and succeeds. This is because the transaction // was still fresh (no reads or writes happened). -#[test] -fn test_deferred_transaction_restart() { - let tmp_db = TempDatabase::new("test_deferred_tx.db"); +#[turso_macros::test] +fn test_deferred_transaction_restart(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); @@ -55,9 +54,8 @@ fn test_deferred_transaction_restart() { // 5. T1 commits (invalidating T2's snapshot). // 6. T2 attempts to write again but still gets BUSY - it cannot restart // because it has performed reads and has a committed snapshot. -#[test] -fn test_deferred_transaction_no_restart() { - let tmp_db = TempDatabase::new("test_deferred_tx_no_restart.db"); +#[turso_macros::test] +fn test_deferred_transaction_no_restart(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); @@ -104,9 +102,8 @@ fn test_deferred_transaction_no_restart() { } } -#[test] -fn test_txn_error_doesnt_rollback_txn() -> Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("create table t (x);"); +#[turso_macros::test(init_sql = "create table t (x);")] +fn test_txn_error_doesnt_rollback_txn(tmp_db: TempDatabase) -> Result<()> { let conn = tmp_db.connect_limbo(); conn.execute("begin")?; @@ -127,11 +124,10 @@ fn test_txn_error_doesnt_rollback_txn() -> Result<()> { Ok(()) } -#[test] +#[turso_macros::test] /// Connection 2 should see the initial data (table 'test' in schema + 2 rows). Regression test for #2997 /// It should then see another created table 'test2' in schema, as well. -fn test_transaction_visibility() { - let tmp_db = TempDatabase::new("test_transaction_visibility.db"); +fn test_transaction_visibility(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); @@ -176,11 +172,9 @@ fn test_transaction_visibility() { } } -#[test] +#[turso_macros::test] /// A constraint error does not rollback the transaction, it rolls back the statement. -fn test_constraint_error_aborts_only_stmt_not_entire_transaction() { - let tmp_db = - TempDatabase::new("test_constraint_error_aborts_only_stmt_not_entire_transaction.db"); +fn test_constraint_error_aborts_only_stmt_not_entire_transaction(tmp_db: TempDatabase) { let conn = tmp_db.connect_limbo(); // Create table succeeds @@ -216,13 +210,12 @@ fn test_constraint_error_aborts_only_stmt_not_entire_transaction() { ); } -#[test] +#[turso_macros::test] /// Regression test for https://github.com/tursodatabase/turso/issues/3784 where dirty pages /// were flushed to WAL _before_ deferred FK violations were checked. This resulted in the /// violations being persisted to the database, even though the transaction was aborted. /// This test ensures that dirty pages are not flushed to WAL until after deferred violations are checked. -fn test_deferred_fk_violation_rollback_in_autocommit() { - let tmp_db = TempDatabase::new("test_deferred_fk_violation_rollback.db"); +fn test_deferred_fk_violation_rollback_in_autocommit(tmp_db: TempDatabase) { let conn = tmp_db.connect_limbo(); // Enable foreign keys @@ -247,12 +240,8 @@ fn test_deferred_fk_violation_rollback_in_autocommit() { assert_eq!(row, vec![Value::Integer(0)]); } -#[test] -fn test_mvcc_transactions_autocommit() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_transactions_autocommit.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_transactions_autocommit(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); // This should work - basic CREATE TABLE in MVCC autocommit mode @@ -261,12 +250,8 @@ fn test_mvcc_transactions_autocommit() { .unwrap(); } -#[test] -fn test_mvcc_transactions_immediate() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_transactions_immediate.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_transactions_immediate(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); @@ -282,12 +267,8 @@ fn test_mvcc_transactions_immediate() { assert!(matches!(result, Err(LimboError::Busy))); } -#[test] -fn test_mvcc_transactions_deferred() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_transactions_deferred.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_transactions_deferred(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); let conn2 = tmp_db.connect_limbo(); @@ -319,12 +300,8 @@ fn test_mvcc_transactions_deferred() { } } -#[test] -fn test_mvcc_insert_select_basic() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_update_basic.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_insert_select_basic(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); conn1 @@ -343,12 +320,8 @@ fn test_mvcc_insert_select_basic() { assert_eq!(row, vec![Value::Integer(1), Value::build_text("first")]); } -#[test] -fn test_mvcc_update_basic() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_update_basic.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_update_basic(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); conn1 @@ -415,12 +388,8 @@ fn test_mvcc_concurrent_insert_basic() { ); } -#[test] -fn test_mvcc_update_same_row_twice() { - let tmp_db = TempDatabase::new_with_opts( - "test_mvcc_update_same_row_twice.db", - turso_core::DatabaseOpts::new().with_mvcc(true), - ); +#[turso_macros::test(mvcc)] +fn test_mvcc_update_same_row_twice(tmp_db: TempDatabase) { let conn1 = tmp_db.connect_limbo(); conn1 diff --git a/tests/integration/query_processing/test_write_path.rs b/tests/integration/query_processing/test_write_path.rs index e3bddb095a..909df12356 100644 --- a/tests/integration/query_processing/test_write_path.rs +++ b/tests/integration/query_processing/test_write_path.rs @@ -3,10 +3,7 @@ use crate::common::{compare_string, do_flush, TempDatabase}; use log::debug; use std::io::{Read, Seek, Write}; use std::sync::Arc; -use turso_core::{ - CheckpointMode, Connection, Database, DatabaseOpts, LimboError, Row, Statement, StepResult, - Value, -}; +use turso_core::{CheckpointMode, Connection, LimboError, Row, Statement, StepResult, Value}; const WAL_HEADER_SIZE: usize = 32; const WAL_FRAME_HEADER_SIZE: usize = 24; @@ -23,12 +20,10 @@ macro_rules! change_state { }; } -#[test] +#[turso_macros::test(init_sql = "CREATE TABLE test (x INTEGER PRIMARY KEY, t TEXT);")] #[ignore] -fn test_simple_overflow_page() -> anyhow::Result<()> { +fn test_simple_overflow_page(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (x INTEGER PRIMARY KEY, t TEXT);"); let conn = tmp_db.connect_limbo(); let mut huge_text = String::new(); @@ -85,12 +80,10 @@ fn test_simple_overflow_page() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_sequential_overflow_page() -> anyhow::Result<()> { +#[turso_macros::test(mvcc, init_sql = "CREATE TABLE test (x INTEGER PRIMARY KEY, t TEXT);")] +fn test_sequential_overflow_page(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = - TempDatabase::new_with_rusqlite("CREATE TABLE test (x INTEGER PRIMARY KEY, t TEXT);"); let conn = tmp_db.connect_limbo(); let iterations = 10_usize; @@ -153,13 +146,12 @@ fn test_sequential_overflow_page() -> anyhow::Result<()> { Ok(()) } -#[test_log::test] +#[turso_macros::test(init_sql = "CREATE TABLE test (x INTEGER PRIMARY KEY);")] #[ignore = "this takes too long :)"] -fn test_sequential_write() -> anyhow::Result<()> { +fn test_sequential_write(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x INTEGER PRIMARY KEY);"); let conn = tmp_db.connect_limbo(); let list_query = "SELECT * FROM test"; @@ -189,12 +181,11 @@ fn test_sequential_write() -> anyhow::Result<()> { Ok(()) } -#[test] +#[turso_macros::test(init_sql = "CREATE TABLE test (x REAL);")] /// There was a regression with inserting multiple rows with a column containing an unary operator :) /// https://github.com/tursodatabase/turso/pull/679 -fn test_regression_multi_row_insert() -> anyhow::Result<()> { +fn test_regression_multi_row_insert(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x REAL);"); let conn = tmp_db.connect_limbo(); let insert_query = "INSERT INTO test VALUES (-2), (-3), (-1)"; @@ -224,10 +215,9 @@ fn test_regression_multi_row_insert() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_statement_reset() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "create table test (i integer);")] +fn test_statement_reset(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("create table test (i integer);"); let conn = tmp_db.connect_limbo(); conn.execute("insert into test values (1)")?; @@ -270,10 +260,9 @@ fn test_statement_reset() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_wal_checkpoint() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE test (x INTEGER PRIMARY KEY);")] +fn test_wal_checkpoint(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x INTEGER PRIMARY KEY);"); // threshold is 1000 by default let iterations = 1001_usize; let conn = tmp_db.connect_limbo(); @@ -300,10 +289,9 @@ fn test_wal_checkpoint() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_wal_restart() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE test (x INTEGER PRIMARY KEY);")] +fn test_wal_restart(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x INTEGER PRIMARY KEY);"); // threshold is 1000 by default fn insert(i: usize, conn: &Arc, tmp_db: &TempDatabase) -> anyhow::Result<()> { @@ -345,10 +333,9 @@ fn test_wal_restart() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_after_big_blob() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE temp (t1 BLOB, t2 INTEGER)")] +fn test_insert_after_big_blob(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE temp (t1 BLOB, t2 INTEGER)"); let conn = tmp_db.connect_limbo(); conn.execute("insert into temp(t1) values (zeroblob (262144))")?; @@ -357,14 +344,13 @@ fn test_insert_after_big_blob() -> anyhow::Result<()> { Ok(()) } -#[test_log::test] +#[turso_macros::test(init_sql = "CREATE TABLE test (x PRIMARY KEY);")] #[ignore = "this takes too long :)"] -fn test_write_delete_with_index() -> anyhow::Result<()> { +fn test_write_delete_with_index(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x PRIMARY KEY);"); let conn = tmp_db.connect_limbo(); let list_query = "SELECT * FROM test"; @@ -412,13 +398,12 @@ fn test_write_delete_with_index() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_update_with_index() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE test (x REAL PRIMARY KEY, y TEXT);")] +fn test_update_with_index(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE test (x REAL PRIMARY KEY, y TEXT);"); let conn = tmp_db.connect_limbo(); common::run_query(&tmp_db, &conn, "INSERT INTO test VALUES (1.0, 'foo')")?; @@ -448,13 +433,12 @@ fn test_update_with_index() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_delete_with_index() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (x UNIQUE)")] +fn test_delete_with_index(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (x UNIQUE)"); let conn = tmp_db.connect_limbo(); common::run_query(&tmp_db, &conn, "INSERT INTO t VALUES (1), (2)")?; @@ -467,10 +451,11 @@ fn test_delete_with_index() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_update_regression() -> anyhow::Result<()> { +#[turso_macros::test( + init_sql = "CREATE TABLE imaginative_baroja (blithesome_hall BLOB,remarkable_lester INTEGER,generous_balagun TEXT,ample_earth INTEGER,marvelous_khadzhiev BLOB,glowing_parissi TEXT,insightful_ryner BLOB)" +)] +fn test_update_regression(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE imaginative_baroja (blithesome_hall BLOB,remarkable_lester INTEGER,generous_balagun TEXT,ample_earth INTEGER,marvelous_khadzhiev BLOB,glowing_parissi TEXT,insightful_ryner BLOB)"); let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO imaginative_baroja VALUES (X'617070726F61636861626C655F6F6D6164', 5581285929211692372, 'approachable_podur', -4145754929970306534, X'666F72747569746F75735F7368617270', 'sensible_amesly', X'636F6D70657469746976655F6669746368'), (X'6D6972746866756C5F686F6673746565', -8554670009677647372, 'shimmering_modkraftdk', 4993627046425025026, X'636F6E73696465726174655F63616765', 'breathtaking_boggs', X'616D617A696E675F73696D6F6E65'), (X'7669766163696F75735F7363687761727A', 5860599187854155616, 'sparkling_aurora', 3757552048117668067, X'756E697175655F6769617A', 'lovely_leroy', X'68617264776F726B696E675F6D696C6C6572'), (X'677265676172696F75735F7061657065', -488992130149088413, 'focused_brinker', 4503849242092922100, X'66756E6E795F6A616B736963', 'competitive_communications', X'657863656C6C656E745F7873696C656E74'), (X'7374756E6E696E675F74616E6E656E6261756D', -5634782647279946253, 'fabulous_crute', -3978009805517476564, X'72656C617865645F63617272796F7574', 'spellbinding_erkan', X'66756E6E795F646F626273'), (X'696D6167696E61746976655F746F6C6F6B6F6E6E696B6F7661', 4236471363502323025, 'excellent_wolke', 7606168469334609395, X'736C65656B5F6D6361666565', 'magnificent_riley', X'616D6961626C655F706173736164616B6973'), (X'77696C6C696E675F736872657665', 5048296470820985219, 'ambitious_jeppesen', 6961857167361512834, X'70617469656E745F6272696E6B6572', 'giving_kramm', X'726573706F6E7369626C655F7363686D696474'), (X'73656E7369626C655F6D757865726573', -5519194136843846790, 'frank_ruggero', 4354855935194921345, X'76697669645F63617365', 'focused_lovecruft', X'6D61676E69666963656E745F736B79')")?; @@ -501,20 +486,14 @@ fn test_update_regression() -> anyhow::Result<()> { Ok(()) } -#[test] +#[turso_macros::test(init_sql = "CREATE TABLE t(x UNIQUE)")] /// Test that a large insert statement containing a UNIQUE constraint violation /// is properly rolled back so that the database size is also shrunk to the size /// before that statement is executed. -fn test_rollback_on_unique_constraint_violation() -> anyhow::Result<()> { +fn test_rollback_on_unique_constraint_violation(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_opts( - "big_statement_rollback.db", - DatabaseOpts::new().with_indexes(true), - ); let conn = tmp_db.connect_limbo(); - conn.execute("CREATE TABLE t(x UNIQUE)")?; - conn.execute("BEGIN")?; conn.execute("INSERT INTO t VALUES (10000)")?; @@ -549,15 +528,11 @@ fn test_rollback_on_unique_constraint_violation() -> anyhow::Result<()> { Ok(()) } -#[test] +#[turso_macros::test] /// Test that a large delete statement containing a foreign key constraint violation /// is properly rolled back. -fn test_rollback_on_foreign_key_constraint_violation() -> anyhow::Result<()> { +fn test_rollback_on_foreign_key_constraint_violation(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_opts( - "big_delete_rollback.db", - DatabaseOpts::new().with_indexes(true), - ); let conn = tmp_db.connect_limbo(); // Enable foreign keys @@ -624,10 +599,9 @@ fn test_rollback_on_foreign_key_constraint_violation() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_multiple_statements() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (x)")] +fn test_multiple_statements(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (x)"); let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO t values(1); insert into t values(2);")?; @@ -715,13 +689,12 @@ impl ConnectionPlan { } } -#[test] -fn test_write_concurrent_connections() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t (x)")] +fn test_write_concurrent_connections(tmp_db: TempDatabase) -> anyhow::Result<()> { let _ = env_logger::try_init(); maybe_setup_tracing(); - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t (x)"); let num_connections = 4; let num_inserts_per_connection = 100; let mut connections = vec![]; @@ -767,12 +740,13 @@ fn test_write_concurrent_connections() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_wal_bad_frame() -> anyhow::Result<()> { +#[turso_macros::test(init_sql = "CREATE TABLE t1 (x)")] +fn test_wal_bad_frame(tmp_db: TempDatabase) -> anyhow::Result<()> { maybe_setup_tracing(); let _ = env_logger::try_init(); + let db_opts = tmp_db.db_opts; let db_path = { - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE t1 (x)"); + let tmp_db = tmp_db; let db_path = tmp_db.path.clone(); let conn = tmp_db.connect_limbo(); conn.execute("BEGIN")?; @@ -817,20 +791,10 @@ fn test_wal_bad_frame() -> anyhow::Result<()> { }; { let result = { - let io: Arc = Arc::new(turso_core::PlatformIO::new().unwrap()); - let db = Database::open_file_with_flags( - io.clone(), - db_path.to_str().unwrap(), - turso_core::OpenFlags::default(), - turso_core::DatabaseOpts::new().with_indexes(false), - None, - ) - .unwrap(); - let tmp_db = TempDatabase { - path: db_path, - io, - db, - }; + let tmp_db = TempDatabase::builder() + .with_db_path(db_path) + .with_opts(db_opts) + .build(); let conn = tmp_db.connect_limbo(); common::run_query_on_row(&tmp_db, &conn, "SELECT count(1) from t2", |row| { let x = row.get::(0).unwrap(); @@ -859,25 +823,26 @@ fn test_wal_bad_frame() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_read_wal_dumb_no_frames() -> anyhow::Result<()> { +#[turso_macros::test] +fn test_read_wal_dumb_no_frames(tmp_db: TempDatabase) -> anyhow::Result<()> { maybe_setup_tracing(); let _ = env_logger::try_init(); + let opts = tmp_db.db_opts; let db_path = { - let tmp_db = TempDatabase::new_empty(); + let tmp_db = tmp_db; let conn = tmp_db.connect_limbo(); conn.close()?; tmp_db.path.clone() }; // Second connection must recover from the WAL file. Last checksum should be filled correctly. { - let tmp_db = TempDatabase::new_with_existent(&db_path); + let tmp_db = TempDatabase::new_with_existent_with_opts(&db_path, opts); let conn = tmp_db.connect_limbo(); conn.execute("CREATE TABLE t0 (x)")?; conn.close()?; } { - let tmp_db = TempDatabase::new_with_existent(&db_path); + let tmp_db = TempDatabase::new_with_existent_with_opts(&db_path, opts); let conn = tmp_db.connect_limbo(); conn.execute("INSERT INTO t0(x) VALUES (1)")?; conn.close()?; @@ -886,9 +851,8 @@ fn test_read_wal_dumb_no_frames() -> anyhow::Result<()> { Ok(()) } -#[test] -fn test_insert_with_column_names() -> anyhow::Result<()> { - let tmp_db = TempDatabase::new_with_rusqlite("CREATE TABLE a(z)"); +#[turso_macros::test(init_sql = "CREATE TABLE a(z)")] +fn test_insert_with_column_names(tmp_db: TempDatabase) -> anyhow::Result<()> { let conn = tmp_db.connect_limbo(); let result = conn.execute("INSERT INTO a VALUES (b.x)"); @@ -907,9 +871,8 @@ fn test_insert_with_column_names() -> anyhow::Result<()> { Ok(()) } -#[test] -pub fn delete_search_op_ignore_nulls() { - let limbo = TempDatabase::new_empty(); +#[turso_macros::test()] +pub fn delete_search_op_ignore_nulls(limbo: TempDatabase) { let conn = limbo.db.connect().unwrap(); for sql in [ "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, c INT);", @@ -928,9 +891,8 @@ pub fn delete_search_op_ignore_nulls() { ); } -#[test] -pub fn delete_eq_correct() { - let limbo = TempDatabase::new_empty(); +#[turso_macros::test] +pub fn delete_eq_correct(limbo: TempDatabase) { let conn = limbo.db.connect().unwrap(); for sql in [ "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, c INT);", @@ -956,9 +918,8 @@ pub fn delete_eq_correct() { ); } -#[test] -pub fn upsert_conflict() { - let limbo = TempDatabase::new_empty(); +#[turso_macros::test] +pub fn upsert_conflict(limbo: TempDatabase) { let conn = limbo.db.connect().unwrap(); for sql in [ "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, c INT UNIQUE, value INT);", diff --git a/tests/integration/trigger.rs b/tests/integration/trigger.rs index 1898de5da9..bb91b21563 100644 --- a/tests/integration/trigger.rs +++ b/tests/integration/trigger.rs @@ -1,12 +1,11 @@ use crate::common::TempDatabase; -#[test] -fn test_create_trigger() { +#[turso_macros::test(mvcc)] +fn test_create_trigger(db: TempDatabase) { let _ = tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .try_init(); - let db = TempDatabase::new_empty(); let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x, y TEXT)").unwrap(); @@ -45,9 +44,8 @@ fn test_create_trigger() { assert_eq!(results[1], (1, "hello".to_string())); } -#[test] -fn test_drop_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_drop_trigger(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY)") @@ -99,9 +97,8 @@ fn test_drop_trigger() { assert_eq!(results.len(), 0); } -#[test] -fn test_trigger_after_insert() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_after_insert(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY, y TEXT)") @@ -142,9 +139,8 @@ fn test_trigger_after_insert() { assert_eq!(results[0], (1, "hello".to_string())); } -#[test] -fn test_trigger_when_clause() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_when_clause(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY, y INTEGER)") @@ -181,9 +177,8 @@ fn test_trigger_when_clause() { assert_eq!(results[0], 2); } -#[test] -fn test_trigger_drop_table_drops_triggers() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_drop_table_drops_triggers(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY)") @@ -234,9 +229,8 @@ fn test_trigger_drop_table_drops_triggers() { assert_eq!(results.len(), 0); } -#[test] -fn test_trigger_new_old_references() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_new_old_references(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY, y TEXT)") @@ -276,9 +270,8 @@ fn test_trigger_new_old_references() { assert_eq!(results[0], "old=hello new=world"); } -#[test] -fn test_multiple_triggers_same_event() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_multiple_triggers_same_event(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x INTEGER PRIMARY KEY)") @@ -322,9 +315,8 @@ fn test_multiple_triggers_same_event() { assert_eq!(results[1], "trigger2"); } -#[test] -fn test_two_triggers_on_same_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_two_triggers_on_same_table(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE test (x, msg TEXT)").unwrap(); @@ -385,9 +377,8 @@ fn test_two_triggers_on_same_table() { ); } -#[test] -fn test_trigger_mutual_recursion() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_mutual_recursion(db: TempDatabase) { let conn = db.connect_limbo(); conn.execute("CREATE TABLE t (id INTEGER, msg TEXT)") @@ -464,9 +455,8 @@ fn test_trigger_mutual_recursion() { assert_eq!(u_results[0], (1001, "from_t".to_string())); } -#[test] -fn test_after_insert_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_after_insert_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create table and log table @@ -519,9 +509,8 @@ fn test_after_insert_trigger() { assert_eq!(results[1], ("INSERT".to_string(), 2, "banana".to_string())); } -#[test] -fn test_before_update_of_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_before_update_of_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create table with multiple columns @@ -589,9 +578,8 @@ fn test_before_update_of_trigger() { assert_eq!(results[1], (2, 200, 250)); } -#[test] -fn test_after_update_of_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_after_update_of_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -656,9 +644,8 @@ fn log(s: &str) -> &str { s } -#[test] -fn test_before_delete_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_before_delete_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create tables @@ -736,9 +723,8 @@ fn test_before_delete_trigger() { } } -#[test] -fn test_after_delete_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_after_delete_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create tables @@ -801,9 +787,8 @@ fn test_after_delete_trigger() { assert_eq!(results[1], (3, 100, 100)); } -#[test] -fn test_trigger_with_multiple_statements() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_trigger_with_multiple_statements(db: TempDatabase) { let conn = db.connect_limbo(); // Create tables @@ -887,9 +872,8 @@ fn test_trigger_with_multiple_statements() { assert_eq!(audit_results[1], "Balance changed for account 2"); } -#[test] -fn test_alter_table_drop_column_fails_when_trigger_references_new_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_fails_when_trigger_references_new_column(db: TempDatabase) { let conn = db.connect_limbo(); // Create table with columns @@ -918,9 +902,8 @@ fn test_alter_table_drop_column_fails_when_trigger_references_new_column() { ); } -#[test] -fn test_alter_table_drop_column_fails_when_trigger_references_old_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_fails_when_trigger_references_old_column(db: TempDatabase) { let conn = db.connect_limbo(); // Create table with columns @@ -949,9 +932,8 @@ fn test_alter_table_drop_column_fails_when_trigger_references_old_column() { ); } -#[test] -fn test_alter_table_drop_column_fails_when_trigger_references_unqualified_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_fails_when_trigger_references_unqualified_column(db: TempDatabase) { let conn = db.connect_limbo(); // Create table with columns @@ -980,9 +962,8 @@ fn test_alter_table_drop_column_fails_when_trigger_references_unqualified_column ); } -#[test] -fn test_alter_table_drop_column_succeeds_when_trigger_references_other_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_succeeds_when_trigger_references_other_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables @@ -1023,9 +1004,10 @@ fn test_alter_table_drop_column_succeeds_when_trigger_references_other_table() { assert_eq!(columns[0], "x"); } -#[test] -fn test_alter_table_drop_column_from_other_table_causes_parse_error_when_trigger_fires() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_from_other_table_causes_parse_error_when_trigger_fires( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create two tables @@ -1080,9 +1062,8 @@ fn test_alter_table_drop_column_from_other_table_causes_parse_error_when_trigger ); } -#[test] -fn test_alter_table_rename_column_propagates_to_trigger_on_owning_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_propagates_to_trigger_on_owning_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1128,9 +1109,8 @@ fn test_alter_table_rename_column_propagates_to_trigger_on_owning_table() { ); } -#[test] -fn test_alter_table_rename_column_propagates_to_trigger_referencing_other_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_propagates_to_trigger_referencing_other_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables @@ -1178,9 +1158,8 @@ fn test_alter_table_rename_column_propagates_to_trigger_referencing_other_table( ); } -#[test] -fn test_alter_table_rename_column_propagates_to_trigger_with_multiple_references() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_propagates_to_trigger_with_multiple_references(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables @@ -1228,9 +1207,10 @@ fn test_alter_table_rename_column_propagates_to_trigger_with_multiple_references ); } -#[test] -fn test_alter_table_rename_column_fails_when_trigger_when_clause_references_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_fails_when_trigger_when_clause_references_column( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create table @@ -1259,9 +1239,8 @@ fn test_alter_table_rename_column_fails_when_trigger_when_clause_references_colu ); } -#[test] -fn test_alter_table_rename_column_propagates_to_multiple_triggers() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_propagates_to_multiple_triggers(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1326,9 +1305,8 @@ fn test_alter_table_rename_column_propagates_to_multiple_triggers() { ); } -#[test] -fn test_alter_table_drop_column_fails_with_old_reference_in_update_trigger() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_fails_with_old_reference_in_update_trigger(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1351,9 +1329,8 @@ fn test_alter_table_drop_column_fails_with_old_reference_in_update_trigger() { ); } -#[test] -fn test_alter_table_rename_column_in_insert_column_list() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_in_insert_column_list(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables @@ -1401,9 +1378,10 @@ fn test_alter_table_rename_column_in_insert_column_list() { ); } -#[test] -fn test_alter_table_rename_column_in_trigger_table_does_not_rewrite_other_table_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_in_trigger_table_does_not_rewrite_other_table_column( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1462,9 +1440,10 @@ fn test_alter_table_rename_column_in_trigger_table_does_not_rewrite_other_table_ ); } -#[test] -fn test_alter_table_rename_column_in_insert_target_table_does_not_rewrite_trigger_table_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_in_insert_target_table_does_not_rewrite_trigger_table_column( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1528,9 +1507,10 @@ fn test_alter_table_rename_column_in_insert_target_table_does_not_rewrite_trigge ); } -#[test] -fn test_alter_table_rename_column_update_where_clause_does_not_rewrite_target_table_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_update_where_clause_does_not_rewrite_target_table_column( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1587,9 +1567,8 @@ fn test_alter_table_rename_column_update_where_clause_does_not_rewrite_target_ta ); } -#[test] -fn test_alter_table_rename_column_update_set_column_name_rewritten() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_update_set_column_name_rewritten(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1646,9 +1625,10 @@ fn test_alter_table_rename_column_update_set_column_name_rewritten() { ); } -#[test] -fn test_alter_table_rename_column_delete_where_clause_does_not_rewrite_target_table_column() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_delete_where_clause_does_not_rewrite_target_table_column( + db: TempDatabase, +) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1705,9 +1685,8 @@ fn test_alter_table_rename_column_delete_where_clause_does_not_rewrite_target_ta ); } -#[test] -fn test_alter_table_rename_column_update_of_column_list_rewritten() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_update_of_column_list_rewritten(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1759,9 +1738,8 @@ fn test_alter_table_rename_column_update_of_column_list_rewritten() { ); } -#[test] -fn test_alter_table_rename_column_update_of_multiple_columns_rewritten() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_update_of_multiple_columns_rewritten(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1814,9 +1792,8 @@ fn test_alter_table_rename_column_update_of_multiple_columns_rewritten() { ); } -#[test] -fn test_alter_table_drop_column_allows_when_insert_targets_other_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_allows_when_insert_targets_other_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1837,9 +1814,8 @@ fn test_alter_table_drop_column_allows_when_insert_targets_other_table() { conn.execute("ALTER TABLE t DROP COLUMN x").unwrap(); } -#[test] -fn test_alter_table_drop_column_allows_when_update_targets_other_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_allows_when_update_targets_other_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables, both with column 'x' @@ -1860,9 +1836,8 @@ fn test_alter_table_drop_column_allows_when_update_targets_other_table() { conn.execute("ALTER TABLE t DROP COLUMN x").unwrap(); } -#[test] -fn test_alter_table_drop_column_allows_when_insert_targets_owning_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_allows_when_insert_targets_owning_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1889,9 +1864,8 @@ fn test_alter_table_drop_column_allows_when_insert_targets_owning_table() { ); } -#[test] -fn test_alter_table_drop_column_allows_when_update_set_targets_owning_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_drop_column_allows_when_update_set_targets_owning_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create table @@ -1918,9 +1892,8 @@ fn test_alter_table_drop_column_allows_when_update_set_targets_owning_table() { ); } -#[test] -fn test_alter_table_rename_column_qualified_reference_to_trigger_table() { - let db = TempDatabase::new_empty(); +#[turso_macros::test(mvcc)] +fn test_alter_table_rename_column_qualified_reference_to_trigger_table(db: TempDatabase) { let conn = db.connect_limbo(); // Create two tables diff --git a/tests/integration/wal/test_wal.rs b/tests/integration/wal/test_wal.rs index 42e6261e43..5f8d346c15 100644 --- a/tests/integration/wal/test_wal.rs +++ b/tests/integration/wal/test_wal.rs @@ -6,10 +6,9 @@ use std::sync::{Arc, Mutex}; use turso_core::{Connection, LimboError, Result, StepResult}; #[allow(clippy::arc_with_non_send_sync)] -#[test] -fn test_wal_checkpoint_result() -> Result<()> { +#[turso_macros::test] +fn test_wal_checkpoint_result(tmp_db: TempDatabase) -> Result<()> { maybe_setup_tracing(); - let tmp_db = TempDatabase::new("test_wal.db"); let conn = tmp_db.connect_limbo(); conn.execute("CREATE TABLE t1 (id text);")?;