From c069190b687db672d6f97514b1cc1e6a38746237 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 13 Apr 2024 23:34:09 +0000 Subject: [PATCH] api: don't load trashed messages with Message::load_from_db API now pretends that trashed messages don't exist. This way callers don't have to check if loaded message belongs to trash chat. If message may be trashed by the time it is attempted to be loaded, callers should use Message::load_from_db_optional. Most changes are around receive_status_update() function because previously it relied on loading trashed status update messages immediately after adding them to the database. --- src/download.rs | 10 ++- src/ephemeral.rs | 4 +- src/imex.rs | 3 +- src/message.rs | 14 ++--- src/reaction.rs | 19 +++--- src/receive_imf.rs | 47 ++++++++++++--- src/receive_imf/tests.rs | 7 +-- src/securejoin.rs | 24 ++++---- src/sync.rs | 2 +- src/test_utils.rs | 20 ++++-- src/webxdc.rs | 127 +++++++++++++++++++++------------------ 11 files changed, 161 insertions(+), 116 deletions(-) diff --git a/src/download.rs b/src/download.rs index 7919722b4..d8df94d38 100644 --- a/src/download.rs +++ b/src/download.rs @@ -448,10 +448,9 @@ mod tests { ) .await?; assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 0); - assert!(Message::load_from_db(&bob, msg.id) + assert!(Message::load_from_db_optional(&bob, msg.id) .await? - .chat_id - .is_trash()); + .is_none()); Ok(()) } @@ -507,10 +506,9 @@ mod tests { // (usually mdn are too small for not being downloaded directly) receive_imf_from_inbox(&bob, "bar@example.org", raw, false, None, false).await?; assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 0); - assert!(Message::load_from_db(&bob, msg.id) + assert!(Message::load_from_db_optional(&bob, msg.id) .await? - .chat_id - .is_trash()); + .is_none()); Ok(()) } diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 6b62e32bf..d4951ed3e 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -1098,8 +1098,8 @@ mod tests { }) .await; - let loaded = Message::load_from_db(t, msg_id).await?; - assert_eq!(loaded.chat_id, DC_CHAT_ID_TRASH); + let loaded = Message::load_from_db_optional(t, msg_id).await?; + assert!(loaded.is_none()); // Check that the msg was deleted locally. check_msg_is_deleted(t, chat, msg_id).await; diff --git a/src/imex.rs b/src/imex.rs index 235c97f5e..3608ae862 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -1158,7 +1158,8 @@ mod tests { // Send a message that cannot be decrypted because the keys are // not synchronized yet. let sent = alice2.send_text(msg.chat_id, "Test").await; - alice.recv_msg(&sent).await; + let trashed_message = alice.recv_msg_opt(&sent).await; + assert!(trashed_message.is_none()); assert_ne!(alice.get_last_msg().await.get_text(), "Test"); // Transfer the key. diff --git a/src/message.rs b/src/message.rs index 4a4eaa621..f6ffd8bef 100644 --- a/src/message.rs +++ b/src/message.rs @@ -506,7 +506,7 @@ impl Message { " m.location_id AS location,", " c.blocked AS blocked", " FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id", - " WHERE m.id=?;" + " WHERE m.id=? AND chat_id!=3;" ), (id,), |row| { @@ -1145,13 +1145,8 @@ impl Message { pub async fn parent(&self, context: &Context) -> Result> { if let Some(in_reply_to) = &self.in_reply_to { if let Some((msg_id, _ts_sent)) = rfc724_mid_exists(context, in_reply_to).await? { - let msg = Message::load_from_db(context, msg_id).await?; - return if msg.chat_id.is_trash() { - // If message is already moved to trash chat, pretend it does not exist. - Ok(None) - } else { - Ok(Some(msg)) - }; + let msg = Message::load_from_db_optional(context, msg_id).await?; + return Ok(msg); } } Ok(None) @@ -1881,8 +1876,7 @@ pub(crate) async fn get_latest_by_rfc724_mids( ) -> Result> { for id in mids.iter().rev() { if let Some((msg_id, _)) = rfc724_mid_exists(context, id).await? { - let msg = Message::load_from_db(context, msg_id).await?; - if msg.chat_id != DC_CHAT_ID_TRASH { + if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? { return Ok(Some(msg)); } } diff --git a/src/reaction.rs b/src/reaction.rs index e3e2ec893..cd0dce152 100644 --- a/src/reaction.rs +++ b/src/reaction.rs @@ -385,7 +385,6 @@ mod tests { use crate::chat::{forward_msgs, get_chat_msgs, send_text_msg}; use crate::chatlist::Chatlist; use crate::config::Config; - use crate::constants::DC_CHAT_ID_TRASH; use crate::contact::{Contact, ContactAddress, Origin}; use crate::download::DownloadState; use crate::message::{delete_msgs, MessageState}; @@ -594,8 +593,7 @@ Here's my footer -- bob@example.net" assert_eq!(get_chat_msgs(&bob, bob_msg.chat_id).await?.len(), 2); let bob_reaction_msg = bob.pop_sent_msg().await; - let alice_reaction_msg = alice.recv_msg_opt(&bob_reaction_msg).await.unwrap(); - assert_eq!(alice_reaction_msg.chat_id, DC_CHAT_ID_TRASH); + alice.recv_msg_trash(&bob_reaction_msg).await; assert_eq!(get_chat_msgs(&alice, chat_alice.id).await?.len(), 2); let reactions = get_msg_reactions(&alice, alice_msg.sender_msg_id).await?; @@ -648,8 +646,7 @@ Here's my footer -- bob@example.net" bob_msg1.chat_id.accept(&bob).await?; send_reaction(&bob, bob_msg1.id, "👍").await?; let bob_send_reaction = bob.pop_sent_msg().await; - let alice_rcvd_reaction = alice.recv_msg(&bob_send_reaction).await; - assert!(alice_rcvd_reaction.get_timestamp() > bob_msg1.get_timestamp()); + alice.recv_msg_trash(&bob_send_reaction).await; let chatlist = Chatlist::try_load(&bob, 0, None, None).await?; let summary = chatlist.get_summary(&bob, 0, None).await?; @@ -664,7 +661,7 @@ Here's my footer -- bob@example.net" SystemTime::shift(Duration::from_secs(10)); send_reaction(&alice, alice_msg1.sender_msg_id, "🍿").await?; let alice_send_reaction = alice.pop_sent_msg().await; - bob.recv_msg(&alice_send_reaction).await; + bob.recv_msg_opt(&alice_send_reaction).await; assert_summary(&alice, "You reacted 🍿 to \"Party?\"").await; assert_summary(&bob, "ALICE reacted 🍿 to \"Party?\"").await; @@ -681,7 +678,7 @@ Here's my footer -- bob@example.net" SystemTime::shift(Duration::from_secs(10)); send_reaction(&alice, alice_msg1.sender_msg_id, "🤘").await?; let alice_send_reaction = alice.pop_sent_msg().await; - bob.recv_msg(&alice_send_reaction).await; + bob.recv_msg_opt(&alice_send_reaction).await; assert_summary(&alice, "You reacted 🤘 to \"Party?\"").await; assert_summary(&bob, "ALICE reacted 🤘 to \"Party?\"").await; @@ -690,7 +687,7 @@ Here's my footer -- bob@example.net" SystemTime::shift(Duration::from_secs(10)); send_reaction(&alice, alice_msg1.sender_msg_id, "").await?; let alice_remove_reaction = alice.pop_sent_msg().await; - bob.recv_msg(&alice_remove_reaction).await; + bob.recv_msg_opt(&alice_remove_reaction).await; assert_summary(&alice, "kewl").await; assert_summary(&bob, "kewl").await; @@ -807,7 +804,7 @@ Here's my footer -- bob@example.net" let bob_reaction_msg = bob.pop_sent_msg().await; // Alice receives a reaction. - alice.recv_msg_opt(&bob_reaction_msg).await.unwrap(); + alice.recv_msg_trash(&bob_reaction_msg).await; let reactions = get_msg_reactions(&alice, alice_msg_id).await?; assert_eq!(reactions.to_string(), "👍1"); @@ -859,7 +856,7 @@ Here's my footer -- bob@example.net" { send_reaction(&alice2, alice2_msg.id, "👍").await?; let msg = alice2.pop_sent_msg().await; - alice1.recv_msg(&msg).await; + alice1.recv_msg_trash(&msg).await; } // Check that the status is still the same. @@ -881,7 +878,7 @@ Here's my footer -- bob@example.net" let alice1_msg = alice1.recv_msg(&alice0.pop_sent_msg().await).await; send_reaction(&alice0, alice0_msg_id, "👀").await?; - alice1.recv_msg(&alice0.pop_sent_msg().await).await; + alice1.recv_msg_trash(&alice0.pop_sent_msg().await).await; expect_reactions_changed_event(&alice0, chat_id, alice0_msg_id, ContactId::SELF).await?; expect_reactions_changed_event(&alice1, alice1_msg.chat_id, alice1_msg.id, ContactId::SELF) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index ac1b5e4c2..512302602 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -476,11 +476,46 @@ pub(crate) async fn receive_imf_inner( } if let Some(ref status_update) = mime_parser.webxdc_status_update { - if let Err(err) = context - .receive_status_update(from_id, insert_msg_id, status_update) - .await + let can_info_msg; + let instance = if mime_parser + .parts + .first() + .filter(|part| part.typ == Viewtype::Webxdc) + .is_some() { - warn!(context, "receive_imf cannot update status: {err:#}."); + can_info_msg = false; + Some(Message::load_from_db(context, insert_msg_id).await?) + } else if let Some(field) = mime_parser.get_header(HeaderDef::InReplyTo) { + if let Some(instance) = get_rfc724_mid_in_list(context, field).await? { + can_info_msg = instance.download_state() == DownloadState::Done; + Some(instance) + } else { + can_info_msg = false; + None + } + } else { + can_info_msg = false; + None + }; + + if let Some(instance) = instance { + if let Err(err) = context + .receive_status_update( + from_id, + &instance, + received_msg.sort_timestamp, + can_info_msg, + status_update, + ) + .await + { + warn!(context, "receive_imf cannot update status: {err:#}."); + } + } else { + warn!( + context, + "Received webxdc update, but cannot assign it to message." + ); } } @@ -2694,8 +2729,6 @@ async fn mark_recipients_as_verified( /// Returns the last message referenced from `References` header if it is in the database. /// /// For Delta Chat messages it is the last message in the chat of the sender. -/// -/// Note that the returned message may be trashed. async fn get_previous_message( context: &Context, mime_parser: &MimeMessage, @@ -2703,7 +2736,7 @@ async fn get_previous_message( if let Some(field) = mime_parser.get_header(HeaderDef::References) { if let Some(rfc724mid) = parse_message_ids(field).last() { if let Some((msg_id, _)) = rfc724_mid_exists(context, rfc724mid).await? { - return Ok(Some(Message::load_from_db(context, msg_id).await?)); + return Message::load_from_db_optional(context, msg_id).await; } } } diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index 8ea32a2a6..f58d3f76b 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -4014,8 +4014,7 @@ async fn test_member_left_does_not_create_chat() -> Result<()> { // which some members simply deleted and some members left, // recreating the chat for others. remove_contact_from_chat(&alice, alice_chat_id, ContactId::SELF).await?; - let bob_chat_id = bob.recv_msg(&alice.pop_sent_msg().await).await.chat_id; - assert!(bob_chat_id.is_trash()); + bob.recv_msg_trash(&alice.pop_sent_msg().await).await; Ok(()) } @@ -4365,8 +4364,8 @@ async fn test_forged_from() -> Result<()> { .payload .replace("bob@example.net", "notbob@example.net"); - let msg = alice.recv_msg(&sent_msg).await; - assert!(msg.chat_id.is_trash()); + let msg = alice.recv_msg_opt(&sent_msg).await; + assert!(msg.is_none()); Ok(()) } diff --git a/src/securejoin.rs b/src/securejoin.rs index 0f1a7483d..35a380100 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -833,7 +833,7 @@ mod tests { assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some()); // Step 3: Alice receives vc-request, sends vc-auth-required - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; assert_eq!( Chatlist::try_load(&alice, 0, None, None) .await @@ -851,7 +851,7 @@ mod tests { ); // Step 4: Bob receives vc-auth-required, sends vc-request-with-auth - bob.recv_msg(&sent).await; + bob.recv_msg_trash(&sent).await; // Check Bob emitted the JoinerProgress event. let event = bob @@ -933,7 +933,7 @@ mod tests { } // Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; assert_eq!(contact_bob.is_verified(&alice.ctx).await.unwrap(), true); // exactly one one-to-one chat should be visible for both now @@ -982,7 +982,7 @@ mod tests { assert_eq!(contact_bob.is_verified(&bob.ctx).await.unwrap(), false); // Step 7: Bob receives vc-contact-confirm - bob.recv_msg(&sent).await; + bob.recv_msg_trash(&sent).await; assert_eq!(contact_alice.is_verified(&bob.ctx).await.unwrap(), true); // Check Bob got the verified message in his 1:1 chat. @@ -1083,7 +1083,7 @@ mod tests { assert_eq!(contact_bob.is_verified(&alice.ctx).await?, false); // Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; assert_eq!(contact_bob.is_verified(&alice.ctx).await?, true); let sent = alice.pop_sent_msg().await; @@ -1104,7 +1104,7 @@ mod tests { assert_eq!(contact_bob.is_verified(&bob.ctx).await?, false); // Step 7: Bob receives vc-contact-confirm - bob.recv_msg(&sent).await; + bob.recv_msg_trash(&sent).await; assert_eq!(contact_alice.is_verified(&bob.ctx).await?, true); Ok(()) @@ -1182,7 +1182,7 @@ mod tests { assert!(msg.get_header(HeaderDef::SecureJoinGroup).is_none()); // Step 3: Alice receives vg-request, sends vg-auth-required - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; let sent = alice.pop_sent_msg().await; let msg = bob.parse_msg(&sent).await; @@ -1193,7 +1193,7 @@ mod tests { ); // Step 4: Bob receives vg-auth-required, sends vg-request-with-auth - bob.recv_msg(&sent).await; + bob.recv_msg_trash(&sent).await; let sent = bob.pop_sent_msg().await; // Check Bob emitted the JoinerProgress event. @@ -1240,7 +1240,7 @@ mod tests { assert_eq!(contact_bob.is_verified(&alice.ctx).await?, false); // Step 5+6: Alice receives vg-request-with-auth, sends vg-member-added - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; assert_eq!(contact_bob.is_verified(&alice.ctx).await?, true); let sent = alice.pop_sent_msg().await; @@ -1388,15 +1388,15 @@ First thread."#; // vc-request let sent = bob.pop_sent_msg().await; - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; // vc-auth-required let sent = alice.pop_sent_msg().await; - bob.recv_msg(&sent).await; + bob.recv_msg_trash(&sent).await; // vc-request-with-auth let sent = bob.pop_sent_msg().await; - alice.recv_msg(&sent).await; + alice.recv_msg_trash(&sent).await; // Alice has Bob verified now. let contact_bob_id = diff --git a/src/sync.rs b/src/sync.rs index 7cc539a28..01d0e3eb1 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -571,7 +571,7 @@ mod tests { let sent_msg = alice.pop_sent_msg().await; let alice2 = TestContext::new_alice().await; alice2.set_config_bool(Config::SyncMsgs, true).await?; - alice2.recv_msg(&sent_msg).await; + alice2.recv_msg_trash(&sent_msg).await; assert!(token::exists(&alice2, token::Namespace::Auth, "testtoken").await?); assert_eq!(Chatlist::try_load(&alice2, 0, None, None).await?.len(), 0); diff --git a/src/test_utils.rs b/src/test_utils.rs index 900fd48dd..4354976cf 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -27,8 +27,7 @@ use crate::chat::{ }; use crate::chatlist::Chatlist; use crate::config::Config; -use crate::constants::DC_GCL_NO_SPECIALS; -use crate::constants::{Blocked, Chattype}; +use crate::constants::{Blocked, Chattype, DC_CHAT_ID_TRASH, DC_GCL_NO_SPECIALS}; use crate::contact::{Contact, ContactAddress, ContactId, Modifier, Origin}; use crate::context::Context; use crate::e2ee::EncryptHelper; @@ -179,9 +178,9 @@ impl TestContextManager { loop { if let Some(sent) = scanner.pop_sent_msg_opt(Duration::ZERO).await { - scanned.recv_msg(&sent).await; + scanned.recv_msg_opt(&sent).await; } else if let Some(sent) = scanned.pop_sent_msg_opt(Duration::ZERO).await { - scanner.recv_msg(&sent).await; + scanner.recv_msg_opt(&sent).await; } else { break; } @@ -537,6 +536,16 @@ impl TestContext { receive_imf(self, msg.payload().as_bytes(), false) .await .unwrap() + .filter(|msg| msg.chat_id != DC_CHAT_ID_TRASH) + } + + /// Recevies a message and asserts that it goes to trash chat. + pub async fn recv_msg_trash(&self, msg: &SentMessage<'_>) { + let received = receive_imf(self, msg.payload().as_bytes(), false) + .await + .unwrap() + .unwrap(); + assert_eq!(received.chat_id, DC_CHAT_ID_TRASH); } /// Gets the most recent message of a chat. @@ -1069,7 +1078,8 @@ pub(crate) async fn mark_as_verified(this: &TestContext, other: &TestContext) { /// alice0's side that implies sending a sync message. pub(crate) async fn sync(alice0: &TestContext, alice1: &TestContext) { let sync_msg = alice0.pop_sent_msg().await; - alice1.recv_msg(&sync_msg).await; + let no_msg = alice1.recv_msg_opt(&sync_msg).await; + assert!(no_msg.is_none()); } /// Pretty-print an event to stdout diff --git a/src/webxdc.rs b/src/webxdc.rs index fc5f36b57..8fe7cf952 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -30,7 +30,6 @@ use crate::chat::{self, Chat}; use crate::constants::Chattype; use crate::contact::ContactId; use crate::context::Context; -use crate::download::DownloadState; use crate::events::EventType; use crate::message::{Message, MessageState, MsgId, Viewtype}; use crate::mimefactory::wrapped_base64_encode; @@ -285,7 +284,7 @@ impl Context { /// writes it to the database and handles events, info-messages, document name and summary. async fn create_status_update_record( &self, - instance: &mut Message, + instance: &Message, status_update_item: StatusUpdateItem, timestamp: i64, can_info_msg: bool, @@ -329,6 +328,7 @@ impl Context { let mut param_changed = false; + let mut instance = instance.clone(); if let Some(ref document) = status_update_item.document { if instance .param @@ -446,7 +446,7 @@ impl Context { mut status_update: StatusUpdateItem, descr: &str, ) -> Result<()> { - let mut instance = Message::load_from_db(self, instance_msg_id) + let instance = Message::load_from_db(self, instance_msg_id) .await .with_context(|| { format!("Failed to load message {instance_msg_id} from the database") @@ -474,7 +474,7 @@ impl Context { status_update.uid = Some(create_id()); let status_update_serial: StatusUpdateSerial = self .create_status_update_record( - &mut instance, + &instance, status_update, create_smeared_timestamp(self), send_now, @@ -569,33 +569,22 @@ impl Context { /// Receives status updates from receive_imf to the database /// and sends out an event. /// - /// `from_id` is the sender + /// `instance` is a webxdc instance. /// - /// `msg_id` may be an instance (in case there are initial status updates) - /// or a reply to an instance (for all other updates). + /// `from_id` is the sender. + /// + /// `timestamp` is the timestamp of the update. /// /// `json` is an array containing one or more update items as created by send_webxdc_status_update(), /// the array is parsed using serde, the single payloads are used as is. pub(crate) async fn receive_status_update( &self, from_id: ContactId, - msg_id: MsgId, + instance: &Message, + timestamp: i64, + can_info_msg: bool, json: &str, ) -> Result<()> { - let msg = Message::load_from_db(self, msg_id).await?; - let (timestamp, mut instance, can_info_msg) = if msg.viewtype == Viewtype::Webxdc { - (msg.timestamp_sort, msg, false) - } else if let Some(parent) = msg.parent(self).await? { - if parent.viewtype == Viewtype::Webxdc { - (msg.timestamp_sort, parent, true) - } else if parent.download_state() != DownloadState::Done { - (msg.timestamp_sort, parent, false) - } else { - bail!("receive_status_update: message is not the child of a webxdc message.") - } - } else { - bail!("receive_status_update: status message has no parent.") - }; let chat_id = instance.chat_id; if from_id != ContactId::SELF && !chat::is_contact_in_chat(self, chat_id, from_id).await? { @@ -612,7 +601,7 @@ impl Context { let updates: StatusUpdates = serde_json::from_str(json)?; for update_item in updates.updates { self.create_status_update_record( - &mut instance, + instance, update_item, timestamp, can_info_msg, @@ -866,9 +855,10 @@ mod tests { use crate::chatlist::Chatlist; use crate::config::Config; use crate::contact::Contact; + use crate::download::DownloadState; use crate::ephemeral; use crate::receive_imf::{receive_imf, receive_imf_from_inbox}; - use crate::test_utils::TestContext; + use crate::test_utils::{TestContext, TestContextManager}; use crate::tools::{self, SystemTime}; use crate::{message, sql}; @@ -1053,8 +1043,10 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_webxdc_instance_and_info() -> Result<()> { + let mut tcm = TestContextManager::new(); + // Alice uses webxdc in a group - let alice = TestContext::new_alice().await; + let alice = tcm.alice().await; alice.set_config_bool(Config::BccSelf, false).await?; let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?; let alice_instance = send_webxdc_instance(&alice, alice_grp).await?; @@ -1069,7 +1061,7 @@ mod tests { assert_eq!(alice_grp.get_msg_cnt(&alice).await?, 2); assert!(alice.get_last_msg_in(alice_grp).await.is_info()); - // Alice adds Bob and resend already used webxdc + // Alice adds Bob and resends already used webxdc add_contact_to_chat( &alice, alice_grp, @@ -1081,7 +1073,7 @@ mod tests { let sent1 = alice.pop_sent_msg().await; // Bob received webxdc, legacy info-messages updates are received but not added to the chat - let bob = TestContext::new_bob().await; + let bob = tcm.bob().await; let bob_instance = bob.recv_msg(&sent1).await; assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); assert!(!bob_instance.is_info()); @@ -1204,7 +1196,7 @@ mod tests { .await?; let bob_instance = bob.get_last_msg().await; bob_instance.chat_id.accept(&bob).await?; - bob.recv_msg(&sent2).await; + bob.recv_msg_trash(&sent2).await; assert_eq!(bob_instance.download_state, DownloadState::Available); // Bob downloads instance, updates should be assigned correctly @@ -1239,9 +1231,12 @@ mod tests { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; let instance = send_webxdc_instance(&t, chat_id).await?; + let now = tools::time(); t.receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updates":[{"payload":1}]}"#, ) .await?; @@ -1269,9 +1264,12 @@ mod tests { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; let instance = send_webxdc_instance(&t, chat_id).await?; + let now = tools::time(); t.receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updates":[{"payload":1}, {"payload":2}]}"#, ) .await?; @@ -1336,7 +1334,7 @@ mod tests { async fn test_create_status_update_record() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; - let mut instance = send_webxdc_instance(&t, chat_id).await?; + let instance = send_webxdc_instance(&t, chat_id).await?; assert_eq!( t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0)) @@ -1346,7 +1344,7 @@ mod tests { let update_id1 = t .create_status_update_record( - &mut instance, + &instance, StatusUpdateItem { payload: json!({"foo": "bar"}), info: None, @@ -1370,7 +1368,7 @@ mod tests { // Whatever the payload is, update should be ignored just because ID is duplicate. let update_id1_duplicate = t .create_status_update_record( - &mut instance, + &instance, StatusUpdateItem { payload: json!({"nothing": "this should be ignored"}), info: None, @@ -1403,7 +1401,7 @@ mod tests { let update_id2 = t .create_status_update_record( - &mut instance, + &instance, StatusUpdateItem { payload: json!({"foo2": "bar2"}), info: None, @@ -1422,7 +1420,7 @@ mod tests { r#"[{"payload":{"foo2":"bar2"},"serial":3,"max_serial":3}]"# ); t.create_status_update_record( - &mut instance, + &instance, StatusUpdateItem { payload: Value::Bool(true), info: None, @@ -1463,15 +1461,18 @@ mod tests { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; let instance = send_webxdc_instance(&t, chat_id).await?; + let now = tools::time(); assert!(t - .receive_status_update(ContactId::SELF, instance.id, r#"foo: bar"#) + .receive_status_update(ContactId::SELF, &instance, now, true, r#"foo: bar"#) .await .is_err()); // no json assert!(t .receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updada":[{"payload":{"foo":"bar"}}]}"# ) .await @@ -1479,7 +1480,9 @@ mod tests { assert!(t .receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updates":[{"foo":"bar"}]}"# ) .await @@ -1487,7 +1490,9 @@ mod tests { assert!(t .receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updates":{"payload":{"foo":"bar"}}}"# ) .await @@ -1495,7 +1500,9 @@ mod tests { t.receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#"{"updates":[{"payload":{"foo":"bar"}, "someTrash": "definitely TrAsH"}]}"#, ) .await?; @@ -1507,7 +1514,9 @@ mod tests { t.receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#" {"updates": [ {"payload" :42} , {"payload": 23} ] } "#, ) .await?; @@ -1521,7 +1530,9 @@ mod tests { t.receive_status_update( ContactId::SELF, - instance.id, + &instance, + now, + true, r#" {"updates": [ {"payload" :"ok", "future_item": "test"} ], "from": "future" } "#, ) .await?; // ignore members that may be added in the future @@ -1619,7 +1630,8 @@ mod tests { assert_eq!(bob_instance.viewtype, Viewtype::Webxdc); assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1); - bob.recv_msg(sent2).await; + let bob_received_update = bob.recv_msg_opt(sent2).await; + assert!(bob_received_update.is_none()); expect_status_update_event(&bob, bob_instance.id).await?; assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 1); @@ -1632,7 +1644,7 @@ mod tests { // Alice has a second device and also receives messages there let alice2 = TestContext::new_alice().await; alice2.recv_msg(sent1).await; - alice2.recv_msg(sent2).await; + alice2.recv_msg_trash(sent2).await; let alice2_instance = alice2.get_last_msg().await; let alice2_chat_id = alice2_instance.chat_id; assert_eq!(alice2_instance.viewtype, Viewtype::Webxdc); @@ -2166,8 +2178,8 @@ sth_for_the = "future""# // Bob receives the updates let bob_instance = bob.recv_msg(sent_instance).await; - bob.recv_msg(sent_update1).await; - bob.recv_msg(sent_update2).await; + bob.recv_msg_trash(sent_update1).await; + bob.recv_msg_trash(sent_update2).await; let info = Message::load_from_db(&bob, bob_instance.id) .await? .get_webxdc_info(&bob) @@ -2177,8 +2189,8 @@ sth_for_the = "future""# // Alice has a second device and also receives the updates there let alice2 = TestContext::new_alice().await; let alice2_instance = alice2.recv_msg(sent_instance).await; - alice2.recv_msg(sent_update1).await; - alice2.recv_msg(sent_update2).await; + alice2.recv_msg_trash(sent_update1).await; + alice2.recv_msg_trash(sent_update2).await; let info = Message::load_from_db(&alice2, alice2_instance.id) .await? .get_webxdc_info(&alice2) @@ -2219,7 +2231,7 @@ sth_for_the = "future""# // Bob receives the updates let bob_instance = bob.recv_msg(sent_instance).await; - bob.recv_msg(sent_update1).await; + bob.recv_msg_trash(sent_update1).await; let info = Message::load_from_db(&bob, bob_instance.id) .await? .get_webxdc_info(&bob) @@ -2271,7 +2283,7 @@ sth_for_the = "future""# // Bob receives all messages let bob_instance = bob.recv_msg(sent1).await; let bob_chat_id = bob_instance.chat_id; - bob.recv_msg(sent2).await; + bob.recv_msg_trash(sent2).await; assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2); let info_msg = bob.get_last_msg().await; assert!(info_msg.is_info()); @@ -2290,7 +2302,7 @@ sth_for_the = "future""# let alice2 = TestContext::new_alice().await; let alice2_instance = alice2.recv_msg(sent1).await; let alice2_chat_id = alice2_instance.chat_id; - alice2.recv_msg(sent2).await; + alice2.recv_msg_trash(sent2).await; assert_eq!(alice2_chat_id.get_msg_cnt(&alice2).await?, 2); let info_msg = alice2.get_last_msg().await; assert!(info_msg.is_info()); @@ -2340,9 +2352,9 @@ sth_for_the = "future""# // When Bob receives the messages, they should be cleaned up as well let bob_instance = bob.recv_msg(sent1).await; let bob_chat_id = bob_instance.chat_id; - bob.recv_msg(sent2).await; + bob.recv_msg_trash(sent2).await; assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2); - bob.recv_msg(sent3).await; + bob.recv_msg_trash(sent3).await; assert_eq!(bob_chat_id.get_msg_cnt(&bob).await?, 2); let info_msg = bob.get_last_msg().await; assert_eq!(info_msg.get_text(), "i2"); @@ -2400,7 +2412,7 @@ sth_for_the = "future""# // Bob receives instance+update let bob_instance = bob.recv_msg(sent1).await; - bob.recv_msg(sent2).await; + bob.recv_msg_trash(sent2).await; assert!(bob_instance.get_showpadlock()); // Bob adds Claire with unknown key, update to Alice+Claire cannot be encrypted @@ -2530,7 +2542,7 @@ sth_for_the = "future""# .await?; bob.flush_status_updates().await?; let msg = bob.pop_sent_msg().await; - alice.recv_msg(&msg).await; + alice.recv_msg_trash(&msg).await; alice .get_webxdc_status_updates(alice_instance.id, StatusUpdateSerial(0)) .await @@ -2648,7 +2660,8 @@ sth_for_the = "future""# ) .await?; alice.flush_status_updates().await?; - bob.recv_msg(&alice.pop_sent_msg().await).await; + let received_update = bob.recv_msg_opt(&alice.pop_sent_msg().await).await; + assert!(received_update.is_none()); assert_eq!( bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) @@ -2683,7 +2696,7 @@ sth_for_the = "future""# .set(Param::Arg, r#"{"updates":[{"payload":{"foo":"bar"}}]}"#); update.set_quote(alice, Some(&alice_instance)).await?; let sent_msg = alice.send_msg(alice_chat.id, &mut update).await; - bob.recv_msg(&sent_msg).await; + bob.recv_msg_trash(&sent_msg).await; assert_eq!( bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0)) .await?,