Major expansion of the Timmy Time Dashboard: Backend modules: - Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms - L402/Lightning: payment_handler, l402_proxy with HMAC macaroons - Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice) - Notifications: push notifier for swarm events - Shortcuts: Siri Shortcuts iOS integration endpoints - WebSocket: live dashboard event manager - Inter-agent: agent-to-agent messaging layer Dashboard routes: - /swarm/* — swarm management and agent registry - /marketplace — agent catalog with sat pricing - /voice/* — voice command processing - /mobile — mobile status endpoint - /swarm/live — WebSocket live feed React web dashboard (dashboard-web/): - Sovereign Terminal design — dark theme with Bitcoin orange accents - Three-column layout: status sidebar, workspace tabs, context panel - Chat, Swarm, Tasks, Marketplace tab views - JetBrains Mono typography, terminal aesthetic - Framer Motion animations throughout Tests: 228 passing (expanded from 93) Includes Kimi's additional templates and QA work.
111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
"""Tests for the L402 proxy and payment handler."""
|
|
|
|
import hashlib
|
|
|
|
import pytest
|
|
|
|
|
|
# ── Payment Handler ──────────────────────────────────────────────────────────
|
|
|
|
def test_create_invoice():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
invoice = handler.create_invoice(100, "test payment")
|
|
assert invoice.amount_sats == 100
|
|
assert invoice.memo == "test payment"
|
|
assert invoice.payment_hash is not None
|
|
assert invoice.payment_request.startswith("lnbc")
|
|
|
|
|
|
def test_check_payment_mock_auto_settles():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
invoice = handler.create_invoice(50, "auto settle")
|
|
assert handler.check_payment(invoice.payment_hash) is True
|
|
|
|
|
|
def test_check_payment_nonexistent():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
assert handler.check_payment("nonexistent-hash") is False
|
|
|
|
|
|
def test_settle_invoice_with_preimage():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
invoice = handler.create_invoice(75, "preimage test")
|
|
invoice.settled = False # Reset for manual settlement
|
|
assert handler.settle_invoice(invoice.payment_hash, invoice.preimage) is True
|
|
assert invoice.settled is True
|
|
|
|
|
|
def test_settle_invoice_wrong_preimage():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
invoice = handler.create_invoice(75, "wrong preimage")
|
|
invoice.settled = False
|
|
assert handler.settle_invoice(invoice.payment_hash, "0" * 64) is False
|
|
|
|
|
|
def test_list_invoices():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
handler.create_invoice(10, "a")
|
|
handler.create_invoice(20, "b")
|
|
assert len(handler.list_invoices()) == 2
|
|
|
|
|
|
def test_list_invoices_settled_only():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
inv = handler.create_invoice(10, "settle me")
|
|
handler.check_payment(inv.payment_hash) # auto-settles in mock
|
|
settled = handler.list_invoices(settled_only=True)
|
|
assert len(settled) >= 1
|
|
|
|
|
|
def test_get_invoice():
|
|
from timmy_serve.payment_handler import PaymentHandler
|
|
handler = PaymentHandler()
|
|
inv = handler.create_invoice(100, "get me")
|
|
found = handler.get_invoice(inv.payment_hash)
|
|
assert found is not None
|
|
assert found.amount_sats == 100
|
|
|
|
|
|
# ── L402 Proxy ───────────────────────────────────────────────────────────────
|
|
|
|
def test_create_l402_challenge():
|
|
from timmy_serve.l402_proxy import create_l402_challenge
|
|
challenge = create_l402_challenge(100, "API access")
|
|
assert "macaroon" in challenge
|
|
assert "invoice" in challenge
|
|
assert "payment_hash" in challenge
|
|
|
|
|
|
def test_verify_l402_token_valid():
|
|
from timmy_serve.l402_proxy import create_l402_challenge, verify_l402_token
|
|
challenge = create_l402_challenge(50, "verify test")
|
|
# In mock mode, payment auto-settles
|
|
assert verify_l402_token(challenge["macaroon"]) is True
|
|
|
|
|
|
def test_verify_l402_token_invalid_format():
|
|
from timmy_serve.l402_proxy import verify_l402_token
|
|
assert verify_l402_token("not-a-valid-token") is False
|
|
|
|
|
|
def test_macaroon_roundtrip():
|
|
from timmy_serve.l402_proxy import Macaroon
|
|
mac = Macaroon(identifier="test-id", signature="test-sig")
|
|
serialized = mac.serialize()
|
|
restored = Macaroon.deserialize(serialized)
|
|
assert restored is not None
|
|
assert restored.identifier == "test-id"
|
|
assert restored.signature == "test-sig"
|
|
|
|
|
|
def test_macaroon_deserialize_invalid():
|
|
from timmy_serve.l402_proxy import Macaroon
|
|
assert Macaroon.deserialize("garbage") is None
|