Nats + Redis PubSub cluster updates replacing Gossip protocol

This commit is contained in:
mdecimus
2025-05-14 19:43:47 +02:00
parent 7ec5701af8
commit 839b7189fa
65 changed files with 1807 additions and 1350 deletions

View File

@@ -4,13 +4,21 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use std::time::Duration;
use imap_proto::ResponseType;
use crate::jmap::delivery::SmtpConnection;
use super::{AssertResult, ImapConnection, Type};
pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
const SLEEP: Duration = Duration::from_millis(200);
pub async fn test(
imap: &mut ImapConnection,
imap_check: &mut ImapConnection,
is_cluster_test: bool,
) {
println!("Running IDLE tests...");
// Switch connection to IDLE mode
@@ -28,6 +36,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
// Expect a new mailbox update
imap.send("CREATE Provolone").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -40,6 +51,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Continuation, ResponseType::Ok).await;
imap.send_untagged(message).await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -53,6 +67,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("STORE 1:* +FLAGS (\\Seen)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -66,6 +83,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("CLOSE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -77,6 +97,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
// Delete folder and expect an update
imap.send("DELETE Provolone").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -88,6 +111,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Continuation, ResponseType::Ok).await;
imap.send_untagged(message).await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -108,6 +134,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.send("STORE 1 +FLAGS (\\Deleted)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -118,6 +147,9 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
.await
.assert_contains("* 1 EXPUNGE")
.assert_contains("* 0 EXISTS");
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
@@ -133,7 +165,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
.assert_contains("* 0 EXISTS");
// Test SMTP delivery notifications
let mut lmtp = SmtpConnection::connect_port(11201).await;
let mut lmtp = SmtpConnection::connect_port(if is_cluster_test { 17000 } else { 11201 }).await;
lmtp.ingest(
"bill@example.com",
&["jdoe@example.com"],
@@ -148,11 +180,18 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
),
)
.await;
if is_cluster_test {
tokio::time::sleep(SLEEP).await;
}
imap_check
.assert_read(Type::Status, ResponseType::Ok)
.await
.assert_contains("STATUS \"INBOX\"")
.assert_contains("MESSAGES 11");
.assert_contains(if is_cluster_test {
"MESSAGES 1"
} else {
"MESSAGES 11"
});
// Stop IDLE mode
imap_check.send_raw("DONE").await;

View File

@@ -26,6 +26,7 @@ use crate::{
use ::managesieve::core::ManageSieveSessionManager;
use ::store::Stores;
use ahash::AHashSet;
use base64::{Engine, engine::general_purpose};
use common::{
Caches, Core, Data, Inner, Server,
config::{
@@ -95,7 +96,7 @@ pub async fn imap_tests() {
store::test(&mut imap, &mut imap_check, &handle).await;
copy_move::test(&mut imap, &mut imap_check).await;
thread::test(&mut imap, &mut imap_check).await;
idle::test(&mut imap, &mut imap_check).await;
idle::test(&mut imap, &mut imap_check, false).await;
condstore::test(&mut imap, &mut imap_check).await;
acl::test(&mut imap, &mut imap_check).await;
@@ -169,7 +170,7 @@ async fn init_imap_tests(store_id: &str, delete_if_exists: bool) -> IMAPTest {
let cache = Caches::parse(&mut config);
let store = core.storage.data.clone();
let (ipc, mut ipc_rxs) = build_ipc(&mut config);
let (ipc, mut ipc_rxs) = build_ipc(&mut config, false);
let inner = Arc::new(Inner {
shared_core: core.into_shared(),
data,
@@ -306,8 +307,11 @@ pub enum Type {
impl ImapConnection {
pub async fn connect(tag: &'static [u8]) -> Self {
let (reader, writer) =
tokio::io::split(TcpStream::connect("127.0.0.1:9991").await.unwrap());
Self::connect_to(tag, "127.0.0.1:9991").await
}
pub async fn connect_to(tag: &'static [u8], addr: impl AsRef<str>) -> Self {
let (reader, writer) = tokio::io::split(TcpStream::connect(addr.as_ref()).await.unwrap());
ImapConnection {
tag,
reader: BufReader::new(reader).lines(),
@@ -377,6 +381,16 @@ impl ImapConnection {
}
}
pub async fn authenticate(&mut self, user: &str, pass: &str) {
let creds = general_purpose::STANDARD.encode(format!("\0{user}\0{pass}"));
self.send(&format!(
"AUTHENTICATE PLAIN {{{}+}}\r\n{creds}",
creds.len()
))
.await;
self.assert_read(Type::Tagged, ResponseType::Ok).await;
}
pub async fn send(&mut self, text: &str) {
//let c = println!("-> {}{:?}", std::str::from_utf8(self.tag).unwrap(), text);
self.writer.write_all(self.tag).await.unwrap();