From d3370d5d5472d02d229404483261eac7028f5065 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Wed, 18 Mar 2026 10:46:46 -0300 Subject: [PATCH] test: MDN on pre-message has effect if received before sending full message (#8004) --- src/config.rs | 4 +++ src/context.rs | 7 +++++ src/test_utils.rs | 17 ++++++++--- src/tests/pre_messages/receiving.rs | 44 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 16fac5de7..0bdc75547 100644 --- a/src/config.rs +++ b/src/config.rs @@ -427,6 +427,10 @@ pub enum Config { /// storing the same token multiple times on the server. EncryptedDeviceToken, + /// Make `TestContext::pop_sent_msg_opt()` and related functions pop messages from the `smtp` + /// head, i.e. make it a queue. For historical reasons the default is a stack. + PopSentMsgFromHead, + /// Enables running test hooks, e.g. see `InnerContext::pre_encrypt_mime_hook`. /// This way is better than conditional compilation, i.e. `#[cfg(test)]`, because tests not /// using this still run unmodified code. diff --git a/src/context.rs b/src/context.rs index adcb3b2a7..d78fc6f61 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1084,6 +1084,13 @@ impl Context { .await? .to_string(), ); + res.insert( + "pop_sent_msg_from_head", + self.sql + .get_raw_config("pop_sent_msg_from_head") + .await? + .unwrap_or_default(), + ); res.insert( "test_hooks", self.sql diff --git a/src/test_utils.rs b/src/test_utils.rs index 0435f330e..ed5cf8219 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -624,16 +624,25 @@ impl TestContext { } pub async fn pop_sent_msg_opt(&self, timeout: Duration) -> Option> { + let from_head = self + .get_config_bool(Config::PopSentMsgFromHead) + .await + .unwrap(); + let order_subst = match from_head { + true => "", + false => " DESC", + }; let start = Instant::now(); let (rowid, msg_id, payload, recipients) = loop { let row = self .ctx .sql .query_row_optional( - r#" - SELECT id, msg_id, mime, recipients - FROM smtp - ORDER BY id DESC"#, + &format!( + "SELECT id, msg_id, mime, recipients +FROM smtp +ORDER BY id{order_subst}" + ), (), |row| { let rowid: i64 = row.get(0)?; diff --git a/src/tests/pre_messages/receiving.rs b/src/tests/pre_messages/receiving.rs index ec0aa9d64..3863cb1f3 100644 --- a/src/tests/pre_messages/receiving.rs +++ b/src/tests/pre_messages/receiving.rs @@ -4,6 +4,7 @@ use pretty_assertions::assert_eq; use crate::EventType; use crate::chat; +use crate::config::Config; use crate::contact; use crate::download::{DownloadState, PRE_MSG_ATTACHMENT_SIZE_THRESHOLD, PostMsgMetadata}; use crate::message::{Message, MessageState, Viewtype, delete_msgs, markseen_msgs}; @@ -253,6 +254,49 @@ async fn test_lost_pre_msg() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_pre_msg_mdn() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + alice + .set_config_bool(Config::PopSentMsgFromHead, true) + .await?; + let bob = &tcm.bob().await; + let alice_chat_id = alice.create_group_with_members("", &[bob]).await; + + let file_bytes = include_bytes!("../../../test-data/image/screenshot.gif"); + let mut msg = Message::new(Viewtype::Image); + msg.set_file_from_bytes(alice, "a.jpg", file_bytes, None)?; + msg.set_text("populate".to_string()); + let pre_msg = alice.send_msg(alice_chat_id, &mut msg).await; + let alice_msg_id = msg.id; + + let msg = bob.recv_msg(&pre_msg).await; + assert_eq!(msg.download_state, DownloadState::Available); + assert_eq!(msg.id.get_state(bob).await?, MessageState::InFresh); + assert_eq!(msg.text, "populate"); + msg.chat_id.accept(bob).await?; + markseen_msgs(bob, vec![msg.id]).await?; + assert_eq!(msg.id.get_state(bob).await?, MessageState::InSeen); + assert_eq!( + bob.sql.count("SELECT COUNT(*) FROM smtp_mdns", ()).await?, + 1 + ); + smtp::queue_mdn(bob).await?; + alice.recv_msg_trash(&bob.pop_sent_msg().await).await; + assert_eq!( + alice_msg_id.get_state(alice).await?, + MessageState::OutPending + ); + + let _full_msg = alice.pop_sent_msg().await; + assert_eq!( + alice_msg_id.get_state(alice).await?, + MessageState::OutMdnRcvd + ); + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_post_msg_bad_sender() -> Result<()> { let mut tcm = TestContextManager::new();