mirror of
https://github.com/chatmail/core.git
synced 2026-04-18 05:56:31 +03:00
237 lines
8.5 KiB
Python
237 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Testing webxdc iroh connectivity
|
|
|
|
If you want to debug iroh at rust-trace/log level set
|
|
|
|
RUST_LOG=iroh_net=trace,iroh_gossip=trace
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import threading
|
|
import time
|
|
|
|
import pytest
|
|
|
|
from deltachat_rpc_client import EventType
|
|
|
|
|
|
@pytest.fixture
|
|
def path_to_webxdc(request):
|
|
p = request.path.parent.parent.parent.joinpath("test-data/webxdc/chess.xdc")
|
|
assert p.exists()
|
|
return str(p)
|
|
|
|
|
|
def log(msg):
|
|
logging.info(msg)
|
|
|
|
|
|
def setup_realtime_webxdc(ac1, ac2, path_to_webxdc):
|
|
assert ac1.get_config("webxdc_realtime_enabled") == "1"
|
|
assert ac2.get_config("webxdc_realtime_enabled") == "1"
|
|
ac1_ac2_chat = ac1.create_chat(ac2)
|
|
ac2.create_chat(ac1)
|
|
|
|
# share a webxdc app between ac1 and ac2
|
|
ac1_webxdc_msg = ac1_ac2_chat.send_message(text="play", file=path_to_webxdc)
|
|
ac2_webxdc_msg = ac2.wait_for_incoming_msg()
|
|
assert ac2_webxdc_msg.get_snapshot().text == "play"
|
|
|
|
# send iroh announcements simultaneously
|
|
log("sending ac1 -> ac2 realtime advertisement and additional message")
|
|
ac1_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
|
|
log("sending ac2 -> ac1 realtime advertisement and additional message")
|
|
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
|
|
return ac1_webxdc_msg, ac2_webxdc_msg
|
|
|
|
|
|
def setup_thread_send_realtime_data(msg, data):
|
|
def thread_run():
|
|
for _i in range(10):
|
|
msg.send_webxdc_realtime_data(data)
|
|
time.sleep(1)
|
|
|
|
threading.Thread(target=thread_run, daemon=True).start()
|
|
|
|
|
|
def wait_receive_realtime_data(msg_data_list):
|
|
account = msg_data_list[0][0].account
|
|
msg_data_list = msg_data_list[:]
|
|
|
|
log(f"account {account.id}: waiting for realtime data {msg_data_list}")
|
|
while msg_data_list:
|
|
event = account.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_DATA:
|
|
for i, (msg, data) in enumerate(msg_data_list):
|
|
if msg.id == event.msg_id:
|
|
assert list(data) == event.data
|
|
log(f"msg {msg.id}: got correct realtime data {data}")
|
|
del msg_data_list[i]
|
|
break
|
|
|
|
|
|
def test_realtime_sequentially(acfactory, path_to_webxdc):
|
|
"""Test two peers trying to establish connection sequentially."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
ac1.create_chat(ac2)
|
|
ac2.create_chat(ac1)
|
|
|
|
# share a webxdc app between ac1 and ac2
|
|
ac1_webxdc_msg = acfactory.send_message(from_account=ac1, to_account=ac2, text="play", file=path_to_webxdc)
|
|
ac2_webxdc_msg = ac2.get_message_by_id(ac2.wait_for_incoming_msg_event().msg_id)
|
|
snapshot = ac2_webxdc_msg.get_snapshot()
|
|
assert snapshot.text == "play"
|
|
|
|
# send iroh announcements sequentially
|
|
log("sending ac1 -> ac2 realtime advertisement and additional message")
|
|
ac1_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
acfactory.send_message(from_account=ac1, to_account=ac2, text="ping1")
|
|
|
|
log("waiting for incoming message on ac2")
|
|
snapshot = ac2.get_message_by_id(ac2.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
assert snapshot.text == "ping1"
|
|
|
|
log("sending ac2 -> ac1 realtime advertisement and additional message")
|
|
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
acfactory.send_message(from_account=ac2, to_account=ac1, text="ping2")
|
|
|
|
log("waiting for incoming message on ac1")
|
|
snapshot = ac1.get_message_by_id(ac1.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
assert snapshot.text == "ping2"
|
|
|
|
log("sending realtime data ac1 -> ac2")
|
|
# Test that 128 KB of data can be sent in a single message.
|
|
data = os.urandom(128000)
|
|
ac1_webxdc_msg.send_webxdc_realtime_data(data)
|
|
|
|
log("ac2: waiting for realtime data")
|
|
while 1:
|
|
event = ac2.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_DATA:
|
|
assert event.data == list(data)
|
|
break
|
|
|
|
|
|
def test_realtime_simultaneously(acfactory, path_to_webxdc):
|
|
"""Test two peers trying to establish connection simultaneously."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
|
|
ac1_webxdc_msg, ac2_webxdc_msg = setup_realtime_webxdc(ac1, ac2, path_to_webxdc)
|
|
|
|
setup_thread_send_realtime_data(ac1_webxdc_msg, [10])
|
|
wait_receive_realtime_data([(ac2_webxdc_msg, [10])])
|
|
|
|
|
|
def test_two_parallel_realtime_simultaneously(acfactory, path_to_webxdc):
|
|
"""Test two peers trying to establish connection simultaneously."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
|
|
ac1_webxdc_msg, ac2_webxdc_msg = setup_realtime_webxdc(ac1, ac2, path_to_webxdc)
|
|
ac1_webxdc_msg2, ac2_webxdc_msg2 = setup_realtime_webxdc(ac1, ac2, path_to_webxdc)
|
|
|
|
setup_thread_send_realtime_data(ac1_webxdc_msg, [10])
|
|
setup_thread_send_realtime_data(ac1_webxdc_msg2, [20])
|
|
setup_thread_send_realtime_data(ac2_webxdc_msg, [30])
|
|
setup_thread_send_realtime_data(ac2_webxdc_msg2, [40])
|
|
|
|
wait_receive_realtime_data([(ac1_webxdc_msg, [30]), (ac1_webxdc_msg2, [40])])
|
|
wait_receive_realtime_data([(ac2_webxdc_msg, [10]), (ac2_webxdc_msg2, [20])])
|
|
|
|
|
|
def test_no_duplicate_messages(acfactory, path_to_webxdc):
|
|
"""Test that messages are received only once."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
|
|
ac1_ac2_chat = ac1.create_chat(ac2)
|
|
|
|
ac1_webxdc_msg = ac1_ac2_chat.send_message(text="webxdc", file=path_to_webxdc)
|
|
|
|
ac2_webxdc_msg = ac2.wait_for_incoming_msg()
|
|
ac2_webxdc_msg.get_snapshot().chat.accept()
|
|
assert ac2_webxdc_msg.get_snapshot().text == "webxdc"
|
|
|
|
# Issue a "send" call in parallel with sending advertisement.
|
|
# Previously due to a bug this caused subscribing to the channel twice.
|
|
ac2_webxdc_msg.send_webxdc_realtime_data.future(b"foobar")
|
|
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
|
|
def thread_run():
|
|
for i in range(10):
|
|
data = str(i).encode()
|
|
ac1_webxdc_msg.send_webxdc_realtime_data(data)
|
|
time.sleep(1)
|
|
|
|
threading.Thread(target=thread_run, daemon=True).start()
|
|
|
|
while 1:
|
|
event = ac2.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_DATA:
|
|
n = int(bytes(event.data).decode())
|
|
break
|
|
|
|
while 1:
|
|
event = ac2.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_DATA:
|
|
assert int(bytes(event.data).decode()) > n
|
|
break
|
|
|
|
|
|
def test_no_reordering(acfactory, path_to_webxdc):
|
|
"""Test that sending a lot of realtime messages does not result in reordering."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
|
|
ac1_webxdc_msg, ac2_webxdc_msg = setup_realtime_webxdc(ac1, ac2, path_to_webxdc)
|
|
|
|
setup_thread_send_realtime_data(ac1_webxdc_msg, b"hello")
|
|
wait_receive_realtime_data([(ac2_webxdc_msg, b"hello")])
|
|
|
|
for i in range(200):
|
|
ac1_webxdc_msg.send_webxdc_realtime_data([i])
|
|
|
|
for i in range(200):
|
|
while 1:
|
|
event = ac2.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_DATA and bytes(event.data) != b"hello":
|
|
if event.data[0] == i:
|
|
break
|
|
pytest.fail("Reordering detected")
|
|
|
|
|
|
def test_advertisement_after_chatting(acfactory, path_to_webxdc):
|
|
"""Test that realtime advertisement is assigned to the correct message after chatting."""
|
|
ac1, ac2 = acfactory.get_online_accounts(2)
|
|
ac1.set_config("webxdc_realtime_enabled", "1")
|
|
ac2.set_config("webxdc_realtime_enabled", "1")
|
|
|
|
ac1_ac2_chat = ac1.create_chat(ac2)
|
|
ac1_webxdc_msg = ac1_ac2_chat.send_message(text="WebXDC", file=path_to_webxdc)
|
|
ac2_webxdc_msg = ac2.wait_for_incoming_msg()
|
|
assert ac2_webxdc_msg.get_snapshot().text == "WebXDC"
|
|
|
|
ac1_ac2_chat.send_text("Hello!")
|
|
ac2_hello_msg = ac2.wait_for_incoming_msg()
|
|
ac2_hello_msg_snapshot = ac2_hello_msg.get_snapshot()
|
|
assert ac2_hello_msg_snapshot.text == "Hello!"
|
|
ac2_hello_msg_snapshot.chat.accept()
|
|
|
|
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
|
|
while 1:
|
|
event = ac1.wait_for_event()
|
|
if event.kind == EventType.WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED:
|
|
assert event.msg_id == ac1_webxdc_msg.id
|
|
break
|