Allow multiple backends to run in parallel for repl tests (#1346)

This commit is contained in:
Firstyear 2023-01-25 14:14:16 +10:00 committed by GitHub
parent 723c428e37
commit 08ebcc7901
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 340 additions and 52 deletions

View file

@ -98,6 +98,100 @@ pub(crate) fn qs_test(_args: &TokenStream, item: TokenStream, with_init: bool) -
result.into()
}
pub(crate) fn qs_pair_test(_args: &TokenStream, item: TokenStream, with_init: bool) -> TokenStream {
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
return token_stream_with_error(item, syn::Error::new_spanned(attr, msg));
};
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
}
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, _last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
let header = quote! {
#[::core::prelude::v1::test]
};
let init = if with_init {
quote! {
server_a.initialise_helper(duration_from_epoch_now())
.await
.expect("init_a failed!");
server_b.initialise_helper(duration_from_epoch_now())
.await
.expect("init_b failed!");
}
} else {
quote! {}
};
let test_fn = &input.sig.ident;
let test_driver = Ident::new(&format!("qs_{}", test_fn), input.sig.span());
// Effectively we are just injecting a real test function around this which we will
// call.
let result = quote! {
#input
#header
fn #test_driver() {
let body = async {
let (server_a, server_b) = crate::testkit::setup_pair_test().await;
#init
#test_fn(&server_a, &server_b).await;
// Any needed teardown?
// Make sure there are no errors.
let verifications_a = server_a.verify().await;
let verifications_b = server_b.verify().await;
trace!("Verification result: {:?}, {:?}", verifications_a, verifications_b);
assert!(verifications_a.len() + verifications_b.len() == 0);
};
#[allow(clippy::expect_used, clippy::diverging_sub_expression)]
{
return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body);
}
}
};
result.into()
}
pub(crate) fn idm_test(_args: &TokenStream, item: TokenStream) -> TokenStream {
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,

View file

@ -22,6 +22,11 @@ pub fn qs_test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_test(&args, item, true)
}
#[proc_macro_attribute]
pub fn qs_pair_test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_pair_test(&args, item, true)
}
#[proc_macro_attribute]
pub fn qs_test_no_init(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_test(&args, item, false)

View file

@ -99,16 +99,19 @@ impl TryFrom<IdRawEntry> for IdSqliteEntry {
#[derive(Clone)]
pub struct IdlSqlite {
pool: Pool<SqliteConnectionManager>,
db_name: &'static str,
}
pub struct IdlSqliteReadTransaction {
committed: bool,
conn: r2d2::PooledConnection<SqliteConnectionManager>,
db_name: &'static str,
}
pub struct IdlSqliteWriteTransaction {
committed: bool,
conn: r2d2::PooledConnection<SqliteConnectionManager>,
db_name: &'static str,
}
pub trait IdlSqliteTransaction {
@ -561,7 +564,7 @@ pub trait IdlSqliteTransaction {
impl IdlSqliteTransaction for IdlSqliteReadTransaction {
fn get_db_name(&self) -> &str {
"main"
self.db_name
}
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
@ -585,7 +588,10 @@ impl Drop for IdlSqliteReadTransaction {
}
impl IdlSqliteReadTransaction {
pub fn new(conn: r2d2::PooledConnection<SqliteConnectionManager>) -> Self {
pub fn new(
conn: r2d2::PooledConnection<SqliteConnectionManager>,
db_name: &'static str,
) -> Self {
// Start the transaction
//
// I'm happy for this to be an expect, because this is a huge failure
@ -599,13 +605,14 @@ impl IdlSqliteReadTransaction {
IdlSqliteReadTransaction {
committed: false,
conn,
db_name,
}
}
}
impl IdlSqliteTransaction for IdlSqliteWriteTransaction {
fn get_db_name(&self) -> &str {
"main"
self.db_name
}
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager> {
@ -626,7 +633,10 @@ impl Drop for IdlSqliteWriteTransaction {
}
impl IdlSqliteWriteTransaction {
pub fn new(conn: r2d2::PooledConnection<SqliteConnectionManager>) -> Self {
pub fn new(
conn: r2d2::PooledConnection<SqliteConnectionManager>,
db_name: &'static str,
) -> Self {
// Start the transaction
#[allow(clippy::expect_used)]
conn.execute("BEGIN EXCLUSIVE TRANSACTION", [])
@ -634,6 +644,7 @@ impl IdlSqliteWriteTransaction {
IdlSqliteWriteTransaction {
committed: false,
conn,
db_name,
}
}
@ -656,7 +667,7 @@ impl IdlSqliteWriteTransaction {
.conn
.prepare(&format!(
"SELECT MAX(id) as id_max FROM {}.id2entry",
"main"
self.get_db_name(),
))
.map_err(sqlite_error)?;
// This exists checks for if any rows WERE returned
@ -724,7 +735,7 @@ impl IdlSqliteWriteTransaction {
.conn
.prepare(&format!(
"INSERT OR REPLACE INTO {}.id2entry (id, data) VALUES(:id, :data)",
"main"
self.get_db_name()
))
.map_err(sqlite_error)?;
@ -781,7 +792,10 @@ impl IdlSqliteWriteTransaction {
pub fn delete_identry(&self, id: u64) -> Result<(), OperationError> {
let mut stmt = self
.conn
.prepare(&format!("DELETE FROM {}.id2entry WHERE id = :id", "main"))
.prepare(&format!(
"DELETE FROM {}.id2entry WHERE id = :id",
self.get_db_name()
))
.map_err(sqlite_error)?;
let iid: i64 = id
@ -812,7 +826,7 @@ impl IdlSqliteWriteTransaction {
// Delete this idx_key from the table.
let query = format!(
"DELETE FROM {}.idx_{}_{} WHERE key = :key",
"main",
self.get_db_name(),
itype.as_idx_str(),
attr
);
@ -828,7 +842,7 @@ impl IdlSqliteWriteTransaction {
// update or create it.
let query = format!(
"INSERT OR REPLACE INTO {}.idx_{}_{} (key, idl) VALUES(:key, :idl)",
"main",
self.get_db_name(),
itype.as_idx_str(),
attr
);
@ -850,7 +864,7 @@ impl IdlSqliteWriteTransaction {
pub fn create_name2uuid(&self) -> Result<(), OperationError> {
self.conn
.execute(
&format!("CREATE TABLE IF NOT EXISTS {}.idx_name2uuid (name TEXT PRIMARY KEY, uuid TEXT)", "main"),
&format!("CREATE TABLE IF NOT EXISTS {}.idx_name2uuid (name TEXT PRIMARY KEY, uuid TEXT)", self.get_db_name()),
[],
)
.map(|_| ())
@ -863,7 +877,7 @@ impl IdlSqliteWriteTransaction {
self.conn
.prepare(&format!(
"INSERT OR REPLACE INTO {}.idx_name2uuid (name, uuid) VALUES(:name, :uuid)",
"main"
self.get_db_name()
))
.and_then(|mut stmt| {
stmt.execute(named_params! {
@ -879,7 +893,7 @@ impl IdlSqliteWriteTransaction {
self.conn
.prepare(&format!(
"DELETE FROM {}.idx_name2uuid WHERE name = :name",
"main"
self.get_db_name()
))
.and_then(|mut stmt| stmt.execute(&[(":name", &name)]))
.map(|_| ())
@ -889,7 +903,7 @@ impl IdlSqliteWriteTransaction {
pub fn create_externalid2uuid(&self) -> Result<(), OperationError> {
self.conn
.execute(
&format!("CREATE TABLE IF NOT EXISTS {}.idx_externalid2uuid (eid TEXT PRIMARY KEY, uuid TEXT)", "main"),
&format!("CREATE TABLE IF NOT EXISTS {}.idx_externalid2uuid (eid TEXT PRIMARY KEY, uuid TEXT)", self.get_db_name()),
[],
)
.map(|_| ())
@ -902,7 +916,7 @@ impl IdlSqliteWriteTransaction {
self.conn
.prepare(&format!(
"INSERT OR REPLACE INTO {}.idx_externalid2uuid (eid, uuid) VALUES(:eid, :uuid)",
"main"
self.get_db_name()
))
.and_then(|mut stmt| {
stmt.execute(named_params! {
@ -918,7 +932,7 @@ impl IdlSqliteWriteTransaction {
self.conn
.prepare(&format!(
"DELETE FROM {}.idx_externalid2uuid WHERE eid = :eid",
"main"
self.get_db_name()
))
.and_then(|mut stmt| stmt.execute(&[(":eid", &name)]))
.map(|_| ())
@ -930,7 +944,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"CREATE TABLE IF NOT EXISTS {}.idx_uuid2spn (uuid TEXT PRIMARY KEY, spn BLOB)",
"main"
self.get_db_name()
),
[],
)
@ -972,7 +986,7 @@ impl IdlSqliteWriteTransaction {
self.conn
.prepare(&format!(
"INSERT OR REPLACE INTO {}.idx_uuid2spn (uuid, spn) VALUES(:uuid, :spn)",
"main"
self.get_db_name()
))
.and_then(|mut stmt| {
stmt.execute(named_params! {
@ -987,7 +1001,7 @@ impl IdlSqliteWriteTransaction {
.conn
.prepare(&format!(
"DELETE FROM {}.idx_uuid2spn WHERE uuid = :uuid",
"main"
self.get_db_name()
))
.and_then(|mut stmt| stmt.execute(&[(":uuid", &uuids)]))
.map(|_| ())
@ -1000,7 +1014,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"CREATE TABLE IF NOT EXISTS {}.idx_uuid2rdn (uuid TEXT PRIMARY KEY, rdn TEXT)",
"main"
self.get_db_name()
),
[],
)
@ -1015,7 +1029,7 @@ impl IdlSqliteWriteTransaction {
.conn
.prepare(&format!(
"INSERT OR REPLACE INTO {}.idx_uuid2rdn (uuid, rdn) VALUES(:uuid, :rdn)",
"main"
self.get_db_name()
))
.and_then(|mut stmt| stmt.execute(&[(":uuid", &uuids), (":rdn", k)]))
.map(|_| ())
@ -1024,7 +1038,7 @@ impl IdlSqliteWriteTransaction {
.conn
.prepare(&format!(
"DELETE FROM {}.idx_uuid2rdn WHERE uuid = :uuid",
"main"
self.get_db_name()
))
.and_then(|mut stmt| stmt.execute(&[(":uuid", &uuids)]))
.map(|_| ())
@ -1039,7 +1053,7 @@ impl IdlSqliteWriteTransaction {
// We could also re-design our idl storage.
let idx_stmt = format!(
"CREATE TABLE IF NOT EXISTS {}.idx_{}_{} (key TEXT PRIMARY KEY, idl BLOB)",
"main",
self.get_db_name(),
itype.as_idx_str(),
attr
);
@ -1057,7 +1071,7 @@ impl IdlSqliteWriteTransaction {
idx_table_list.iter().try_for_each(|idx_table| {
trace!(table = ?idx_table, "removing idx_table");
self.conn
.prepare(format!("DROP TABLE {}.{}", "main", idx_table).as_str())
.prepare(format!("DROP TABLE {}.{}", self.get_db_name(), idx_table).as_str())
.and_then(|mut stmt| stmt.execute([]).map(|_| ()))
.map_err(sqlite_error)
})
@ -1074,7 +1088,7 @@ impl IdlSqliteWriteTransaction {
id TEXT PRIMARY KEY,
slope INTEGER
)",
"main"
self.get_db_name()
),
[],
)
@ -1083,7 +1097,10 @@ impl IdlSqliteWriteTransaction {
// Remove any data if it exists.
self.conn
.execute(&format!("DELETE FROM {}.idxslope_analysis", "main"), [])
.execute(
&format!("DELETE FROM {}.idxslope_analysis", self.get_db_name()),
[],
)
.map(|_| ())
.map_err(sqlite_error)?;
@ -1091,7 +1108,7 @@ impl IdlSqliteWriteTransaction {
let key = format!("idx_{}_{}", k.itype.as_idx_str(), k.attr);
self.conn
.execute(
&format!("INSERT OR REPLACE INTO {}.idxslope_analysis (id, slope) VALUES(:id, :slope)", "main"),
&format!("INSERT OR REPLACE INTO {}.idxslope_analysis (id, slope) VALUES(:id, :slope)", self.get_db_name()),
named_params! {
":id": &key,
":slope": &v,
@ -1124,7 +1141,7 @@ impl IdlSqliteWriteTransaction {
.get_conn()
.prepare(&format!(
"SELECT slope FROM {}.idxslope_analysis WHERE id = :id",
"main"
self.get_db_name()
))
.map_err(sqlite_error)?;
@ -1140,7 +1157,7 @@ impl IdlSqliteWriteTransaction {
pub unsafe fn purge_id2entry(&self) -> Result<(), OperationError> {
self.conn
.execute(&format!("DELETE FROM {}.id2entry", "main"), [])
.execute(&format!("DELETE FROM {}.id2entry", self.get_db_name()), [])
.map(|_| ())
.map_err(sqlite_error)
}
@ -1156,7 +1173,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"INSERT OR REPLACE INTO {}.db_sid (id, data) VALUES(:id, :sid)",
"main"
self.get_db_name()
),
named_params! {
":id": &2,
@ -1182,7 +1199,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"INSERT OR REPLACE INTO {}.db_did (id, data) VALUES(:id, :did)",
"main"
self.get_db_name()
),
named_params! {
":id": &2,
@ -1208,7 +1225,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"INSERT OR REPLACE INTO {}.db_op_ts (id, data) VALUES(:id, :did)",
"main"
self.get_db_name()
),
named_params! {
":id": &1,
@ -1228,7 +1245,10 @@ impl IdlSqliteWriteTransaction {
fn get_db_version_key(&self, key: &str) -> i64 {
self.conn
.query_row(
&format!("SELECT version FROM {}.db_version WHERE id = :id", "main"),
&format!(
"SELECT version FROM {}.db_version WHERE id = :id",
self.get_db_name()
),
&[(":id", &key)],
|row| row.get(0),
)
@ -1243,7 +1263,7 @@ impl IdlSqliteWriteTransaction {
.execute(
&format!(
"INSERT OR REPLACE INTO {}.db_version (id, version) VALUES(:id, :dbv_id2entry)",
"main"
self.get_db_name()
),
named_params! {
":id": &key,
@ -1266,6 +1286,16 @@ impl IdlSqliteWriteTransaction {
}
pub fn setup(&self) -> Result<(), OperationError> {
// If the db_name is NOT main, we MAY need to create it as we are in
// a test!
if self.get_db_name() != "main" {
warn!("Using non-default db-name - this database content WILL be lost!");
// we need to attach the DB!
self.conn
.execute(&format!("ATTACH DATABASE '' AS {}", self.get_db_name()), [])
.map_err(sqlite_error)?;
};
// This stores versions of components. For example:
// ----------------------
// | id | version |
@ -1286,7 +1316,7 @@ impl IdlSqliteWriteTransaction {
version INTEGER
)
",
"main"
self.get_db_name()
),
[],
)
@ -1306,7 +1336,7 @@ impl IdlSqliteWriteTransaction {
data BLOB NOT NULL
)
",
"main"
self.get_db_name()
),
[],
)
@ -1318,7 +1348,7 @@ impl IdlSqliteWriteTransaction {
data BLOB NOT NULL
)
",
"main"
self.get_db_name()
),
[],
)
@ -1339,7 +1369,7 @@ impl IdlSqliteWriteTransaction {
data BLOB NOT NULL
)
",
"main"
self.get_db_name()
),
[],
)
@ -1358,7 +1388,7 @@ impl IdlSqliteWriteTransaction {
data BLOB NOT NULL
)
",
"main"
self.get_db_name()
),
[],
)
@ -1505,7 +1535,10 @@ impl IdlSqlite {
OperationError::SqliteError
})?;
Ok(IdlSqlite { pool })
Ok(IdlSqlite {
pool,
db_name: cfg.db_name,
})
}
pub(crate) fn get_allids_count(&self) -> Result<u64, OperationError> {
@ -1526,7 +1559,7 @@ impl IdlSqlite {
.pool
.try_get()
.expect("Unable to get connection from pool!!!");
IdlSqliteReadTransaction::new(conn)
IdlSqliteReadTransaction::new(conn, self.db_name)
}
pub fn write(&self) -> IdlSqliteWriteTransaction {
@ -1535,7 +1568,7 @@ impl IdlSqlite {
.pool
.try_get()
.expect("Unable to get connection from pool!!!");
IdlSqliteWriteTransaction::new(conn)
IdlSqliteWriteTransaction::new(conn, self.db_name)
}
}
@ -1547,7 +1580,7 @@ mod tests {
#[test]
fn test_idl_sqlite_verify() {
let _ = sketching::test_init();
let cfg = BackendConfig::new_test();
let cfg = BackendConfig::new_test("main");
let be = IdlSqlite::new(&cfg, false).unwrap();
let be_w = be.write();
let r = be_w.verify();

View file

@ -108,6 +108,7 @@ impl IdxMeta {
pub struct BackendConfig {
path: String,
pool_size: u32,
db_name: &'static str,
fstype: FsType,
// Cachesizes?
arcsize: Option<usize>,
@ -118,15 +119,17 @@ impl BackendConfig {
BackendConfig {
pool_size,
path: path.to_string(),
db_name: "main",
fstype,
arcsize,
}
}
pub(crate) fn new_test() -> Self {
pub(crate) fn new_test(db_name: &'static str) -> Self {
BackendConfig {
pool_size: 1,
path: "".to_string(),
db_name,
fstype: FsType::Generic,
arcsize: Some(1024),
}
@ -1834,7 +1837,7 @@ mod tests {
},
];
let be = Backend::new(BackendConfig::new_test(), idxmeta, false)
let be = Backend::new(BackendConfig::new_test("main"), idxmeta, false)
.expect("Failed to setup backend");
let mut be_txn = be.write();
@ -3164,4 +3167,68 @@ mod tests {
assert!(res == Err(OperationError::ResourceLimit));
})
}
#[test]
fn test_be_mulitple_create() {
let _ = sketching::test_init();
// This is a demo idxmeta, purely for testing.
let idxmeta = vec![IdxKey {
attr: AttrString::from("uuid"),
itype: IndexType::Equality,
}];
let be_a = Backend::new(BackendConfig::new_test("main"), idxmeta.clone(), false)
.expect("Failed to setup backend");
let be_b = Backend::new(BackendConfig::new_test("db_2"), idxmeta, false)
.expect("Failed to setup backend");
let mut be_a_txn = be_a.write();
let mut be_b_txn = be_b.write();
assert!(be_a_txn.get_db_s_uuid() != be_b_txn.get_db_s_uuid());
// Create into A
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("william"));
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
let e = unsafe { e.into_sealed_new() };
let single_result = be_a_txn.create(&CID_ZERO, vec![e.clone()]);
assert!(single_result.is_ok());
// Assert it's in A but not B.
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("william"))) };
let lims = Limits::unlimited();
let r = be_a_txn.search(&lims, &filt);
assert!(r.expect("Search failed!").len() == 1);
let r = be_b_txn.search(&lims, &filt);
assert!(r.expect("Search failed!").len() == 0);
// Create into B
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
e.add_ava("userid", Value::from("claire"));
e.add_ava("uuid", Value::from("0c680959-0944-47d6-9dea-53304d124266"));
let e = unsafe { e.into_sealed_new() };
let single_result = be_b_txn.create(&CID_ZERO, vec![e.clone()]);
assert!(single_result.is_ok());
// Assert it's in B but not A
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire"))) };
let lims = Limits::unlimited();
let r = be_a_txn.search(&lims, &filt);
assert!(r.expect("Search failed!").len() == 0);
let r = be_b_txn.search(&lims, &filt);
assert!(r.expect("Search failed!").len() == 1);
}
}

View file

@ -9,8 +9,8 @@ macro_rules! setup_test {
let schema_txn = schema_outer.write_blocking();
schema_txn.reload_idxmeta()
};
let be =
Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let be = Backend::new(BackendConfig::new_test("main"), idxmeta, false)
.expect("Failed to init BE");
let qs = QueryServer::new(be, schema_outer, "example.com".to_string());
async_std::task::block_on(qs.initialise_helper(duration_from_epoch_now()))
@ -30,8 +30,8 @@ macro_rules! setup_test {
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be =
Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let be = Backend::new(BackendConfig::new_test("main"), idxmeta, false)
.expect("Failed to init BE");
let qs = QueryServer::new(be, schema_outer, "example.com".to_string());
async_std::task::block_on(qs.initialise_helper(duration_from_epoch_now()))

View file

@ -0,0 +1,7 @@
use crate::prelude::*;
#[tokio::test]
async fn multiple_qs_setup() {
assert!(true);
}

View file

@ -168,8 +168,7 @@ mod tests {
let filt = filter!(f_eq("name", PartialValue::new_iname("testperson")));
let admin = server_txn.internal_search_uuid(UUID_ADMIN).expect("failed");
let se1 = unsafe { SearchEvent::new_impersonate_entry(admin.clone(), filt.clone()) };
let se2 = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
let se1 = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
let mut e = entry_init!(
("class", Value::new_class("object")),
@ -193,7 +192,7 @@ mod tests {
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
let r2 = server_txn.search(&se2).expect("search failure");
let r2 = server_txn.search(&se1).expect("search failure");
debug!("--> {:?}", r2);
assert!(r2.len() == 1);
@ -210,4 +209,51 @@ mod tests {
assert!(server_txn.commit().is_ok());
}
#[qs_pair_test]
async fn test_pair_create_user(server_a: &QueryServer, server_b: &QueryServer) {
let mut server_a_txn = server_a.write(duration_from_epoch_now()).await;
let mut server_b_txn = server_b.write(duration_from_epoch_now()).await;
// Create on server a
let filt = filter!(f_eq("name", PartialValue::new_iname("testperson")));
let admin = server_a_txn
.internal_search_uuid(UUID_ADMIN)
.expect("failed");
let se_a = unsafe { SearchEvent::new_impersonate_entry(admin, filt.clone()) };
let admin = server_b_txn
.internal_search_uuid(UUID_ADMIN)
.expect("failed");
let se_b = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
let e = entry_init!(
("class", Value::new_class("person")),
("class", Value::new_class("account")),
("name", Value::new_iname("testperson")),
("description", Value::new_utf8s("testperson")),
("displayname", Value::new_utf8s("testperson"))
);
let cr = server_a_txn.internal_create(vec![e.clone()]);
assert!(cr.is_ok());
let r1 = server_a_txn.search(&se_a).expect("search failure");
assert!(!r1.is_empty());
// Not on sb
let r2 = server_b_txn.search(&se_b).expect("search failure");
assert!(r2.is_empty());
let cr = server_b_txn.internal_create(vec![e.clone()]);
assert!(cr.is_ok());
// Now is present
let r2 = server_b_txn.search(&se_b).expect("search failure");
assert!(!r2.is_empty());
assert!(server_a_txn.commit().is_ok());
assert!(server_b_txn.commit().is_ok());
}
}

View file

@ -14,12 +14,48 @@ pub async fn setup_test() -> QueryServer {
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be = Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let be =
Backend::new(BackendConfig::new_test("main"), idxmeta, false).expect("Failed to init BE");
// Init is called via the proc macro
QueryServer::new(be, schema_outer, "example.com".to_string())
}
#[allow(clippy::expect_used)]
pub async fn setup_pair_test() -> (QueryServer, QueryServer) {
sketching::test_init();
let qs_a = {
// Create an in memory BE
let schema_outer = Schema::new().expect("Failed to init schema");
let idxmeta = {
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be = Backend::new(BackendConfig::new_test("db_a"), idxmeta, false)
.expect("Failed to init BE");
// Init is called via the proc macro
QueryServer::new(be, schema_outer, "example.com".to_string())
};
let qs_b = {
// Create an in memory BE
let schema_outer = Schema::new().expect("Failed to init schema");
let idxmeta = {
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be = Backend::new(BackendConfig::new_test("db_b"), idxmeta, false)
.expect("Failed to init BE");
// Init is called via the proc macro
QueryServer::new(be, schema_outer, "example.com".to_string())
};
(qs_a, qs_b)
}
#[allow(clippy::expect_used)]
pub async fn setup_idm_test() -> (IdmServer, IdmServerDelayed) {
let qs = setup_test().await;