Skip to content

Commit fa24dee

Browse files
authored
remove: partial downloads (remove creation of the stub messages) (#7373)
part of #7367
1 parent f01972d commit fa24dee

File tree

22 files changed

+159
-1312
lines changed

22 files changed

+159
-1312
lines changed

deltachat-ffi/deltachat.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7241,13 +7241,7 @@ void dc_event_unref(dc_event_t* event);
72417241
/// `%1$s` will be replaced by the percentage used
72427242
#define DC_STR_QUOTA_EXCEEDING_MSG_BODY 98
72437243

7244-
/// "%1$s message"
7245-
///
7246-
/// Used as the message body when a message
7247-
/// was not yet downloaded completely
7248-
/// (dc_msg_get_download_state() is e.g. @ref DC_DOWNLOAD_AVAILABLE).
7249-
///
7250-
/// `%1$s` will be replaced by human-readable size (e.g. "1.2 MiB").
7244+
/// @deprecated Deprecated 2025-11-12, this string is no longer needed.
72517245
#define DC_STR_PARTIAL_DOWNLOAD_MSG_BODY 99
72527246

72537247
/// "Multi Device Synchronization"

deltachat-rpc-client/tests/test_chatlist_events.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from __future__ import annotations
22

3-
import base64
4-
import os
53
from typing import TYPE_CHECKING
64

75
from deltachat_rpc_client import Account, EventType, const
@@ -111,40 +109,6 @@ def test_delivery_status_failed(acfactory: ACFactory) -> None:
111109
assert failing_message.get_snapshot().state == const.MessageState.OUT_FAILED
112110

113111

114-
def test_download_on_demand(acfactory: ACFactory) -> None:
115-
"""
116-
Test if download on demand emits chatlist update events.
117-
This is only needed for last message in chat, but finding that out is too expensive, so it's always emitted
118-
"""
119-
alice, bob = acfactory.get_online_accounts(2)
120-
121-
alice_contact_bob = alice.create_contact(bob, "Bob")
122-
alice_chat_bob = alice_contact_bob.create_chat()
123-
alice_chat_bob.send_text("hi")
124-
125-
alice.set_config("download_limit", "1")
126-
127-
msg = bob.wait_for_incoming_msg()
128-
chat_id = msg.get_snapshot().chat_id
129-
msg.get_snapshot().chat.accept()
130-
bob.get_chat_by_id(chat_id).send_message(
131-
"Hello World, this message is bigger than 5 bytes",
132-
html=base64.b64encode(os.urandom(300000)).decode("utf-8"),
133-
)
134-
135-
message = alice.wait_for_incoming_msg()
136-
snapshot = message.get_snapshot()
137-
assert snapshot.download_state == const.DownloadState.AVAILABLE
138-
139-
alice.clear_all_events()
140-
141-
snapshot = message.get_snapshot()
142-
chat_id = snapshot.chat_id
143-
alice._rpc.download_full_message(alice.id, message.id)
144-
145-
wait_for_chatlist_specific_item(alice, chat_id)
146-
147-
148112
def get_multi_account_test_setup(acfactory: ACFactory) -> [Account, Account, Account]:
149113
alice, bob = acfactory.get_online_accounts(2)
150114

deltachat-rpc-client/tests/test_something.py

Lines changed: 3 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ def test_receive_imf_failure(acfactory) -> None:
336336
alice_contact_bob = alice.create_contact(bob, "Bob")
337337
alice_chat_bob = alice_contact_bob.create_chat()
338338

339-
bob.set_config("fail_on_receiving_full_msg", "1")
339+
bob.set_config("simulate_receive_imf_error", "1")
340340
alice_chat_bob.send_text("Hello!")
341341
event = bob.wait_for_event(EventType.MSGS_CHANGED)
342342
assert event.chat_id == bob.get_device_chat().id
@@ -345,12 +345,12 @@ def test_receive_imf_failure(acfactory) -> None:
345345
snapshot = message.get_snapshot()
346346
assert (
347347
snapshot.text == "❌ Failed to receive a message:"
348-
" Condition failed: `!context.get_config_bool(Config::FailOnReceivingFullMsg).await?`."
348+
" Condition failed: `!context.get_config_bool(Config::SimulateReceiveImfError).await?`."
349349
" Please report this bug to [email protected] or https://support.delta.chat/."
350350
)
351351

352352
# The failed message doesn't break the IMAP loop.
353-
bob.set_config("fail_on_receiving_full_msg", "0")
353+
bob.set_config("simulate_receive_imf_error", "0")
354354
alice_chat_bob.send_text("Hello again!")
355355
event = bob.wait_for_incoming_msg_event()
356356
msg_id = event.msg_id
@@ -604,60 +604,6 @@ def test_mdn_doesnt_break_autocrypt(acfactory) -> None:
604604
assert snapshot.show_padlock
605605

606606

607-
def test_reaction_to_partially_fetched_msg(acfactory, tmp_path):
608-
"""See https://github.com/deltachat/deltachat-core-rust/issues/3688 "Partially downloaded
609-
messages are received out of order".
610-
611-
If the Inbox contains X small messages followed by Y large messages followed by Z small
612-
messages, Delta Chat first downloaded a batch of X+Z messages, and then a batch of Y messages.
613-
614-
This bug was discovered by @Simon-Laux while testing reactions PR #3644 and can be reproduced
615-
with online test as follows:
616-
- Bob enables download limit and goes offline.
617-
- Alice sends a large message to Bob and reacts to this message with a thumbs-up.
618-
- Bob goes online
619-
- Bob first processes a reaction message and throws it away because there is no corresponding
620-
message, then processes a partially downloaded message.
621-
- As a result, Bob does not see a reaction
622-
"""
623-
download_limit = 300000
624-
ac1, ac2 = acfactory.get_online_accounts(2)
625-
ac1_addr = ac1.get_config("addr")
626-
chat = ac1.create_chat(ac2)
627-
ac2.set_config("download_limit", str(download_limit))
628-
ac2.stop_io()
629-
630-
logging.info("sending small+large messages from ac1 to ac2")
631-
msgs = []
632-
msgs.append(chat.send_text("hi"))
633-
path = tmp_path / "large"
634-
path.write_bytes(os.urandom(download_limit + 1))
635-
msgs.append(chat.send_file(str(path)))
636-
for m in msgs:
637-
m.wait_until_delivered()
638-
639-
logging.info("sending a reaction to the large message from ac1 to ac2")
640-
# TODO: Find the reason of an occasional message reordering on the server (so that the reaction
641-
# has a lower UID than the previous message). W/a is to sleep for some time to let the reaction
642-
# have a later INTERNALDATE.
643-
time.sleep(1.1)
644-
react_str = "\N{THUMBS UP SIGN}"
645-
msgs.append(msgs[-1].send_reaction(react_str))
646-
msgs[-1].wait_until_delivered()
647-
648-
ac2.start_io()
649-
650-
logging.info("wait for ac2 to receive a reaction")
651-
msg2 = Message(ac2, ac2.wait_for_reactions_changed().msg_id)
652-
assert msg2.get_sender_contact().get_snapshot().address == ac1_addr
653-
assert msg2.get_snapshot().download_state == DownloadState.AVAILABLE
654-
reactions = msg2.get_reactions()
655-
contacts = [Contact(ac2, int(i)) for i in reactions.reactions_by_contact]
656-
assert len(contacts) == 1
657-
assert contacts[0].get_snapshot().address == ac1_addr
658-
assert list(reactions.reactions_by_contact.values())[0] == [react_str]
659-
660-
661607
def test_reactions_for_a_reordering_move(acfactory, direct_imap):
662608
"""When a batch of messages is moved from Inbox to DeltaChat folder with a single MOVE command,
663609
their UIDs may be reordered (e.g. Gmail is known for that) which led to that messages were
@@ -702,50 +648,6 @@ def test_reactions_for_a_reordering_move(acfactory, direct_imap):
702648
assert list(reactions.reactions_by_contact.values())[0] == [react_str]
703649

704650

705-
@pytest.mark.parametrize("n_accounts", [3, 2])
706-
def test_download_limit_chat_assignment(acfactory, tmp_path, n_accounts):
707-
download_limit = 300000
708-
709-
alice, *others = acfactory.get_online_accounts(n_accounts)
710-
bob = others[0]
711-
712-
alice_group = alice.create_group("test group")
713-
for account in others:
714-
chat = account.create_chat(alice)
715-
chat.send_text("Hello Alice!")
716-
assert alice.get_message_by_id(alice.wait_for_incoming_msg_event().msg_id).get_snapshot().text == "Hello Alice!"
717-
718-
contact = alice.create_contact(account)
719-
alice_group.add_contact(contact)
720-
721-
if n_accounts == 2:
722-
bob_chat_alice = bob.create_chat(alice)
723-
bob.set_config("download_limit", str(download_limit))
724-
725-
alice_group.send_text("hi")
726-
snapshot = bob.get_message_by_id(bob.wait_for_incoming_msg_event().msg_id).get_snapshot()
727-
assert snapshot.text == "hi"
728-
bob_group = snapshot.chat
729-
730-
path = tmp_path / "large"
731-
path.write_bytes(os.urandom(download_limit + 1))
732-
733-
for i in range(10):
734-
logging.info("Sending message %s", i)
735-
alice_group.send_file(str(path))
736-
snapshot = bob.get_message_by_id(bob.wait_for_incoming_msg_event().msg_id).get_snapshot()
737-
assert snapshot.download_state == DownloadState.AVAILABLE
738-
if n_accounts > 2:
739-
assert snapshot.chat == bob_group
740-
else:
741-
# Group contains only Alice and Bob,
742-
# so partially downloaded messages are
743-
# hard to distinguish from private replies to group messages.
744-
#
745-
# Message may be a private reply, so we assign it to 1:1 chat with Alice.
746-
assert snapshot.chat == bob_chat_alice
747-
748-
749651
def test_markseen_contact_request(acfactory):
750652
"""
751653
Test that seen status is synchronized for contact request messages

python/tests/test_1_online.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22
import queue
33
import sys
4-
import base64
54
from datetime import datetime, timezone
65

76
import pytest
@@ -222,38 +221,6 @@ def test_webxdc_huge_update(acfactory, data, lp):
222221
assert update["payload"] == payload
223222

224223

225-
def test_webxdc_download_on_demand(acfactory, data, lp):
226-
ac1, ac2 = acfactory.get_online_accounts(2)
227-
acfactory.introduce_each_other([ac1, ac2])
228-
chat = acfactory.get_accepted_chat(ac1, ac2)
229-
230-
msg1 = Message.new_empty(ac1, "webxdc")
231-
msg1.set_text("message1")
232-
msg1.set_file(data.get_path("webxdc/minimal.xdc"))
233-
msg1 = chat.send_msg(msg1)
234-
assert msg1.is_webxdc()
235-
assert msg1.filename
236-
237-
msg2 = ac2._evtracker.wait_next_incoming_message()
238-
assert msg2.is_webxdc()
239-
240-
lp.sec("ac2 sets download limit")
241-
ac2.set_config("download_limit", "100")
242-
assert msg1.send_status_update({"payload": base64.b64encode(os.urandom(300000))}, "some test data")
243-
ac2_update = ac2._evtracker.wait_next_incoming_message()
244-
assert ac2_update.download_state == dc.const.DC_DOWNLOAD_AVAILABLE
245-
assert not msg2.get_status_updates()
246-
247-
ac2_update.download_full()
248-
ac2._evtracker.get_matching("DC_EVENT_WEBXDC_STATUS_UPDATE")
249-
assert msg2.get_status_updates()
250-
251-
# Get a event notifying that the message disappeared from the chat.
252-
msgs_changed_event = ac2._evtracker.get_matching("DC_EVENT_MSGS_CHANGED")
253-
assert msgs_changed_event.data1 == msg2.chat.id
254-
assert msgs_changed_event.data2 == 0
255-
256-
257224
def test_enable_mvbox_move(acfactory, lp):
258225
(ac1,) = acfactory.get_online_accounts(1)
259226

src/calls/calls_tests.rs

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::*;
22
use crate::chat::forward_msgs;
33
use crate::config::Config;
44
use crate::constants::DC_CHAT_ID_TRASH;
5-
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
5+
use crate::receive_imf::receive_imf;
66
use crate::test_utils::{TestContext, TestContextManager};
77

88
struct CallSetup {
@@ -610,65 +610,3 @@ async fn test_end_text_call() -> Result<()> {
610610

611611
Ok(())
612612
}
613-
614-
/// Tests that partially downloaded "call ended"
615-
/// messages are not processed.
616-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
617-
async fn test_no_partial_calls() -> Result<()> {
618-
let mut tcm = TestContextManager::new();
619-
let alice = &tcm.alice().await;
620-
621-
let seen = false;
622-
623-
// The messages in the test
624-
// have no `Date` on purpose,
625-
// so they are treated as new.
626-
let received_call = receive_imf(
627-
alice,
628-
b"From: [email protected]\n\
629-
630-
Message-ID: <[email protected]>\n\
631-
Chat-Version: 1.0\n\
632-
Chat-Content: call\n\
633-
Chat-Webrtc-Room: YWFhYWFhYWFhCg==\n\
634-
\n\
635-
Hello, this is a call\n",
636-
seen,
637-
)
638-
.await?
639-
.unwrap();
640-
assert_eq!(received_call.msg_ids.len(), 1);
641-
let call_msg = Message::load_from_db(alice, received_call.msg_ids[0])
642-
.await
643-
.unwrap();
644-
assert_eq!(call_msg.viewtype, Viewtype::Call);
645-
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);
646-
647-
let imf_raw = b"From: [email protected]\n\
648-
649-
Message-ID: <[email protected]>\n\
650-
In-Reply-To: <[email protected]>\n\
651-
Chat-Version: 1.0\n\
652-
Chat-Content: call-ended\n\
653-
\n\
654-
Call ended\n";
655-
receive_imf_from_inbox(
656-
alice,
657-
658-
imf_raw,
659-
seen,
660-
Some(imf_raw.len().try_into().unwrap()),
661-
)
662-
.await?;
663-
664-
// The call is still not ended.
665-
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);
666-
667-
// Fully downloading the message ends the call.
668-
receive_imf_from_inbox(alice, "[email protected]", imf_raw, seen, None)
669-
.await
670-
.context("Failed to fully download end call message")?;
671-
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Missed);
672-
673-
Ok(())
674-
}

