basic working mvp
This commit is contained in:
2026-10-07 15:12:38 +03:00
parent 785a6980f6
commit fac12b2ea8
24 changed files with 1696 additions and 1 deletions

92
tests/test_router.py Normal file
View File

@@ -0,0 +1,92 @@
"""Инварианты графа маршрутов и выбор полезной нагрузки при пересылке."""
import asyncio
from copy import deepcopy
import pytest
@pytest.fixture
def router():
"""Создаёт настоящий Router независимо от менеджера и сессий."""
from router import Router
return Router()
class Node:
def __init__(self, last_data=None):
self.last_data = last_data or {}
self.sent = []
def send(self, packet):
self.sent.append(deepcopy(packet))
def test_add_creates_empty_routes_and_preserves_existing_edges(router):
"""Проверяет создание множества маршрутов и сохранение связей при повторном add."""
router.add(1)
assert router.session_routes[1] == set()
router.session_routes[1].add(2)
router.add(1)
assert router.session_routes[1] == {2}
def test_move_rewrites_only_edges_pointing_to_old_uid(router):
"""Проверяет перенос исходящих/входящих связей без изменения несвязанных маршрутов."""
router.session_routes = {1: {2}, 2: {1, 4}, 3: set(), 4: {2}, 5: set()}
router.move(1, 5)
assert router.session_routes == {2: {5, 4}, 3: set(), 4: {2}, 5: {2}}
def test_move_handles_self_route(router):
"""Проверяет замену UID в маршруте, который указывал на собственную сессию."""
router.session_routes = {1: {1, 2}, 2: {1}}
router.move(1, 3)
assert router.session_routes == {2: {3}, 3: {3, 2}}
def test_move_missing_uid_does_not_change_graph(router):
"""Проверяет безопасный перенос отсутствующего UID без добавления новых связей."""
router.session_routes = {1: {2}, 2: set()}
before = deepcopy(router.session_routes)
router.move(99, 100)
assert router.session_routes == before
def test_remove_clears_outgoing_and_incoming_edges(router):
"""Проверяет удаление узла и всех ссылок на него после окончательной очистки."""
router.session_routes = {1: {2}, 2: {1, 3}, 3: {1}, 4: set()}
router.remove(1)
assert router.session_routes == {2: {3}, 3: set(), 4: set()}
def test_remove_missing_uid_is_safe(router):
"""Проверяет повторное удаление уже отсутствующего UID."""
router.session_routes = {1: set()}
router.remove(99)
assert router.session_routes == {1: set()}
def test_process_delivers_source_payload_to_each_target(router):
"""Проверяет fan-out, данные отправителя и отсутствие доставки несвязанным узлам."""
nodes = {
1: Node({"telemetry": {"battery": 87}}),
2: Node({"telemetry": {"battery": 1}}),
3: Node(),
4: Node(),
}
router.sessions = nodes
router.session_routes = {1: {2, 3}, 2: set(), 3: set(), 4: set()}
asyncio.run(router.process(1, "telemetry"))
expected = [{"command": "telemetry", "payload": {"battery": 87}}]
assert nodes[2].sent == expected
assert nodes[3].sent == expected
assert nodes[1].sent == nodes[4].sent == []
def test_process_with_no_routes_sends_nothing(router):
"""Проверяет отсутствие доставки при пустом множестве получателей."""
router.sessions = {1: Node({"telemetry": {"battery": 87}}), 2: Node()}
router.session_routes = {1: set(), 2: set()}
asyncio.run(router.process(1, "telemetry"))
assert router.sessions[1].sent == router.sessions[2].sent == []