diff --git a/src/chat.rs b/src/chat.rs index 8691e10740..8b98f51fa5 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2931,11 +2931,24 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) - msg.param.remove(Param::GuaranteeE2ee); } msg.subject.clone_from(&rendered_msg.subject); + // Sort the message to the bottom. Employ `msgs_index7` to compute `timestamp`. context .sql .execute( - "UPDATE msgs SET pre_rfc724_mid=?, subject=?, param=? WHERE id=?", + " +UPDATE msgs SET + timestamp=( + SELECT MAX(timestamp) FROM msgs WHERE + -- From `InFresh` to `OutMdnRcvd` inclusive except `OutDraft`. + state IN(10,13,16,18,20,24,26,28) AND + hidden IN(0,1) AND + chat_id=? + ), + pre_rfc724_mid=?, subject=?, param=? +WHERE id=? + ", ( + msg.chat_id, &msg.pre_rfc724_mid, &msg.subject, msg.param.to_string(), diff --git a/src/chat/chat_tests.rs b/src/chat/chat_tests.rs index d6cd5c10cf..75f8b55327 100644 --- a/src/chat/chat_tests.rs +++ b/src/chat/chat_tests.rs @@ -5027,6 +5027,31 @@ async fn test_do_not_overwrite_draft() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_outgoing_msg_after_another_from_future() -> Result<()> { + let mut tcm = TestContextManager::new(); + let t = &tcm.alice().await; + let chat_id = t.get_self_chat().await.id; + + // Simulate sending a message with clock set to the future. + SystemTime::shift(Duration::from_secs(3600)); + let msg_id = send_text_msg(t, chat_id, "test".to_string()).await?; + SystemTime::shift_back(Duration::from_secs(3600)); + + let timestamp_sent: i64 = t + .sql + .query_get_value("SELECT timestamp_sent FROM msgs WHERE id=?", (msg_id,)) + .await? + .unwrap(); + // Let's have a check here that locally sent messages have zero `timestamp_sent`, it can be a + // useful invariant. + assert_eq!(timestamp_sent, 0); + + let msg_id = send_text_msg(t, chat_id, "Fixed my clock".to_string()).await?; + assert_eq!(t.get_last_msg_in(chat_id).await.id, msg_id); + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_info_contact_id() -> Result<()> { let mut tcm = TestContextManager::new();