src/chat/chat_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3130,7 +3130,7 @@ async fn test_broadcast_channel_protected_listid() -> Result<()> {
31303130
.await?
31313131
.grpid;
31323132

3133-
let parsed = mimeparser::MimeMessage::from_bytes(bob, sent.payload.as_bytes(), None).await?;
3133+
let parsed = mimeparser::MimeMessage::from_bytes(bob, sent.payload.as_bytes()).await?;
31343134
assert_eq!(
31353135
parsed.get_mailinglist_header().unwrap(),
31363136
format!("My Channel <{}>", alice_list_id)
@@ -3325,7 +3325,7 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {
33253325
remove_contact_from_chat(bob0, bob_chat_id, ContactId::SELF).await?;
33263326

33273327
let leave_msg = bob0.pop_sent_msg().await;
3328-
let parsed = MimeMessage::from_bytes(bob1, leave_msg.payload().as_bytes(), None).await?;
3328+
let parsed = MimeMessage::from_bytes(bob1, leave_msg.payload().as_bytes()).await?;
33293329
assert_eq!(
33303330
parsed.parts[0].msg,
33313331
stock_str::msg_group_left_remote(bob0).await

src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,8 @@ pub enum Config {
438438
/// storing the same token multiple times on the server.
439439
EncryptedDeviceToken,
440440

441-
/// Return an error from `receive_imf_inner()` for a fully downloaded message. For tests.
442-
FailOnReceivingFullMsg,
441+
/// Return an error from `receive_imf_inner()`. For tests.
442+
SimulateReceiveImfError,
443443
}
444444

445445
impl Config {

src/context/context_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ async fn test_get_info_completeness() {
297297
"encrypted_device_token",
298298
"stats_last_update",
299299
"stats_last_old_contact_id",
300+
"simulate_receive_imf_error",
300301
];
301302
let t = TestContext::new().await;
302303
let info = t.get_info().await.unwrap();

0 commit comments

Comments
 (0)