feat: Nostr relay publish + availability subscription via nostrclient (#2) #11
1 changed files with 90 additions and 0 deletions
test: event-builder shape (30402/30078/31923/22001)
Pure tests (no signing/relays): listing tags (d/title/price/status/g/t), reservation carries canonical amount_sat as plaintext JSON, calendar start/end + no broken 'a' tag, availability response plaintext. 20 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
commit
1465a30a01
90
tests/test_events.py
Normal file
90
tests/test_events.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""Nostr event builders — tag/kind/content shape (no signing, no relays)."""
|
||||
|
||||
import json
|
||||
|
||||
from ..models import AvailabilityResult, Booking, BookingStatus
|
||||
from ..nostr import events
|
||||
from ..nostr.kinds import (
|
||||
KIND_AVAILABILITY_RESPONSE,
|
||||
KIND_CALENDAR_EVENT,
|
||||
KIND_LISTING,
|
||||
KIND_RESERVATION,
|
||||
)
|
||||
from .conftest import make_room
|
||||
|
||||
|
||||
def _tag(ev, name):
|
||||
"""First tag value for `name`, or None."""
|
||||
return next((t[1] for t in ev["tags"] if t[0] == name), None)
|
||||
|
||||
|
||||
def _tags(ev, name):
|
||||
return [t[1] for t in ev["tags"] if t[0] == name]
|
||||
|
||||
|
||||
def test_listing_event_shape():
|
||||
room = make_room(
|
||||
currency="EUR", price=80.0,
|
||||
)
|
||||
room.amenities = ["wifi", "breakfast"]
|
||||
room.location = "Château"
|
||||
room.geohash = "u0j2"
|
||||
room.images = ["https://img/1.jpg"]
|
||||
|
||||
ev = events.build_listing_event(room)
|
||||
|
||||
assert ev["kind"] == KIND_LISTING # 30402
|
||||
assert _tag(ev, "d") == room.id # addressable: re-publish replaces
|
||||
assert _tag(ev, "title") == "Tower Room"
|
||||
price = next(t for t in ev["tags"] if t[0] == "price")
|
||||
assert price == ["price", "80.0", "EUR", "night"]
|
||||
assert _tag(ev, "status") == "active"
|
||||
assert _tag(ev, "location") == "Château"
|
||||
assert _tag(ev, "g") == "u0j2"
|
||||
assert _tags(ev, "image") == ["https://img/1.jpg"]
|
||||
assert set(_tags(ev, "t")) == {"wifi", "breakfast"}
|
||||
|
||||
|
||||
def test_reservation_event_is_plaintext_json_no_scaffolding():
|
||||
booking = Booking(
|
||||
id="bk1", room_id="room1", guest_pubkey="npub_guest",
|
||||
check_in="2026-08-01", check_out="2026-08-04", nights=3, num_guests=2,
|
||||
currency="sat", price_fiat=300.0, amount_sat=300, deposit_sat=300,
|
||||
status=BookingStatus.confirmed,
|
||||
)
|
||||
ev = events.build_reservation_event(booking, booking.guest_pubkey)
|
||||
|
||||
assert ev["kind"] == KIND_RESERVATION # 30078
|
||||
assert _tag(ev, "d") == "bk1"
|
||||
assert _tag(ev, "p") == "npub_guest"
|
||||
assert "_plaintext" not in ev # scaffolding removed; service.py encrypts content
|
||||
payload = json.loads(ev["content"])
|
||||
assert payload["amount_sat"] == 300 # canonical, carried verbatim
|
||||
assert payload["status"] == "confirmed"
|
||||
|
||||
|
||||
def test_block_calendar_event_shape():
|
||||
room = make_room()
|
||||
ev = events.build_block_calendar_event(room, "2026-09-01", "2026-09-05", "blk1")
|
||||
|
||||
assert ev["kind"] == KIND_CALENDAR_EVENT # 31923
|
||||
assert _tag(ev, "d") == "room1:blk1"
|
||||
assert _tag(ev, "start") == "2026-09-01"
|
||||
assert _tag(ev, "end") == "2026-09-05"
|
||||
# the broken {operator_pubkey} 'a' tag was removed
|
||||
assert not any(t[0] == "a" for t in ev["tags"])
|
||||
|
||||
|
||||
def test_availability_response_is_plaintext():
|
||||
result = AvailabilityResult(
|
||||
room_id="room1", check_in="2026-08-01", check_out="2026-08-04",
|
||||
available=True, nights=3, quote_sat=300, quote_fiat=3.0, currency="sat",
|
||||
)
|
||||
ev = events.build_availability_response(result, "npub_requester")
|
||||
|
||||
assert ev["kind"] == KIND_AVAILABILITY_RESPONSE # 22001
|
||||
assert _tag(ev, "p") == "npub_requester"
|
||||
assert "_plaintext" not in ev # public info: no encryption
|
||||
payload = json.loads(ev["content"])
|
||||
assert payload["available"] is True
|
||||
assert payload["quote_sat"] == 300
|
||||
Loading…
Add table
Add a link
Reference in a new issue