mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-05-24 10:35:19 +00:00
184 lines
6.0 KiB
Python
184 lines
6.0 KiB
Python
# SPDX-License-Identifier: 0BSD
|
|
|
|
import json
|
|
import shutil
|
|
import tempfile
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
import RNS
|
|
|
|
from meshchatx.meshchat import ReticulumMeshChat
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_dir():
|
|
dir_path = tempfile.mkdtemp()
|
|
yield dir_path
|
|
shutil.rmtree(dir_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_rns_minimal():
|
|
with (
|
|
patch("RNS.Reticulum") as mock_rns,
|
|
patch("RNS.Transport"),
|
|
patch("LXMF.LXMRouter"),
|
|
patch("meshchatx.meshchat.get_file_path", return_value="/tmp/mock_path"),
|
|
):
|
|
mock_rns_instance = mock_rns.return_value
|
|
mock_rns_instance.configpath = "/tmp/mock_config"
|
|
mock_rns_instance.is_connected_to_shared_instance = False
|
|
mock_rns_instance.transport_enabled.return_value = True
|
|
|
|
mock_id = MagicMock(spec=RNS.Identity)
|
|
mock_id.hash = b"test_hash_32_bytes_long_01234567"
|
|
mock_id.hexhash = mock_id.hash.hex()
|
|
mock_id.get_private_key.return_value = b"test_private_key"
|
|
yield mock_id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_favourites_import(mock_rns_minimal, temp_dir):
|
|
with patch("meshchatx.meshchat.generate_ssl_certificate"):
|
|
app = ReticulumMeshChat(
|
|
identity=mock_rns_minimal,
|
|
storage_dir=temp_dir,
|
|
reticulum_config_dir=temp_dir,
|
|
)
|
|
handler = None
|
|
for route in app.get_routes():
|
|
if route.path == "/api/v1/favourites/import" and route.method == "POST":
|
|
handler = route.handler
|
|
break
|
|
assert handler is not None
|
|
|
|
request = MagicMock()
|
|
request.json = AsyncMock(
|
|
return_value={
|
|
"favourites": [
|
|
{
|
|
"destination_hash": "a" * 32,
|
|
"display_name": "Node A",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
{
|
|
"destination_hash": "b" * 32,
|
|
"display_name": "Node B",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
],
|
|
},
|
|
)
|
|
response = await handler(request)
|
|
data = json.loads(response.body)
|
|
assert data["imported"] == 2
|
|
assert data["skipped"] == 0
|
|
|
|
rows = app.database.announces.get_favourites(aspect="nomadnetwork.node")
|
|
assert len(rows) == 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_favourites_import_skips_invalid(mock_rns_minimal, temp_dir):
|
|
with patch("meshchatx.meshchat.generate_ssl_certificate"):
|
|
app = ReticulumMeshChat(
|
|
identity=mock_rns_minimal,
|
|
storage_dir=temp_dir,
|
|
reticulum_config_dir=temp_dir,
|
|
)
|
|
handler = None
|
|
for route in app.get_routes():
|
|
if route.path == "/api/v1/favourites/import" and route.method == "POST":
|
|
handler = route.handler
|
|
break
|
|
assert handler is not None
|
|
|
|
request = MagicMock()
|
|
request.json = AsyncMock(
|
|
return_value={
|
|
"favourites": [
|
|
{
|
|
"destination_hash": "a" * 32,
|
|
"display_name": "Node A",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
{"display_name": "Missing hash"},
|
|
{"destination_hash": "b" * 32, "aspect": None},
|
|
],
|
|
},
|
|
)
|
|
response = await handler(request)
|
|
data = json.loads(response.body)
|
|
assert data["imported"] == 1
|
|
assert data["skipped"] == 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_favourites_import_deduplicates(mock_rns_minimal, temp_dir):
|
|
with patch("meshchatx.meshchat.generate_ssl_certificate"):
|
|
app = ReticulumMeshChat(
|
|
identity=mock_rns_minimal,
|
|
storage_dir=temp_dir,
|
|
reticulum_config_dir=temp_dir,
|
|
)
|
|
handler = None
|
|
for route in app.get_routes():
|
|
if route.path == "/api/v1/favourites/import" and route.method == "POST":
|
|
handler = route.handler
|
|
break
|
|
assert handler is not None
|
|
|
|
request = MagicMock()
|
|
request.json = AsyncMock(
|
|
return_value={
|
|
"favourites": [
|
|
{
|
|
"destination_hash": "a" * 32,
|
|
"display_name": "First",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
{
|
|
"destination_hash": "a" * 32,
|
|
"display_name": "Second",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
{
|
|
"destination_hash": "b" * 32,
|
|
"display_name": "Node B",
|
|
"aspect": "nomadnetwork.node",
|
|
},
|
|
],
|
|
},
|
|
)
|
|
response = await handler(request)
|
|
data = json.loads(response.body)
|
|
assert data["imported"] == 2
|
|
assert data["skipped"] == 0
|
|
|
|
rows = app.database.announces.get_favourites(aspect="nomadnetwork.node")
|
|
assert len(rows) == 2
|
|
names = {r["display_name"] for r in rows}
|
|
assert names == {"Second", "Node B"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_favourites_import_rejects_non_array(mock_rns_minimal, temp_dir):
|
|
with patch("meshchatx.meshchat.generate_ssl_certificate"):
|
|
app = ReticulumMeshChat(
|
|
identity=mock_rns_minimal,
|
|
storage_dir=temp_dir,
|
|
reticulum_config_dir=temp_dir,
|
|
)
|
|
handler = None
|
|
for route in app.get_routes():
|
|
if route.path == "/api/v1/favourites/import" and route.method == "POST":
|
|
handler = route.handler
|
|
break
|
|
assert handler is not None
|
|
|
|
request = MagicMock()
|
|
request.json = AsyncMock(return_value={"favourites": "not an array"})
|
|
response = await handler(request)
|
|
assert response.status == 400
|