Files
meshcore-bot/tests/unit/test_path_command_lookup.py
T
agessaman 9b437efb05 feat(utils): add public_key_has_prefix function and refactor path command logic
- Introduced a new utility function `public_key_has_prefix` to check if a public key starts with a specified prefix in a case-insensitive manner.
- Updated the `PathCommand` class to utilize the new utility function for public key prefix matching, enhancing code readability and maintainability.
- Refactored logic in `PathCommand` and `BotDataViewer` to streamline the handling of recent repeaters based on recency scores, improving clarity in the filtering process.
2026-06-01 15:27:27 -07:00

117 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Unit tests for PathCommand repeater lookup (recency filter and prefix matching)."""
from datetime import datetime, timedelta
from unittest.mock import AsyncMock, Mock
import pytest
from modules.commands.path_command import PathCommand
from modules.utils import public_key_has_prefix
from tests.helpers import create_test_repeater
@pytest.mark.unit
class TestPublicKeyHasPrefix:
def test_case_insensitive_match(self):
assert public_key_has_prefix("155eabcd", "155E") is True
assert public_key_has_prefix("155EABCD", "155e") is True
def test_empty_inputs(self):
assert public_key_has_prefix("", "155E") is False
assert public_key_has_prefix("155eabcd", "") is False
@pytest.mark.unit
class TestPathCommandLookupRecency:
@pytest.fixture
def path_command(self, mock_bot):
cmd = PathCommand(mock_bot)
cmd.graph_based_validation = False
cmd.geographic_guessing_enabled = False
return cmd
@pytest.mark.asyncio
async def test_single_stale_repeater_resolves(self, path_command):
stale = datetime.now() - timedelta(days=30)
def lookup(node_id):
return [
create_test_repeater(
prefix="15",
name="Stale Repeater",
public_key="155e" + "ab" * 31,
last_heard=stale,
last_advert_timestamp=stale,
)
]
result = await path_command._lookup_repeater_names(["155E"], lookup_func=lookup)
assert result["155E"]["found"] is True
assert result["155E"]["collision"] is False
assert result["155E"]["name"] == "Stale Repeater"
@pytest.mark.asyncio
async def test_multiple_stale_repeaters_remain_unknown(self, path_command):
stale = datetime.now() - timedelta(days=30)
def lookup(node_id):
return [
create_test_repeater(
prefix="15",
name="Stale A",
public_key="155e" + "11" * 31,
last_heard=stale,
last_advert_timestamp=stale,
),
create_test_repeater(
prefix="15",
name="Stale B",
public_key="155e" + "22" * 31,
last_heard=stale,
last_advert_timestamp=stale,
),
]
result = await path_command._lookup_repeater_names(["155E"], lookup_func=lookup)
assert result["155E"]["found"] is False
@pytest.mark.asyncio
async def test_case_insensitive_repeater_manager_match(self, mock_bot):
mock_bot.repeater_manager.get_repeater_devices = AsyncMock(
return_value=[
{
"public_key": "155e" + "ab" * 31,
"name": "Repeater 155E",
"device_type": "repeater",
"last_heard": datetime.now() - timedelta(days=30),
"last_advert_timestamp": datetime.now() - timedelta(days=30),
"is_currently_tracked": False,
"latitude": 47.6,
"longitude": -122.3,
"city": "Seattle",
"state": "WA",
"country": "USA",
"advert_count": 1,
"signal_strength": None,
"snr": None,
"hop_count": 0,
"role": "repeater",
"is_starred": 0,
}
]
)
mock_bot.meshcore = Mock()
mock_bot.meshcore.contacts = {}
path_command = PathCommand(mock_bot)
path_command.graph_based_validation = False
path_command.geographic_guessing_enabled = False
result = await path_command._lookup_repeater_names(["155E"])
assert result["155E"]["found"] is True
assert result["155E"]["name"] == "Repeater 155E"