Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2faa709
remove: partial downloads
Simon-Laux Oct 30, 2025
36c6604
remove partial download tests and fix issues in other tests
Simon-Laux Oct 30, 2025
da0e91e
remove remaining partial messages tests
Simon-Laux Oct 30, 2025
ea4aadc
remove download limit validation, it does not really matter in the new
Simon-Laux Oct 30, 2025
851c2fc
fix clippy
Simon-Laux Oct 30, 2025
989bcd2
ignore that `partial_download_msg_body` is dead code
Simon-Laux Oct 30, 2025
a67a145
remove test for download limit validation
Simon-Laux Oct 30, 2025
4541fbc
remove `test_download_on_demand`
Simon-Laux Oct 31, 2025
67f9cf6
remove test `test_download_limit_chat_assignment`
Simon-Laux Oct 31, 2025
2f58869
Remove superfluous parentheses.
Simon-Laux Oct 31, 2025
ead69c4
fix the issue that broke the imap fetching
Simon-Laux Oct 31, 2025
d88ca75
fix python lint errors
Simon-Laux Oct 31, 2025
7cba269
remove cffi python test`test_webxdc_download_on_demand`
Simon-Laux Nov 1, 2025
938c890
fix python lint
Simon-Laux Nov 1, 2025
0dc4560
fix rebase issue
Simon-Laux Nov 6, 2025
949c570
fix another rebase issue
Simon-Laux Nov 6, 2025
2387d22
fix lint of python test
Simon-Laux Nov 6, 2025
a4155b0
reintroduce `Config::FailOnReceivingFullMsg` but renamed it to
Simon-Laux Nov 6, 2025
cc653dc
allow exclusion of `simulate_receive_imf_error` from get_info
Simon-Laux Nov 8, 2025
8b77749
feat: send pre-message on messages with large attachments
Simon-Laux Nov 2, 2025
e044fe6
allow unused for `MAX_FETCH_MSG_SIZE`
Simon-Laux Nov 6, 2025
5d2a9df
remove todo comment
Simon-Laux Nov 6, 2025
fcdd28c
add tests for sending pre-messages
Simon-Laux Nov 8, 2025
f874a62
delimit `Chat-Full-Message-ID` with `<>` like other message ids.
Simon-Laux Nov 8, 2025
c7688f3
fix test
Simon-Laux Nov 8, 2025
7f1576d
test that Autocrypt-gossip and selfavatar should never go into
Simon-Laux Nov 8, 2025
90b61a1
fix bug that broke
Simon-Laux Nov 8, 2025
78cf68f
receive pre-mesages, start with changes to imap loop.
Simon-Laux Nov 9, 2025
f6c9547
simplify code a bit
Simon-Laux Nov 12, 2025
a3ac275
refactor: move download code from `scheduler.rs` to `download.rs`, also
Simon-Laux Nov 12, 2025
3e5a8c1
`MAX_FETCH_MSG_SIZE` is no longer unused
Simon-Laux Nov 12, 2025
03e8ec6
Parse if it is a pre-message or full-message
Simon-Laux Nov 14, 2025
4fbe2d3
start with receiving logic
Simon-Laux Nov 14, 2025
6ed7df3
get rid of `MsgId::get_by_rfc724_mid` because it was a duplicate of
Simon-Laux Nov 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions deltachat-rpc-client/tests/test_chatlist_events.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from __future__ import annotations

import base64
import os
from typing import TYPE_CHECKING

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


def test_download_on_demand(acfactory: ACFactory) -> None:
"""
Test if download on demand emits chatlist update events.
This is only needed for last message in chat, but finding that out is too expensive, so it's always emitted
"""
alice, bob = acfactory.get_online_accounts(2)

alice_contact_bob = alice.create_contact(bob, "Bob")
alice_chat_bob = alice_contact_bob.create_chat()
alice_chat_bob.send_text("hi")

alice.set_config("download_limit", "1")

msg = bob.wait_for_incoming_msg()
chat_id = msg.get_snapshot().chat_id
msg.get_snapshot().chat.accept()
bob.get_chat_by_id(chat_id).send_message(
"Hello World, this message is bigger than 5 bytes",
html=base64.b64encode(os.urandom(300000)).decode("utf-8"),
)

message = alice.wait_for_incoming_msg()
snapshot = message.get_snapshot()
assert snapshot.download_state == const.DownloadState.AVAILABLE

alice.clear_all_events()

