forked from ChelseaKR/habitable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_relay.py
More file actions
90 lines (71 loc) · 3 KB
/
Copy pathtest_relay.py
File metadata and controls
90 lines (71 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright 2026 Chelsea Kelly-Reif
"""The optional ciphertext-only relay."""
from __future__ import annotations
import json
import threading
import urllib.error
import urllib.request
from collections.abc import Iterator
import pytest
from habitable.relay import RelayStore, make_server
class TestRelayStore:
def test_post_fetch_round_trip_and_metrics(self) -> None:
store = RelayStore()
store.post("room", b"ciphertext-1")
store.post("room", b"ciphertext-2")
assert store.fetch("room") == [b"ciphertext-1", b"ciphertext-2"]
metrics = store.metrics()
assert metrics["posted"] == 2 and metrics["rooms"] == 1
assert metrics["bytes_relayed"] == len(b"ciphertext-1") + len(b"ciphertext-2")
def test_empty_room(self) -> None:
assert RelayStore().fetch("nobody") == []
@pytest.fixture
def server_url() -> Iterator[str]:
server = make_server("127.0.0.1", 0)
port = server.server_address[1]
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
yield f"http://127.0.0.1:{port}"
finally:
server.shutdown()
server.server_close()
thread.join(timeout=5)
def _get(url: str) -> tuple[int, bytes]:
try:
with urllib.request.urlopen(url, timeout=5) as response:
return response.status, response.read()
except urllib.error.HTTPError as exc:
body = exc.read()
exc.close()
return exc.code, body
def test_healthz(server_url: str) -> None:
status, body = _get(f"{server_url}/healthz")
assert status == 200
assert json.loads(body)["status"] == "ok"
def test_unknown_path_is_404(server_url: str) -> None:
status, _ = _get(f"{server_url}/nope")
assert status == 404
def test_http_post_then_get(server_url: str) -> None:
request = urllib.request.Request(f"{server_url}/rooms/abc", data=b"sealed-bytes", method="POST")
with urllib.request.urlopen(request, timeout=5) as response:
assert response.status == 200
status, body = _get(f"{server_url}/rooms/abc")
assert status == 200
assert json.loads(body)["messages"] # one base64 message present
def test_healthz_exposes_only_aggregate_counts(server_url: str) -> None:
"""The relay must leak no room names or message contents — only counts."""
room = "room-SECRETNAME-123"
blob = b"SECRET-CIPHERTEXT-PAYLOAD"
request = urllib.request.Request(f"{server_url}/rooms/{room}", data=blob, method="POST")
with urllib.request.urlopen(request, timeout=5) as response:
assert response.status == 200
status, body = _get(f"{server_url}/healthz")
assert status == 200
payload = json.loads(body)
assert set(payload) <= {"status", "rooms", "posted", "fetched", "bytes_relayed"}
text = body.decode("utf-8")
assert "SECRETNAME" not in text # no room identifiers
assert "SECRET-CIPHERTEXT" not in text # no message contents
assert payload["rooms"] == 1 and payload["posted"] == 1