Spaces:
Running on Zero
Running on Zero
File size: 4,049 Bytes
cbad453 fa5b4a9 | 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | """Integration test: cross-node chat delivery (M10).
Verifies that chat.send from node A to node B:
- calls chat.deliver on B's bus
- B stores the message
- chat.history on B shows the message
- delivery status is "delivered" (not "queued" or "direct")
Uses in-process InMemoryTransport so no relay/HTTP needed.
"""
from __future__ import annotations
import pytest
from hearthnet.bus import InMemoryTransport
@pytest.fixture()
def two_nodes():
from hearthnet.node import HearthNode
net = InMemoryTransport()
alice = HearthNode("node-alice", "Alice", "ed25519:test", transport=net)
alice.install_demo_services()
net.register(alice.bus)
bob = HearthNode("node-bob", "Bob", "ed25519:test", transport=net)
bob.install_demo_services()
net.register(bob.bus)
return alice, bob
@pytest.mark.asyncio
async def test_chat_send_cross_node_delivers(two_nodes):
alice, bob = two_nodes
r = await alice.bus.call(
"chat.send", (1, 0), {"input": {"recipient": "node-bob", "body": "Hello Bob!"}}
)
status = r.get("output", {}).get("delivered")
assert status == "delivered", f"Expected 'delivered', got {status!r}"
@pytest.mark.asyncio
async def test_chat_history_shows_received_message(two_nodes):
alice, bob = two_nodes
await alice.bus.call(
"chat.send", (1, 0), {"input": {"recipient": "node-bob", "body": "Hi from Alice"}}
)
r = await bob.bus.call("chat.history", (1, 0), {"input": {"peer": "node-alice"}})
msgs = r.get("output", {}).get("messages", [])
assert len(msgs) == 1, f"Expected 1 message in Bob's history, got {len(msgs)}"
assert msgs[0]["body"] == "Hi from Alice"
assert msgs[0]["from"] == "node-alice"
@pytest.mark.asyncio
async def test_self_send_returns_direct(two_nodes):
alice, _ = two_nodes
r = await alice.bus.call(
"chat.send", (1, 0), {"input": {"recipient": "node-alice", "body": "hi me"}}
)
status = r.get("output", {}).get("delivered")
assert status == "direct", f"Expected 'direct' for self-send, got {status!r}"
@pytest.mark.asyncio
async def test_send_to_unknown_node_returns_queued(two_nodes):
alice, _ = two_nodes
r = await alice.bus.call(
"chat.send", (1, 0), {"input": {"recipient": "node-nobody", "body": "hello?"}}
)
status = r.get("output", {}).get("delivered")
assert status == "queued", f"Expected 'queued' for unknown node, got {status!r}"
@pytest.mark.asyncio
async def test_manually_wired_chat_service_delivers():
"""Regression: a ChatService registered manually (as app.py / the HF Space
entry point does) must receive a ``bus=`` reference, otherwise
``_deliver_remote`` short-circuits to ``"queued"`` before attempting
delivery. Mirrors the app.py wiring to guard against that regression.
"""
from hearthnet.node import HearthNode
from hearthnet.services.chat.service import ChatService
net = InMemoryTransport()
alice = HearthNode("node-alice", "Alice", "ed25519:test", transport=net)
# Wire chat exactly like app.py: explicit bus= argument is required.
alice.bus.register_service(ChatService(alice.node_id, bus=alice.bus))
net.register(alice.bus)
bob = HearthNode("node-bob", "Bob", "ed25519:test", transport=net)
bob.bus.register_service(ChatService(bob.node_id, bus=bob.bus))
net.register(bob.bus)
r = await alice.bus.call(
"chat.send", (1, 0), {"input": {"recipient": "node-bob", "body": "wired"}}
)
assert r.get("output", {}).get("delivered") == "delivered"
@pytest.mark.asyncio
async def test_chat_service_without_bus_cannot_deliver():
"""A ChatService constructed without a bus reference can only queue —
documents the failure mode the app.py wiring fix prevents.
"""
from hearthnet.services.chat.service import ChatService
svc = ChatService("node-alice") # no bus=
status = await svc._deliver_remote(
{"to": "node-bob", "from": "node-alice", "body": "x", "event_id": "e1"}
)
assert status == "queued"
|