snapshot = message.get_snapshot()
chat_id = snapshot.chat_id
alice._rpc.download_full_message(alice.id, message.id)

wait_for_chatlist_specific_item(alice, chat_id)


def get_multi_account_test_setup(acfactory: ACFactory) -> [Account, Account, Account]:
alice, bob = acfactory.get_online_accounts(2)

Expand Down
104 changes: 3 additions & 101 deletions deltachat-rpc-client/tests/test_something.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def test_receive_imf_failure(acfactory) -> None:
alice_contact_bob = alice.create_contact(bob, "Bob")
alice_chat_bob = alice_contact_bob.create_chat()

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

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


def test_reaction_to_partially_fetched_msg(acfactory, tmp_path):
"""See https://github.com/deltachat/deltachat-core-rust/issues/3688 "Partially downloaded
messages are received out of order".

If the Inbox contains X small messages followed by Y large messages followed by Z small
messages, Delta Chat first downloaded a batch of X+Z messages, and then a batch of Y messages.

This bug was discovered by @Simon-Laux while testing reactions PR #3644 and can be reproduced
with online test as follows:
- Bob enables download limit and goes offline.
- Alice sends a large message to Bob and reacts to this message with a thumbs-up.
- Bob goes online
- Bob first processes a reaction message and throws it away because there is no corresponding
message, then processes a partially downloaded message.
- As a result, Bob does not see a reaction
"""
download_limit = 300000
ac1, ac2 = acfactory.get_online_accounts(2)
ac1_addr = ac1.get_config("addr")
chat = ac1.create_chat(ac2)
ac2.set_config("download_limit", str(download_limit))
ac2.stop_io()

logging.info("sending small+large messages from ac1 to ac2")
msgs = []
msgs.append(chat.send_text("hi"))
path = tmp_path / "large"
path.write_bytes(os.urandom(download_limit + 1))
msgs.append(chat.send_file(str(path)))
for m in msgs:
m.wait_until_delivered()

logging.info("sending a reaction to the large message from ac1 to ac2")
# TODO: Find the reason of an occasional message reordering on the server (so that the reaction
# has a lower UID than the previous message). W/a is to sleep for some time to let the reaction
# have a later INTERNALDATE.
time.sleep(1.1)
react_str = "\N{THUMBS UP SIGN}"
msgs.append(msgs[-1].send_reaction(react_str))
msgs[-1].wait_until_delivered()

ac2.start_io()

logging.info("wait for ac2 to receive a reaction")
msg2 = Message(ac2, ac2.wait_for_reactions_changed().msg_id)
assert msg2.get_sender_contact().get_snapshot().address == ac1_addr
assert msg2.get_snapshot().download_state == DownloadState.AVAILABLE
reactions = msg2.get_reactions()
contacts = [Contact(ac2, int(i)) for i in reactions.reactions_by_contact]
assert len(contacts) == 1
assert contacts[0].get_snapshot().address == ac1_addr
assert list(reactions.reactions_by_contact.values())[0] == [react_str]


def test_reactions_for_a_reordering_move(acfactory, direct_imap):
"""When a batch of messages is moved from Inbox to DeltaChat folder with a single MOVE command,
their UIDs may be reordered (e.g. Gmail is known for that) which led to that messages were
Expand Down Expand Up @@ -702,50 +648,6 @@ def test_reactions_for_a_reordering_move(acfactory, direct_imap):
assert list(reactions.reactions_by_contact.values())[0] == [react_str]


@pytest.mark.parametrize("n_accounts", [3, 2])
def test_download_limit_chat_assignment(acfactory, tmp_path, n_accounts):
download_limit = 300000

alice, *others = acfactory.get_online_accounts(n_accounts)
bob = others[0]

alice_group = alice.create_group("test group")
for account in others:
chat = account.create_chat(alice)
chat.send_text("Hello Alice!")
assert alice.get_message_by_id(alice.wait_for_incoming_msg_event().msg_id).get_snapshot().text == "Hello Alice!"

contact = alice.create_contact(account)
alice_group.add_contact(contact)

if n_accounts == 2:
bob_chat_alice = bob.create_chat(alice)
bob.set_config("download_limit", str(download_limit))

alice_group.send_text("hi")
snapshot = bob.get_message_by_id(bob.wait_for_incoming_msg_event().msg_id).get_snapshot()
assert snapshot.text == "hi"
bob_group = snapshot.chat

path = tmp_path / "large"
path.write_bytes(os.urandom(download_limit + 1))

for i in range(10):
logging.info("Sending message %s", i)
alice_group.send_file(str(path))
snapshot = bob.get_message_by_id(bob.wait_for_incoming_msg_event().msg_id).get_snapshot()
assert snapshot.download_state == DownloadState.AVAILABLE
if n_accounts > 2:
assert snapshot.chat == bob_group
else:
# Group contains only Alice and Bob,
# so partially downloaded messages are
# hard to distinguish from private replies to group messages.
#
# Message may be a private reply, so we assign it to 1:1 chat with Alice.
assert snapshot.chat == bob_chat_alice


def test_markseen_contact_request(acfactory):
"""
Test that seen status is synchronized for contact request messages
Expand Down
33 changes: 0 additions & 33 deletions python/tests/test_1_online.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os
import queue
import sys
import base64
from datetime import datetime, timezone

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


