diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_chat_send.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_chat_send.py | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/packages/meshbay-hub/tests/test_chat_send.py b/packages/meshbay-hub/tests/test_chat_send.py index 8b098c2a..5db8f266 100644 --- a/packages/meshbay-hub/tests/test_chat_send.py +++ b/packages/meshbay-hub/tests/test_chat_send.py @@ -28,6 +28,7 @@ either source. import json import shutil import subprocess +import sys from pathlib import Path import pytest @@ -42,7 +43,12 @@ pytestmark = pytest.mark.skipif( @pytest.fixture(scope="module") def probe(): - run = subprocess.run(["python3", str(HARNESS)], capture_output=True, timeout=180) + # `sys.executable`, not a bare "python3": the harness imports + # `meshbay_common` to seal the chat keys the way the node does, and the + # system interpreter has neither that nor msgpack. The other probes get + # away with "python3" because they import nothing from this project. + run = subprocess.run([sys.executable, str(HARNESS)], + capture_output=True, timeout=180) assert run.returncode == 0, run.stderr.decode()[-2000:] data = json.loads(run.stdout.decode()) steps = {sc["name"]: {s["label"]: s for s in sc["steps"]} @@ -103,3 +109,52 @@ def test_the_reply_is_not_handed_to_another_request(probe, reply): f"the chat {reply} was routed to the pending music_meta_req ({stolen}) -- " "that request now believes it has an answer, and the chat send is " "waiting for a reply that already arrived") + + +@pytest.mark.parametrize("reply", ["ack", "error"]) +def test_the_message_goes_out_sealed_and_signed(probe, reply): + """ + What actually left the browser (MNP 2.0). + + Asserted for both scenarios because the composer is what decides to send: + a client that fell back to plaintext when something went wrong would be + refused by the node, but the refusal arrives after the fact and reads as + "the message did not send". There is no plaintext form on the wire. + """ + data, _ = probe + sent = [line for line in data["log"] + if line.startswith(f"{reply}: chat_msg ")] + assert sent, (f"no chat_msg reached the stand-in node in the {reply} " + f"scenario — the send did not complete. log: {data['log']}") + assert "format=1" in sent[0], "the message was not sealed" + assert "sig=64" in sent[0], "the message was not signed" + assert "ct=" in sent[0] and "ct=0" not in sent[0], "there was no ciphertext" + assert "plaintextLeak=false" in sent[0], ( + "the text the person typed appears somewhere in the message that went " + "on the wire") + + +def test_the_chat_keys_answer_is_not_handed_to_another_request(probe): + """ + The same defect this file exists for, in the message type that carries the + group's chat keys — which did not exist when it was written, and which a + send now depends on. It went astray on the probe's first encrypted run. + """ + data, _ = probe + stolen = [line for line in data["log"] if "music_meta resolved with" in line] + assert not stolen, ( + f"a reply was routed to the pending music_meta_req ({stolen}) — the " + "send then waits out its own 30s timeout with the composer disabled") + + +def test_history_still_renders(probe): + """ + Not about sending at all, and here because it broke without a sound: + `_asText` was deleted with an unrelated helper beside it, its only caller + sits inside a promise the panel catches, and every conversation rendered + empty with the node answering perfectly. + """ + _, steps = probe + assert steps["ack"]["older request pending"]["bubbles"] == 5, ( + "the five history messages did not render — the panel swallows a " + "failure in the transport's message reader, so this is silent") |