Skip to content

Commit 8120705

Browse files
igor-sirotinclaude
andauthored
test(functional): verify "sent" status while recipient offline (#7506)
* test(functional): verify "sent" status while recipient offline Add envelope.sent / outgoingStatus="sent" coverage to TestDeliveryConfirmation, with the recipient offline for the whole exchange so MVDS can never ACK. The message can then only ever reach "sent" (envelope published to a peer), never "delivered", isolating the envelope-sent path from MVDS delivery. Register the envelope.sent SignalType and use the store REST API (#7473) to confirm the envelope actually reached the store node. Replaces test_delivery_confirmation_after_recipient_offline, whose DELIVERED assertion duplicated test_delivery_confirmation_online (it only reached DELIVERED by bringing the recipient back online). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(functional): confirm store persistence with a single REST read envelope.sent already guarantees the envelope reached a peer, so the message is persisted at the store node by then — a single get_messages read suffices instead of polling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent db8f71a commit 8120705

2 files changed

Lines changed: 50 additions & 24 deletions

File tree

tests-functional/clients/signals.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
class SignalType(Enum):
1818
MESSAGES_NEW = "messages.new"
1919
MESSAGE_DELIVERED = "message.delivered"
20+
ENVELOPE_SENT = "envelope.sent"
2021
NODE_READY = "node.ready"
2122
NODE_STARTED = "node.started"
2223
NODE_LOGIN = "node.login"
Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import logging
2-
from time import sleep
2+
import time
33
from uuid import uuid4
44

55
import pytest
66

7+
from clients.logos_delivery import LogosDeliveryClient
78
from clients.signals import SignalType
89
from steps import messenger
910

@@ -13,13 +14,24 @@
1314
@pytest.mark.rpc
1415
@pytest.mark.wakuext
1516
class TestDeliveryConfirmation:
16-
"""Regression coverage for delivery confirmation (issue #7472).
17-
18-
A 1:1 message must progress to outgoing status ``delivered`` and the
19-
sender must receive a ``message.delivered`` signal, both when the
20-
recipient is online and when it comes online after a period offline.
17+
"""Regression coverage for outgoing message status (issue #7472).
18+
19+
Two distinct outgoing states are exercised:
20+
21+
* ``delivered`` — driven by an MVDS delivery ACK from the recipient. Verified
22+
with the recipient online (``test_delivery_confirmation_online``).
23+
* ``sent`` — driven by ``envelope.sent`` (the envelope reaching at least one
24+
peer, i.e. the store node), independent of MVDS. Verified with the
25+
recipient offline (``test_sent_status_while_recipient_offline``), so MVDS
26+
cannot ACK and the only way the status can advance is the envelope-sent
27+
path. This is the path that ``EnvelopesMonitor`` currently drives and that
28+
the logos-delivery Messaging API will own once integrated.
2129
"""
2230

31+
@pytest.fixture()
32+
def logos_delivery(self):
33+
return LogosDeliveryClient()
34+
2335
@pytest.fixture()
2436
def sender(self, backend_new_profile):
2537
return backend_new_profile("sender")
@@ -28,10 +40,10 @@ def sender(self, backend_new_profile):
2840
def receiver(self, backend_new_profile):
2941
return backend_new_profile("receiver")
3042

31-
def _assert_outgoing_status(self, node, message_id, expected_status="delivered"):
32-
# The status field is written just before the message.delivered signal
33-
# fires (same loop in markDeliveredMessages), so once we've seen the
34-
# signal a single read is enough — no polling needed.
43+
def _assert_outgoing_status(self, node, message_id, expected_status):
44+
# The status field is written just before the corresponding signal fires
45+
# (same loop in markDeliveredMessages / processSentMessage), so once we've
46+
# seen the signal a single read is enough — no polling needed.
3547
message = node.wakuext_service.message_by_message_id(message_id)
3648
actual_status = message.get("outgoingStatus", "")
3749
assert actual_status == expected_status, f"Message {message_id} outgoing status was '{actual_status}', expected '{expected_status}'"
@@ -51,25 +63,38 @@ def test_delivery_confirmation_online(self, sender, receiver):
5163

5264
self._assert_outgoing_status(sender, message_id, "delivered")
5365

54-
def test_delivery_confirmation_after_recipient_offline(self, sender, receiver):
66+
def test_sent_status_while_recipient_offline(self, sender, receiver, logos_delivery):
5567
messenger.make_contacts(sender, receiver)
5668

57-
message_text = f"delivery_offline_{uuid4()}"
69+
message_text = f"sent_offline_{uuid4()}"
5870

59-
# The recipient is offline when the message is sent; confirmation must
60-
# still arrive once it reconnects and the message is delivered.
71+
# Mark the start of the offline window for the store query (Unix ns, with
72+
# a small buffer for host/container clock skew).
73+
offline_start_ns = time.time_ns() - 5_000_000_000
74+
75+
# The recipient stays offline for the whole exchange, so MVDS datasync can
76+
# never ACK the message. The message can therefore only ever reach "sent"
77+
# (envelope published to a peer), never "delivered" — which isolates the
78+
# envelope.sent path from MVDS delivery. All assertions stay inside the
79+
# pause block so the recipient can't come back and ACK mid-test.
6180
with messenger.node_pause(receiver):
6281
response = sender.wakuext_service.send_one_to_one_message(receiver.public_key, message_text)
6382
message_id = response.get("messages", [])[0].get("id", "")
6483
assert message_id, "Sender did not get a message id back"
65-
sleep(30)
66-
67-
receiver.wait_for_online(timeout=60)
6884

69-
with receiver.expect_signal(SignalType.MESSAGES_NEW, pattern=message_id, timeout=120, start="beginning"):
70-
pass
71-
72-
with sender.expect_signal(SignalType.MESSAGE_DELIVERED, pattern=message_id, timeout=120, start="beginning"):
73-
pass
74-
75-
self._assert_outgoing_status(sender, message_id, "delivered")
85+
# `message_id` is only known after the send, so wait post-hoc and scan
86+
# from the beginning to avoid matching envelope.sent signals from
87+
# make_contacts.
88+
with sender.expect_signal(SignalType.ENVELOPE_SENT, pattern=message_id, timeout=120, start="beginning"):
89+
pass
90+
91+
# Exact match: "sent" (not "delivered") proves the status came from the
92+
# envelope-sent path and not from an MVDS ACK.
93+
self._assert_outgoing_status(sender, message_id, "sent")
94+
95+
# envelope.sent means the envelope already reached a peer, so it is
96+
# already persisted at the store node: a single REST read confirms it
97+
# was published to the network (not just marked locally), with MVDS
98+
# provably out of the picture (recipient offline). No polling needed.
99+
stored = logos_delivery.get_messages(start_time=offline_start_ns)
100+
assert stored, "Store node holds no messages for the offline window; envelope was not published"

0 commit comments

Comments
 (0)