From 0b44886b6285f63c7b450df2f452f72cda4be7bd Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 21 Nov 2022 09:06:23 -0300 Subject: [PATCH] Add a test for bug "Partially downloaded messages are received out of order" (#3688) + add Message.download_state property. --- python/src/deltachat/_build.py | 1 + python/src/deltachat/message.py | 11 ++++++ python/tests/test_1_online.py | 60 +++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/python/src/deltachat/_build.py b/python/src/deltachat/_build.py index 09795b3db..995dd34b8 100644 --- a/python/src/deltachat/_build.py +++ b/python/src/deltachat/_build.py @@ -156,6 +156,7 @@ def extract_defines(flags): | DC_KEY_GEN | DC_IMEX | DC_CONNECTIVITY + | DC_DOWNLOAD ) # End of prefix matching _[\w_]+ # Match the suffix, e.g. _RSA2048 in DC_KEY_GEN_RSA2048 ) # Close the capturing group, this contains diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index e0b4d468f..0891b46cf 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -461,6 +461,17 @@ class Message(object): """mark this message as seen.""" self.account.mark_seen_messages([self.id]) + # + # Message download state + # + @property + def download_state(self): + assert self.id > 0 + + # load message from db to get a fresh/current state + dc_msg = ffi.gc(lib.dc_get_msg(self.account._dc_context, self.id), lib.dc_msg_unref) + return lib.dc_msg_get_download_state(dc_msg) + # some code for handling DC_MSG_* view types diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 2a7f1d78b..85712af80 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -1267,6 +1267,66 @@ def test_send_and_receive_image(acfactory, lp, data): assert m == msg_in +def test_reaction_to_partially_fetched_msg(acfactory, lp, tmpdir): + """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 = 32768 + 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() + + reactions_queue = queue.Queue() + + class InPlugin: + @account_hookimpl + def ac_reactions_changed(self, message): + reactions_queue.put(message) + + ac2.add_account_plugin(InPlugin()) + + lp.sec("sending small+large messages from ac1 to ac2") + msgs = [] + msgs.append(chat.send_text("hi")) + path = tmpdir.join("large") + with open(path, "wb") as fout: + fout.write(os.urandom(download_limit + 1)) + msgs.append(chat.send_file(path.strpath)) + + lp.sec("sending a reaction to the large message from ac1 to ac2") + react_str = "\N{THUMBS UP SIGN}" + msgs.append(msgs[-1].send_reaction(react_str)) + + for m in msgs: + ac1._evtracker.wait_msg_delivered(m) + ac2.start_io() + + lp.sec("wait for ac2 to receive a reaction") + msg2 = ac2._evtracker.wait_next_reactions_changed() + assert msg2.get_sender_contact().addr == ac1_addr + assert msg2.download_state == const.DC_DOWNLOAD_AVAILABLE + assert reactions_queue.get() == msg2 + reactions = msg2.get_reactions() + contacts = reactions.get_contacts() + assert len(contacts) == 1 + assert contacts[0].addr == ac1_addr + assert reactions.get_by_contact(contacts[0]) == react_str + + def test_import_export_online_all(acfactory, tmpdir, data, lp): (ac1,) = acfactory.get_online_accounts(1)