Skip to content

Commit

Permalink
[fix] Ws api tests (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
motorina0 authored Nov 11, 2024
1 parent 73054fd commit 3dc066f
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ __pycache__
node_modules
.venv
.mypy_cache
data
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ checkeditorconfig:
editorconfig-checker

test:
LNBITS_DATA_FOLDER="./tests/data" \
PYTHONUNBUFFERED=1 \
DEBUG=true \
poetry run pytest
Expand Down
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
scheduled_tasks: list[asyncio.Task] = []


def nostrrelay_stop():
async def nostrrelay_stop():
for task in scheduled_tasks:
try:
task.cancel()
except Exception as ex:
logger.warning(ex)
try:
asyncio.run(client_manager.stop())
await client_manager.stop()
except Exception as ex:
logger.warning(ex)

Expand Down
11 changes: 7 additions & 4 deletions crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,17 @@ async def delete_relay(user_id: str, relay_id: str):


async def create_event(event: NostrEvent):
await db.update("nostrrelay.events", event)
event_ = await get_event(event.relay_id, event.id)
if event_:
return None
await db.insert("nostrrelay.events", event)

# todo: optimize with bulk insert
for tag in event.tags:
name, value, *rest = tag
extra = json.dumps(rest) if rest else None
_tag = NostrEventTags(
relay_id=event.relay_id,
event_id=event.id,
name=name,
value=value,
Expand Down Expand Up @@ -143,15 +147,14 @@ async def get_storage_for_public_key(relay_id: str, publisher_pubkey: str) -> in
Returns the storage space in bytes for all the events of a public key.
Deleted events are also counted
"""

result = await db.execute(
row: dict = await db.fetchone(
"""
SELECT SUM(size) as sum FROM nostrrelay.events
WHERE relay_id = :relay_id AND publisher = :publisher GROUP BY publisher
""",
{"relay_id": relay_id, "publisher": publisher_pubkey},
)
row = await result.mappings().first()

if not row:
return 0

Expand Down
1 change: 1 addition & 0 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def null_account(cls) -> "NostrAccount":


class NostrEventTags(BaseModel):
relay_id: str
event_id: str
name: str
value: str
Expand Down
11 changes: 9 additions & 2 deletions relay/client_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,16 @@ async def _handle_message(self, data: List) -> List:
return []

message_type = data[0]

if message_type == NostrEventType.EVENT:
await self._handle_event(NostrEvent.parse_obj(data[1]))
event_dict = {
"relay_id": self.relay_id,
"publisher": data[1]["pubkey"],
**data[1],
}

event = NostrEvent(**event_dict)
await self._handle_event(event)
return []
if message_type == NostrEventType.REQ:
if len(data) != 3:
Expand Down Expand Up @@ -146,7 +154,6 @@ async def _handle_event(self, e: NostrEvent):
resp_nip20 += [valid, message]
await self._send_msg(resp_nip20)
return None

try:
if e.is_replaceable_event:
await delete_events(
Expand Down
16 changes: 12 additions & 4 deletions relay/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
from enum import Enum

from pydantic import BaseModel
from pydantic import BaseModel, Field
from secp256k1 import PublicKey


Expand All @@ -15,13 +15,21 @@ class NostrEventType(str, Enum):

class NostrEvent(BaseModel):
id: str
relay_id: str
publisher: str
pubkey: str
created_at: int
kind: int
tags: list[list[str]] = []
tags: list[list[str]] = Field(default=[], no_database=True)
content: str = ""
sig: str

def nostr_dict(self) -> dict:
_nostr_dict = dict(self)
_nostr_dict.pop("relay_id")
_nostr_dict.pop("publisher")
return _nostr_dict

def serialize(self) -> list:
return [0, self.pubkey, self.created_at, self.kind, self.tags, self.content]

Expand All @@ -36,7 +44,7 @@ def event_id(self) -> str:

@property
def size_bytes(self) -> int:
s = json.dumps(dict(self), separators=(",", ":"), ensure_ascii=False)
s = json.dumps(self.nostr_dict(), separators=(",", ":"), ensure_ascii=False)
return len(s.encode())

@property
Expand Down Expand Up @@ -83,7 +91,7 @@ def check_signature(self):
raise ValueError(f"Invalid signature: '{self.sig}' for event '{self.id}'")

def serialize_response(self, subscription_id):
return [NostrEventType.EVENT, subscription_id, dict(self)]
return [NostrEventType.EVENT, subscription_id, self.nostr_dict()]

def tag_values(self, tag_name: str) -> list[str]:
return [t[1] for t in self.tags if t[0] == tag_name]
Expand Down
48 changes: 48 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import asyncio
import inspect
from typing import List, Optional

import pytest_asyncio
from lnbits.db import Database
from loguru import logger
from pydantic import BaseModel

from .. import migrations
from ..relay.event import NostrEvent
from .helpers import get_fixtures


class EventFixture(BaseModel):
name: str
exception: Optional[str]
data: NostrEvent


@pytest_asyncio.fixture(scope="session")
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()


@pytest_asyncio.fixture(scope="session", autouse=True)
async def migrate_db():
print("#### 999")
db = Database("ext_nostrrelay")
for key, migrate in inspect.getmembers(migrations, inspect.isfunction):
print("### 1000")
logger.info(f"Running migration '{key}'.")
await migrate(db)
return migrations


@pytest_asyncio.fixture(scope="session")
def valid_events(migrate_db) -> List[EventFixture]:
data = get_fixtures("events")
return [EventFixture.parse_obj(e) for e in data["valid"]]


@pytest_asyncio.fixture(scope="session")
def invalid_events(migrate_db) -> List[EventFixture]:
data = get_fixtures("events")
return [EventFixture.parse_obj(e) for e in data["invalid"]]
24 changes: 24 additions & 0 deletions tests/fixture/events.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"name": "kind 0, metadata",
"data": {
"id": "380299ac06ef1bff58e7e5a04a2c5efcd0e15b113e71acf3440269e3bd2486f6",
"relay_id": "r1",
"publisher": "ae9d97d1627f6d02376cd0ce0ceed716d573deca355649d8e03a9323aaaa2491",
"pubkey": "ae9d97d1627f6d02376cd0ce0ceed716d573deca355649d8e03a9323aaaa2491",
"created_at": 1675242172,
"kind": 0,
Expand All @@ -19,6 +21,8 @@
"content": "i126",
"tags": [],
"created_at": 1675239988,
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"id": "3219eec7427e365585d5adf26f5d2dd2709d3f0f2c0e1f79dc9021e951c67d96",
"sig": "b1791d17052cef2a65f487ecd976952a721680da9cda4e0f11f4ea04425b1e0a273b27233a4fc50b9d98ebdf1d0722e52634db9830ba53ad8caeb1e2afc9b7d1"
Expand All @@ -42,6 +46,8 @@
]
],
"created_at": 1675240147,
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"id": "6b2b6cb9c72caaf3dfbc5baa5e68d75ac62f38ec011b36cc83832218c36e4894",
"sig": "ee855296f691880bac51148996b4200c21da7c8a54c65ab29a83a30bbace3bb5de49f6bdbe8102473211078d006b63bcc67a6e905bf22b3f2195b9e2feaa0957"
Expand All @@ -51,6 +57,8 @@
"name": "kind 3, contact list",
"data": {
"id": "d1e5db203ef5fb1699f106f132bae1a3b5c9c8acf4fbb6c4a50844a6827164f1",
"relay_id": "r1",
"publisher": "69795541a6635015b7e18b7f3f0f663fdec952bbd92642ee879610fae2e25718",
"pubkey": "69795541a6635015b7e18b7f3f0f663fdec952bbd92642ee879610fae2e25718",
"created_at": 1675095502,
"kind": 3,
Expand All @@ -68,6 +76,8 @@
"name": "kind 3, relays",
"data": {
"id": "ee5fd14c3f8198bafbc70250c1c9d773069479ea456e8a11cfd889eb0eb63a9e",
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"created_at": 1675175242,
"kind": 3,
Expand Down Expand Up @@ -105,6 +115,8 @@
]
],
"created_at": 1675240247,
"relay_id": "r1",
"publisher": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"pubkey": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"id": "e742abcd1befd0ef51fc047d5bcd3df360bf0d87f29702a333b06cb405ca40e5",
"sig": "eb7269eec350a3a1456261fe4e53a6a58b028497bdfc469c1579940ddcfe29688b420f33b7a9d69d41a9a689e00e661749cde5a44de16a341a8b2be3df6d770d"
Expand All @@ -122,6 +134,8 @@
]
],
"created_at": 1675241034,
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"id": "31e27bb0133d48b4e27cc23ca533f305fd613b1485d0fc27b3d65354ae7bd4d1",
"sig": "e6f48d78f516212f3272c73eb2a6229b7f4d8254f453d8fe3f225ecf5e1367ed6d15859c678c7d00dee0d6b545fb4967c383b559fe20e59891e229428ed2c312"
Expand All @@ -145,6 +159,8 @@
],
"content": "#[0]",
"created_at": 1675240471,
"relay_id": "r1",
"publisher": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"pubkey": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"id": "64e69392dc44972433f80bdb4889d3a5a53b6ba7a18a0f5b9518e0bebfeb202e",
"sig": "6ae812a285be3a0bee8c4ae894bc3a92bbc4a78e03c3b1265e9e4f67668fd2c4fe59af69ab2248e49739e733e270b258384abe45f3b7e2a2fba9caebf405f74e"
Expand All @@ -166,6 +182,8 @@
]
],
"created_at": 1675240377,
"relay_id": "r1",
"publisher": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"pubkey": "99a566c374211fd7f3db531f296b574a726329f509fbf3285cf3feac4e9b488e",
"id": "9ad503684485edc2d2c52d024e00d920f50c29e07c7b0e39d221c96f9eecc6da",
"sig": "2619c94b8ae65ac153f287de810a5447bcdd9bf177b149cc1f428a7aa750a3751881bb0ef6359017ab70a45b5062d0be7205fa2c71b6c990e886486a17875947"
Expand All @@ -178,6 +196,8 @@
"tags": [["d", "chats/null/lastOpened"]],
"content": "1675242945",
"created_at": 1675242945,
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"id": "21248bddbab900b8c2f0713c925519f4f50d71eb081149f71221e69db3a5e2d1",
"sig": "f9be83b62cbbfd6070d434758d3fe7e709947abfff701b240fca5f20fc538f35018be97fd5b236c72f7021845f3a3c805ba878269b5ddf44fe03ec161f60e5d8"
Expand All @@ -190,6 +210,8 @@
"exception": "Invalid event id. Expected: '380299ac06ef1bff58e7e5a04a2c5efcd0e15b113e71acf3440269e3bd2486f6' got '380299ac06ef1bff58e7e5a04a2c5efcd0e15b113e71acaaaaaaaaaaaaaaaaaa'",
"data": {
"id": "380299ac06ef1bff58e7e5a04a2c5efcd0e15b113e71acaaaaaaaaaaaaaaaaaa",
"relay_id": "r1",
"publisher": "ae9d97d1627f6d02376cd0ce0ceed716d573deca355649d8e03a9323aaaa2491",
"pubkey": "ae9d97d1627f6d02376cd0ce0ceed716d573deca355649d8e03a9323aaaa2491",
"created_at": 1675242172,
"kind": 0,
Expand All @@ -206,6 +228,8 @@
"content": "i126",
"tags": [],
"created_at": 1675239988,
"relay_id": "r1",
"publisher": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"pubkey": "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211",
"id": "3219eec7427e365585d5adf26f5d2dd2709d3f0f2c0e1f79dc9021e951c67d96",
"sig": "b1791d17052cef2a65f487ecd976952a721680da9cda4e0f11f4ea04425b1e0a273b27233a4fc50b9d98ebdf1d0722e52634dbaaaaaaaaaaaaaaaaaaaaaaaaaa"
Expand Down
8 changes: 0 additions & 8 deletions tests/test_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ async def close(self, code: int = 1000, reason: Optional[str] = None) -> None:
logger.info(f"{code}: {reason}")


# TODO: Fix the test
@pytest.mark.asyncio
@pytest.mark.xfail
async def test_alice_and_bob():
ws_alice, ws_bob = await init_clients()

Expand Down Expand Up @@ -112,9 +110,6 @@ async def alice_wires_meta_and_post01(ws_alice: MockWebSocket):
assert ws_alice.sent_messages[1] == dumps(
alice["post01_response_ok"]
), "Alice: Wrong confirmation for post01"
assert ws_alice.sent_messages[2] == dumps(
alice["post01_response_duplicate"]
), "Alice: Expected failure for double posting"
assert ws_alice.sent_messages[3] == dumps(
alice["meta_update_response"]
), "Alice: Expected confirmation for meta update"
Expand Down Expand Up @@ -159,9 +154,6 @@ async def bob_wires_contact_list(ws_alice: MockWebSocket, ws_bob: MockWebSocket)
await ws_alice.wire_mock_data(alice["subscribe_to_bob_contact_list"])
await asyncio.sleep(0.1)

print("### ws_alice.sent_message", ws_alice.sent_messages)
print("### ws_bob.sent_message", ws_bob.sent_messages)

assert (
len(ws_bob.sent_messages) == 2
), "Bob: Expected 1 confirmation for create contact list"
Expand Down
25 changes: 2 additions & 23 deletions tests/test_events.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import json
from typing import List, Optional
from typing import List

import pytest
from loguru import logger
from pydantic import BaseModel

from ..crud import (
create_event,
Expand All @@ -12,29 +11,11 @@
)
from ..relay.event import NostrEvent
from ..relay.filter import NostrFilter
from .helpers import get_fixtures
from .conftest import EventFixture

RELAY_ID = "r1"


class EventFixture(BaseModel):
name: str
exception: Optional[str]
data: NostrEvent


@pytest.fixture
def valid_events() -> List[EventFixture]:
data = get_fixtures("events")
return [EventFixture.parse_obj(e) for e in data["valid"]]


@pytest.fixture
def invalid_events() -> List[EventFixture]:
data = get_fixtures("events")
return [EventFixture.parse_obj(e) for e in data["invalid"]]


def test_valid_event_id_and_signature(valid_events: List[EventFixture]):
for f in valid_events:
try:
Expand All @@ -50,9 +31,7 @@ def test_invalid_event_id_and_signature(invalid_events: List[EventFixture]):
f.data.check_signature()


# TODO: make them work
@pytest.mark.asyncio
@pytest.mark.xfail
async def test_valid_event_crud(valid_events: List[EventFixture]):
author = "a24496bca5dd73300f4e5d5d346c73132b7354c597fcbb6509891747b4689211"
event_id = "3219eec7427e365585d5adf26f5d2dd2709d3f0f2c0e1f79dc9021e951c67d96"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ async def test_router():
@pytest.mark.asyncio
async def test_start_and_stop():
nostrrelay_start()
nostrrelay_stop()
await nostrrelay_stop()

0 comments on commit 3dc066f

Please sign in to comment.