Registry testing - part 7

This commit is contained in:
mdecimus
2026-03-17 18:15:50 +01:00
parent 56064d7f62
commit 544598c840
83 changed files with 1410 additions and 1100 deletions

View File

@@ -146,7 +146,7 @@ impl Account {
pub async fn find_or_create_domain(&self, name: &'static str) -> Id {
let ids = self
.registry_query(
.registry_query_ids(
ObjectType::Domain,
[(Property::Name, name)],
Vec::<&str>::new(),
@@ -173,7 +173,7 @@ impl Account {
let mut role_ids = Vec::new();
for name in names {
let role_id = *self
.registry_query(
.registry_query_ids(
ObjectType::Role,
[(Property::Description, *name)],
Vec::<&str>::new(),

View File

@@ -504,6 +504,18 @@ impl JmapResponse {
})
}
pub fn assert_destroyed(&self, expected: &[Id]) -> &Self {
let destroyed_ids = self.destroyed_ids().collect::<Vec<_>>();
for expected in expected {
if !destroyed_ids.contains(expected) {
panic!(
"Expected id {expected} to be destroyed but got destroyed ids {destroyed_ids:?}: {self:?}"
);
}
}
self
}
pub fn not_destroyed(&self, id: &str) -> &Value {
self.0
.pointer(&format!("/methodResponses/0/1/notDestroyed/{id}"))
@@ -638,6 +650,8 @@ pub trait JmapUtils {
fn text_field(&self, field: &str) -> &str;
fn integer_field(&self, field: &str) -> i64;
fn assert_is_equal(&self, other: Value);
}
@@ -647,6 +661,13 @@ impl JmapUtils for Value {
.and_then(|v| v.as_str())
.unwrap_or_else(|| panic!("Missing {field} in object: {self:?}"))
}
fn integer_field(&self, field: &str) -> i64 {
self.pointer(&format!("/{field}"))
.and_then(|v| v.as_i64())
.unwrap_or_else(|| panic!("Missing {field} in object: {self:?}"))
}
fn assert_is_equal(&self, expected: Value) {
if self != &expected {
panic!(
@@ -656,6 +677,7 @@ impl JmapUtils for Value {
);
}
}
fn with_property(mut self, field: impl Display, value: impl Into<Value>) -> Self {
if let Value::Object(map) = &mut self {
map.insert(field.to_string(), value.into());

View File

@@ -77,12 +77,24 @@ impl Account {
.await
}
pub async fn registry_query(
pub async fn registry_query_ids(
&self,
object: ObjectType,
filter: impl IntoIterator<Item = (impl Display, impl Into<Value>)>,
sort_by: impl IntoIterator<Item = impl Display>,
) -> Vec<Id> {
self.registry_query(object, filter, sort_by)
.await
.object_ids()
.collect()
}
pub async fn registry_query(
&self,
object: ObjectType,
filter: impl IntoIterator<Item = (impl Display, impl Into<Value>)>,
sort_by: impl IntoIterator<Item = impl Display>,
) -> JmapResponse {
let name = object.as_str();
self.jmap_query(
@@ -92,8 +104,6 @@ impl Account {
Vec::<(&str, &str)>::new(),
)
.await
.object_ids()
.collect()
}
pub async fn registry_destroy(

View File

@@ -9,9 +9,9 @@ use crate::{
store::TempDir,
utils::{
account::Account,
cleanup::{search_store_destroy, store_destroy},
cleanup::{search_store_destroy, store_blob_expire_all, store_destroy},
registry::UnwrapRegistryId,
storage::{RegistryEnvStores, assert_is_empty, build_data_store},
storage::{RegistryEnvStores, assert_is_empty, build_data_store, wait_for_tasks},
},
};
use ahash::AHashMap;
@@ -27,6 +27,7 @@ use common::{
};
use http::HttpSessionManager;
use imap::core::ImapSessionManager;
use jmap_client::client::{Client, Credentials};
use managesieve::core::ManageSieveSessionManager;
use pop3::Pop3SessionManager;
use registry::{
@@ -38,13 +39,20 @@ use registry::{
types::{EnumImpl, map::Map},
};
use services::{SpawnServices, broadcast::subscriber::spawn_broadcast_subscriber};
use smtp::{SpawnQueueManager, core::SmtpSessionManager};
use std::{str::FromStr, sync::Arc};
use smtp::{
SpawnQueueManager,
core::SmtpSessionManager,
queue::{
manager::Queue,
spool::{QueuedMessages, SmtpSpool},
},
};
use std::{str::FromStr, sync::Arc, time::Duration};
use store::{
RegistryStore, Store,
registry::{bootstrap::Bootstrap, write::RegistryWrite},
};
use tokio::sync::watch;
use tokio::sync::{mpsc, watch};
use trc::EventType;
use types::id::Id;
@@ -287,6 +295,14 @@ impl TestServer {
self.accounts.get(name).unwrap()
}
pub async fn wait_for_tasks(&self) {
wait_for_tasks(&self.server).await;
}
pub async fn blob_expire_all(&self) {
store_blob_expire_all(&self.server.core.storage.data).await;
}
pub async fn assert_is_empty(&self) {
assert_is_empty(&self.server).await;
}
@@ -302,4 +318,41 @@ impl TestServer {
pub fn shutdown(&self) {
let _ = self.shutdown_tx.send(true);
}
pub async fn all_queued_messages(&self) -> QueuedMessages {
self.server
.next_event(&mut Queue::new(
self.server.inner.clone(),
mpsc::channel(100).1,
))
.await
}
pub async fn destroy_all_mailboxes(&self, account: &Account) {
self.wait_for_tasks().await;
destroy_all_mailboxes_no_wait(account.client()).await;
}
}
pub async fn destroy_all_mailboxes_for_account(account_id: u32) {
let mut client = Client::new()
.credentials(Credentials::basic("admin", "secret"))
.follow_redirects(["127.0.0.1"])
.timeout(Duration::from_secs(3600))
.accept_invalid_certs(true)
.connect("https://127.0.0.1:8899")
.await
.unwrap();
client.set_default_account_id(Id::from(account_id));
destroy_all_mailboxes_no_wait(&client).await;
}
async fn destroy_all_mailboxes_no_wait(client: &Client) {
let mut request = client.build();
request.query_mailbox().arguments().sort_as_tree(true);
let mut ids = request.send_query_mailbox().await.unwrap().take_ids();
ids.reverse();
for id in ids {
client.mailbox_destroy(&id, true).await.unwrap();
}
}

View File

@@ -154,7 +154,7 @@ fn build_search_store(typ: SearchStoreType, _path: &str) -> SearchStore {
}
}
pub async fn wait_for_index(server: &Server) {
pub async fn wait_for_tasks(server: &Server) {
let mut count = 0;
loop {
let mut has_index_tasks = None;
@@ -193,7 +193,7 @@ pub async fn wait_for_index(server: &Server) {
pub async fn assert_is_empty(server: &Server) {
// Wait for pending index tasks
wait_for_index(server).await;
wait_for_tasks(server).await;
// Assert is empty
store_assert_is_empty(server.store(), server.core.storage.blob.clone(), false).await;