def test_webxdc_download_on_demand(acfactory, data, lp):
ac1, ac2 = acfactory.get_online_accounts(2)
acfactory.introduce_each_other([ac1, ac2])
chat = acfactory.get_accepted_chat(ac1, ac2)

msg1 = Message.new_empty(ac1, "webxdc")
msg1.set_text("message1")
msg1.set_file(data.get_path("webxdc/minimal.xdc"))
msg1 = chat.send_msg(msg1)
assert msg1.is_webxdc()
assert msg1.filename

msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.is_webxdc()

lp.sec("ac2 sets download limit")
ac2.set_config("download_limit", "100")
assert msg1.send_status_update({"payload": base64.b64encode(os.urandom(300000))}, "some test data")
ac2_update = ac2._evtracker.wait_next_incoming_message()
assert ac2_update.download_state == dc.const.DC_DOWNLOAD_AVAILABLE
assert not msg2.get_status_updates()

ac2_update.download_full()
ac2._evtracker.get_matching("DC_EVENT_WEBXDC_STATUS_UPDATE")
assert msg2.get_status_updates()

# Get a event notifying that the message disappeared from the chat.
msgs_changed_event = ac2._evtracker.get_matching("DC_EVENT_MSGS_CHANGED")
assert msgs_changed_event.data1 == msg2.chat.id
assert msgs_changed_event.data2 == 0


def test_enable_mvbox_move(acfactory, lp):
(ac1,) = acfactory.get_online_accounts(1)

Expand Down
64 changes: 1 addition & 63 deletions src/calls/calls_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::*;
use crate::chat::forward_msgs;
use crate::config::Config;
use crate::constants::DC_CHAT_ID_TRASH;
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
use crate::receive_imf::receive_imf;
use crate::test_utils::{TestContext, TestContextManager};

struct CallSetup {
Expand Down Expand Up @@ -610,65 +610,3 @@ async fn test_end_text_call() -> Result<()> {

Ok(())
}

/// Tests that partially downloaded "call ended"
/// messages are not processed.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_partial_calls() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;

let seen = false;

// The messages in the test
// have no `Date` on purpose,
// so they are treated as new.
let received_call = receive_imf(
alice,
b"From: [email protected]\n\
To: [email protected]\n\
Message-ID: <[email protected]>\n\
Chat-Version: 1.0\n\
Chat-Content: call\n\
Chat-Webrtc-Room: YWFhYWFhYWFhCg==\n\
\n\
Hello, this is a call\n",
seen,
)
.await?
.unwrap();
assert_eq!(received_call.msg_ids.len(), 1);
let call_msg = Message::load_from_db(alice, received_call.msg_ids[0])
.await
.unwrap();
assert_eq!(call_msg.viewtype, Viewtype::Call);
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);

let imf_raw = b"From: [email protected]\n\
To: [email protected]\n\
Message-ID: <[email protected]>\n\
In-Reply-To: <[email protected]>\n\
Chat-Version: 1.0\n\
Chat-Content: call-ended\n\
\n\
Call ended\n";
receive_imf_from_inbox(
alice,
"[email protected]",
imf_raw,
seen,
Some(imf_raw.len().try_into().unwrap()),
)
.await?;

// The call is still not ended.
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Alerting);

// Fully downloading the message ends the call.
receive_imf_from_inbox(alice, "[email protected]", imf_raw, seen, None)
.await
.context("Failed to fully download end call message")?;
assert_eq!(call_state(alice, call_msg.id).await?, CallState::Missed);

Ok(())
}
Loading