fix: keep a message read status if a failure arrives later

also simplifies tests to use a shared helper for receiving an mdn
This commit is contained in:
holger krekel
2026-09-21 23:34:40 +02:00
parent 362cc76c83
commit d680c332ed
4 changed files with 42 additions and 29 deletions

View File

@@ -1972,6 +1972,10 @@ pub(crate) async fn set_msg_failed(
msg: &mut Message,
error: &str,
) -> Result<()> {
if msg.state == MessageState::OutMdnRcvd {
info!(context, "{} was read, ignoring failure: {}", msg.id, error);
return Ok(());
}
if msg.state.can_fail() {
msg.state = MessageState::OutFailed;
warn!(context, "{} failed: {}", msg.id, error);

View File

@@ -454,6 +454,28 @@ async fn test_get_state() -> Result<()> {
Ok(())
}
/// Tests that a failure reported after a read receipt leaves the message untouched.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_msg_failed_after_mdn() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let alice_chat = alice.create_chat(bob).await;
let sent = alice.send_text(alice_chat.id, "hi").await;
let bob_msg = bob.recv_msg(&sent).await;
alice.recv_mdn(bob, &bob_msg).await?;
let mut msg = sent.load_from_db().await;
assert_eq!(msg.state, MessageState::OutMdnRcvd);
set_msg_failed(alice, &mut msg, "relay bounced").await?;
let msg = sent.load_from_db().await;
assert_eq!(msg.state, MessageState::OutMdnRcvd);
assert_eq!(msg.error(), None);
let chats = Chatlist::try_load(alice, 0, None, None).await?;
assert_eq!(chats.get_msg_id(0)?, Some(msg.id));
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_bot() -> Result<()> {
let mut tcm = TestContextManager::new();

View File

@@ -2723,20 +2723,8 @@ async fn test_read_receipts_dont_create_chats() -> Result<()> {
let chats = Chatlist::try_load(&alice, 0, None, None).await?;
assert_eq!(chats.len(), 0);
// Bob sends a read receipt.
let mdn_mimefactory = crate::mimefactory::MimeFactory::from_mdn(
&bob,
received_msg.from_id,
received_msg.rfc724_mid,
vec![],
)
.await?;
let bob_addr = bob.get_primary_self_addr().await?;
let rendered_mdn = mdn_mimefactory.render(&bob, &bob_addr).await?;
let mdn_body = rendered_mdn.message;
// Alice receives the read receipt.
receive_imf(&alice, mdn_body.as_bytes(), false).await?;
// Alice receives Bob's read receipt.
alice.recv_mdn(&bob, &received_msg).await?;
// Chat should not pop up in the chatlist.
let chats = Chatlist::try_load(&alice, 0, None, None).await?;
@@ -2759,20 +2747,8 @@ async fn test_read_receipts_dont_unmark_bots() -> Result<()> {
.await;
let received_msg = bob.get_last_msg().await;
// Bob sends a read receipt.
let mdn_mimefactory = crate::mimefactory::MimeFactory::from_mdn(
bob,
received_msg.from_id,
received_msg.rfc724_mid,
vec![],
)
.await?;
let bob_addr = bob.get_primary_self_addr().await?;
let rendered_mdn = mdn_mimefactory.render(bob, &bob_addr).await?;
let mdn_body = rendered_mdn.message;
// Alice receives the read receipt.
receive_imf(alice, mdn_body.as_bytes(), false).await?;
// Alice receives Bob's read receipt.
alice.recv_mdn(bob, &received_msg).await?;
let msg = alice.get_last_msg_in(alice_chat.id).await;
assert_eq!(msg.state, MessageState::OutMdnRcvd);
let ab_contact = alice.add_or_lookup_contact(bob).await;

View File

@@ -35,7 +35,7 @@ use crate::context::Context;
use crate::events::{Event, EventEmitter, EventType, Events};
use crate::key::{self, DcKey, self_fingerprint};
use crate::message::{Message, MessageState, MsgId};
use crate::mimefactory;
use crate::mimefactory::{self, MimeFactory};
use crate::mimeparser::{MimeMessage, SystemMessage};
use crate::pgp::SeipdVersion;
use crate::receive_imf::{ReceivedMsg, receive_imf};
@@ -850,6 +850,17 @@ ORDER BY id"
assert_eq!(received.chat_id, ChatId::TRASH);
}
/// Receives a read receipt from `reader`, who received `msg`.
pub async fn recv_mdn(&self, reader: &TestContext, msg: &Message) -> Result<()> {
let mdn = MimeFactory::from_mdn(reader, msg.from_id, msg.rfc724_mid.clone(), vec![])
.await?
.render(reader, &reader.get_primary_self_addr().await?)
.await?
.message;
receive_imf(self, mdn.as_bytes(), false).await?;
Ok(())
}
/// Gets the most recent message ID of a chat.
///
/// Panics on errors or if the most recent message is a marker.