From 8ff0d3ff9c176a5f95e74b76f5ba60f2f71e8926 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Fri, 22 Dec 2023 10:27:43 +0100 Subject: [PATCH] Fixed tests --- crates/jmap/src/mailbox/mod.rs | 2 +- crates/main/Cargo.toml | 2 +- crates/store/src/backend/sqlite/write.rs | 23 +++++++++- tests/Cargo.toml | 2 +- tests/src/directory/mod.rs | 20 ++++++++- tests/src/directory/sql.rs | 56 +++++++++++++++++++----- tests/src/jmap/mod.rs | 7 ++- tests/src/store/blob.rs | 4 +- tests/src/store/lookup.rs | 43 ++++++++---------- 9 files changed, 112 insertions(+), 47 deletions(-) diff --git a/crates/jmap/src/mailbox/mod.rs b/crates/jmap/src/mailbox/mod.rs index 62ecd39f..bbc1ba91 100644 --- a/crates/jmap/src/mailbox/mod.rs +++ b/crates/jmap/src/mailbox/mod.rs @@ -35,7 +35,7 @@ pub mod set; pub const INBOX_ID: u32 = 0; pub const TRASH_ID: u32 = 1; -pub const JUNK_ID: u32 = 1; +pub const JUNK_ID: u32 = 2; #[derive(Debug, Clone, Copy)] pub struct UidMailbox { diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index 5dfb09cd..674ec8bd 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -32,7 +32,7 @@ jemallocator = "0.5.0" [features] #default = ["sqlite", "foundationdb", "postgres", "mysql", "rocks", "elastic", "s3", "redis"] -default = ["rocks"] +default = ["sqlite", "foundationdb", "postgres", "mysql", "rocks", "elastic", "s3", "redis"] sqlite = ["store/sqlite"] foundationdb = ["store/foundation"] postgres = ["store/postgres"] diff --git a/crates/store/src/backend/sqlite/write.rs b/crates/store/src/backend/sqlite/write.rs index 9578cb0d..1db9d9c2 100644 --- a/crates/store/src/backend/sqlite/write.rs +++ b/crates/store/src/backend/sqlite/write.rs @@ -24,7 +24,7 @@ use rusqlite::{params, OptionalExtension, TransactionBehavior}; use crate::{ - write::{Batch, Operation, ValueOp}, + write::{Batch, BitmapClass, Operation, ValueClass, ValueOp}, BitmapKey, IndexKey, Key, LogKey, ValueKey, }; @@ -95,6 +95,26 @@ impl SqliteStore { table ))? .execute([&key, value])?; + + if matches!(class, ValueClass::ReservedId) { + // Make sure the reserved id is not already in use + let key = BitmapKey { + account_id, + collection, + class: BitmapClass::DocumentIds, + block_num: document_id, + } + .serialize(0); + if trx + .prepare_cached("SELECT 1 FROM b WHERE k = ?")? + .query_row([&key], |_| Ok(true)) + .optional()? + .unwrap_or(false) + { + trx.rollback()?; + return Err(crate::Error::AssertValueFailed); + } + } } else { trx.prepare_cached(&format!("DELETE FROM {} WHERE k = ?", table))? .execute([&key])?; @@ -171,6 +191,7 @@ impl SqliteStore { .optional()? .unwrap_or_else(|| assert_value.is_none()); if !matches { + trx.rollback()?; return Err(crate::Error::AssertValueFailed); } } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 4c8d415e..17721463 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -6,7 +6,7 @@ resolver = "2" [features] #default = ["sqlite", "foundationdb", "postgres", "mysql", "rocks", "elastic", "s3", "redis"] -default = ["rocks"] +default = ["sqlite", "foundationdb", "postgres", "mysql", "rocks", "elastic", "s3", "redis"] sqlite = ["store/sqlite"] foundationdb = ["store/foundation"] postgres = ["store/postgres"] diff --git a/tests/src/directory/mod.rs b/tests/src/directory/mod.rs index 14d44dcf..af6a19ff 100644 --- a/tests/src/directory/mod.rs +++ b/tests/src/directory/mod.rs @@ -43,6 +43,22 @@ use tokio_rustls::TlsAcceptor; use crate::store::TempDir; const CONFIG: &str = r#" +[directory."rocksdb"] +type = "internal" +store = "rocksdb" + +[directory."rocksdb".options] +catch-all = true +subaddressing = true + +[directory."foundationdb"] +type = "internal" +store = "foundationdb" + +[directory."foundationdb".options] +catch-all = true +subaddressing = true + [directory."sqlite"] type = "sql" store = "sqlite" @@ -288,7 +304,9 @@ impl DirectoryTest { let mut config_file = CONFIG.replace("{TMP}", &temp_dir.path.to_string_lossy()); if id_store.is_some() { // Disable foundationdb store for SQL tests (the fdb select api version can only be run once per process) - config_file = config_file.replace("foundationdb", "ignore"); + config_file = config_file + .replace("type = \"foundationdb\"", "type = \"ignore\"") + .replace("store = \"foundationdb\"", "disable = true"); } let config = utils::config::Config::new(&config_file).unwrap(); let stores = config.parse_stores().await.unwrap(); diff --git a/tests/src/directory/sql.rs b/tests/src/directory/sql.rs index 340deb58..3166851f 100644 --- a/tests/src/directory/sql.rs +++ b/tests/src/directory/sql.rs @@ -325,7 +325,7 @@ impl DirectoryStore { ), "INSERT INTO accounts (name, secret, type) VALUES ('admin', 'secret', 'admin')", ] { - let query = if matches!(self.store, LookupStore::Store(Store::MySQL(_))) { + let query = if self.is_mysql() { query.replace("TEXT", "VARCHAR(255)") } else { query.to_string() @@ -346,12 +346,12 @@ impl DirectoryStore { }; self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { concat!( "INSERT INTO accounts (name, secret, description, ", "type, active) VALUES ($1, $2, $3, $4, true) ON CONFLICT (name) DO NOTHING" ) - } else if matches!(self.store, LookupStore::Store(Store::MySQL(_))) { + } else if self.is_mysql() { concat!( "INSERT IGNORE INTO accounts (name, secret, description, ", "type, active) VALUES (?, ?, ?, ?, true)" @@ -381,12 +381,12 @@ impl DirectoryStore { pub async fn create_test_group(&self, login: &str, name: &str) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { concat!( "INSERT INTO accounts (name, description, ", "type, active) VALUES ($1, $2, $3, $4) ON CONFLICT (name) DO NOTHING" ) - } else if matches!(self.store, LookupStore::Store(Store::MySQL(_))) { + } else if self.is_mysql() { concat!( "INSERT IGNORE INTO accounts (name, description, ", "type, active) VALUES (?, ?, ?, ?)" @@ -411,9 +411,9 @@ impl DirectoryStore { pub async fn link_test_address(&self, login: &str, address: &str, typ: &str) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { "INSERT INTO emails (name, address, type) VALUES ($1, $2, $3) ON CONFLICT (name, address) DO NOTHING" - } else if matches!(self.store, LookupStore::Store(Store::MySQL(_))) { + } else if self.is_mysql() { "INSERT IGNORE INTO emails (name, address, type) VALUES (?, ?, ?)" } else { "INSERT OR IGNORE INTO emails (name, address, type) VALUES (?, ?, ?)" @@ -427,7 +427,7 @@ impl DirectoryStore { pub async fn set_test_quota(&self, login: &str, quota: u32) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { "UPDATE accounts SET quota = $1 where name = $2" } else { "UPDATE accounts SET quota = ? where name = ?" @@ -441,7 +441,7 @@ impl DirectoryStore { pub async fn add_to_group(&self, login: &str, group: &str) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { "INSERT INTO group_members (name, member_of) VALUES ($1, $2)" } else { "INSERT INTO group_members (name, member_of) VALUES (?, ?)" @@ -455,7 +455,7 @@ impl DirectoryStore { pub async fn remove_from_group(&self, login: &str, group: &str) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { "DELETE FROM group_members WHERE name = $1 AND member_of = $2" } else { "DELETE FROM group_members WHERE name = ? AND member_of = ?" @@ -469,7 +469,7 @@ impl DirectoryStore { pub async fn remove_test_alias(&self, login: &str, alias: &str) { self.store .query::( - if matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) { + if self.is_postgresql() { "DELETE FROM emails WHERE name = $1 AND address = $2" } else { "DELETE FROM emails WHERE name = ? AND address = ?" @@ -479,4 +479,38 @@ impl DirectoryStore { .await .unwrap(); } + + fn is_mysql(&self) -> bool { + #[cfg(feature = "mysql")] + { + matches!(self.store, LookupStore::Store(Store::MySQL(_))) + } + #[cfg(not(feature = "mysql"))] + { + false + } + } + + fn is_postgresql(&self) -> bool { + #[cfg(feature = "postgres")] + { + matches!(self.store, LookupStore::Store(Store::PostgreSQL(_))) + } + #[cfg(not(feature = "postgres"))] + { + false + } + } + + #[allow(dead_code)] + fn is_sqlite(&self) -> bool { + #[cfg(feature = "sqlite")] + { + matches!(self.store, LookupStore::Store(Store::SQLite(_))) + } + #[cfg(not(feature = "sqlite"))] + { + false + } + } } diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs index a2c57a49..9ecb89bd 100644 --- a/tests/src/jmap/mod.rs +++ b/tests/src/jmap/mod.rs @@ -164,6 +164,7 @@ url = "https://localhost:9200" user = "elastic" password = "RtQ-Lu6+o4rxx=XJplVJ" allow-invalid-certs = true +disable = true # Elastic is disabled by default [certificate.default] cert = "file://{CERT}" @@ -286,10 +287,8 @@ pub async fn jmap_tests() { delete, ) .await; - //assert_is_empty(params.server.clone()).await; - let coco = 1; - /*email_query::test(&mut params, delete).await; + email_query::test(&mut params, delete).await; email_get::test(&mut params).await; email_set::test(&mut params).await; email_parse::test(&mut params).await; @@ -300,7 +299,7 @@ pub async fn jmap_tests() { thread_get::test(&mut params).await; thread_merge::test(&mut params).await; mailbox::test(&mut params).await; - delivery::test(&mut params).await;*/ + delivery::test(&mut params).await; auth_acl::test(&mut params).await; auth_limits::test(&mut params).await; auth_oauth::test(&mut params).await; diff --git a/tests/src/store/blob.rs b/tests/src/store/blob.rs index 20455b77..fc666354 100644 --- a/tests/src/store/blob.rs +++ b/tests/src/store/blob.rs @@ -38,9 +38,9 @@ pub async fn blob_tests() { Config::new(&CONFIG.replace("{TMP}", temp_dir.path.as_path().to_str().unwrap())).unwrap(); let stores = config.parse_stores().await.unwrap(); - for (store_id, blob_store) in stores.blob_stores { + for (store_id, blob_store) in &stores.blob_stores { println!("Testing blob store {}...", store_id); - test_store(blob_store).await; + test_store(blob_store.clone()).await; } for (store_id, store) in stores.stores { diff --git a/tests/src/store/lookup.rs b/tests/src/store/lookup.rs index 70d3fb61..53c9036e 100644 --- a/tests/src/store/lookup.rs +++ b/tests/src/store/lookup.rs @@ -39,15 +39,25 @@ pub async fn lookup_tests() { store.destroy().await; } - // Test value expiry + // Test key let key = "xyz".as_bytes().to_vec(); - assert_eq!( - LookupValue::None, - store - .key_get::(LookupKey::Key(key.clone())) - .await - .unwrap() - ); + store + .key_set( + key.clone(), + LookupValue::Value { + value: "world".to_string().into_bytes(), + expires: 0, + }, + ) + .await + .unwrap(); + store.purge_expired().await.unwrap(); + assert!(matches!(store + .key_get::(LookupKey::Key(key.clone())) + .await + .unwrap(), LookupValue::Value { value,.. } if value == "world")); + + // Test value expiry store .key_set( key.clone(), @@ -76,23 +86,6 @@ pub async fn lookup_tests() { store.assert_is_empty(store.clone().into()).await; } - // Test key - store - .key_set( - key.clone(), - LookupValue::Value { - value: "world".to_string().into_bytes(), - expires: 0, - }, - ) - .await - .unwrap(); - store.purge_expired().await.unwrap(); - assert!(matches!(store - .key_get::(LookupKey::Key(key.clone())) - .await - .unwrap(), LookupValue::Value { value,.. } if value == "world")); - // Test counter let key = "abc".as_bytes().to_vec(); store