Files
meshcore-bot/tests/unit/test_mesh_graph_multihop.py
T
Stacy Olivas ae57e651ea test: expanded test suite for v0.9.0 modules
Command tests:
- tests/commands/: test_base_command, test_cmd_command, test_dice_command,
  test_hello_command, test_help_command, test_magic8_command,
  test_ping_command, test_roll_command
- tests/test_bridge_bot_responses, test_channel_manager_logic,
  test_checkin_service, test_command_manager, test_command_prefix,
  test_config_merge, test_config_validation, test_db_manager,
  test_plugin_loader, test_profanity_filter, test_security_utils,
  test_service_plugin_loader, test_utils

Integration and unit:
- tests/integration/: test_path_graph_integration, test_path_resolution
- tests/regression/: test_keyword_escapes
- tests/unit/: test_mesh_graph, test_mesh_graph_edges,
  test_mesh_graph_multihop, test_mesh_graph_optimizations,
  test_mesh_graph_scoring, test_mesh_graph_validation,
  test_path_command_graph, test_path_command_graph_selection,
  test_path_command_multibyte

Helpers: tests/conftest.py, tests/helpers.py
2026-03-17 18:07:18 -07:00

158 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for MeshGraph multi-hop inference
"""
import pytest
@pytest.mark.unit
class TestMeshGraphMultiHop:
"""Test MeshGraph multi-hop inference functionality."""
def test_find_intermediate_nodes_direct_edge(self, mesh_graph):
"""Test that direct edges are not returned as intermediate nodes."""
mesh_graph.add_edge('01', '7e')
candidates = mesh_graph.find_intermediate_nodes('01', '7e')
# Direct edge exists, so no intermediate nodes should be returned
assert len(candidates) == 0
def test_find_intermediate_nodes_2hop_path(self, mesh_graph):
"""Test finding intermediate nodes in a 2-hop path."""
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
candidates = mesh_graph.find_intermediate_nodes('01', '86')
assert len(candidates) > 0
assert candidates[0][0] == '7e' # Intermediate node
assert candidates[0][1] > 0.0 # Has score
def test_find_intermediate_nodes_3hop_path(self, mesh_graph):
"""Test finding intermediate nodes in a 3-hop path."""
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('86', 'e0')
candidates = mesh_graph.find_intermediate_nodes('01', 'e0', max_hops=3)
assert len(candidates) > 0
# Should return '86' (the node before destination in 3-hop path)
assert candidates[0][0] == '86'
assert candidates[0][1] > 0.0
def test_find_intermediate_nodes_no_path(self, mesh_graph):
"""Test that no candidates are returned when no path exists."""
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('86', 'e0') # Disconnected components
candidates = mesh_graph.find_intermediate_nodes('01', 'e0')
assert len(candidates) == 0
def test_find_intermediate_nodes_min_observations(self, mesh_graph):
"""Test that min_observations filter is applied."""
mesh_graph.add_edge('01', '7e') # Only 1 observation
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('7e', '86') # Ensure 7e->86 has 2 observations
# With min_observations=3, should find no candidates (both edges need 3+)
candidates = mesh_graph.find_intermediate_nodes('01', '86', min_observations=3)
assert len(candidates) == 0
# Add more observations to both edges
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('01', '7e') # Now 01->7e has 3 observations
mesh_graph.add_edge('7e', '86') # Now 7e->86 has 3 observations
candidates = mesh_graph.find_intermediate_nodes('01', '86', min_observations=3)
assert len(candidates) > 0
def test_find_intermediate_nodes_bidirectional_bonus(self, mesh_graph):
"""Test that bidirectional paths get higher scores."""
# Unidirectional path
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
candidates_uni = mesh_graph.find_intermediate_nodes('01', '86')
# Add reverse edges (bidirectional)
mesh_graph.add_edge('7e', '01')
mesh_graph.add_edge('86', '7e')
candidates_bi = mesh_graph.find_intermediate_nodes('01', '86')
assert len(candidates_bi) > 0
assert candidates_bi[0][1] > candidates_uni[0][1]
def test_find_intermediate_nodes_multiple_candidates(self, mesh_graph):
"""Test finding multiple intermediate node candidates."""
# Path 1: 01 -> 7e -> 86
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
# Path 2: 01 -> 7a -> 86
mesh_graph.add_edge('01', '7a')
mesh_graph.add_edge('7a', '86')
candidates = mesh_graph.find_intermediate_nodes('01', '86')
assert len(candidates) >= 2
# Should be sorted by score (highest first)
scores = [c[1] for c in candidates]
assert scores == sorted(scores, reverse=True)
def test_find_intermediate_nodes_3hop_score_reduction(self, mesh_graph):
"""Test that 3-hop paths have reduced scores."""
# 2-hop path
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
candidates_2hop = mesh_graph.find_intermediate_nodes('01', '86', max_hops=2)
# 3-hop path
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('86', 'e0')
candidates_3hop = mesh_graph.find_intermediate_nodes('01', 'e0', max_hops=3)
# 3-hop should have lower score due to 0.8 multiplier
if len(candidates_2hop) > 0 and len(candidates_3hop) > 0:
# Both paths exist, 3-hop should be lower
assert candidates_3hop[0][1] < candidates_2hop[0][1]
def test_find_intermediate_nodes_max_hops_limit(self, mesh_graph):
"""Test that max_hops parameter limits search depth."""
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('86', 'e0')
# With max_hops=2, should not find 3-hop path
candidates = mesh_graph.find_intermediate_nodes('01', 'e0', max_hops=2)
assert len(candidates) == 0
# With max_hops=3, should find it
candidates = mesh_graph.find_intermediate_nodes('01', 'e0', max_hops=3)
assert len(candidates) > 0
def test_find_intermediate_nodes_weakest_link_scoring(self, mesh_graph):
"""Test that path score uses weakest link (minimum confidence)."""
# Create path where one edge has low confidence
mesh_graph.add_edge('01', '7e') # 1 observation
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('7e', '86')
mesh_graph.add_edge('7e', '86') # 3 observations
candidates = mesh_graph.find_intermediate_nodes('01', '86')
assert len(candidates) > 0
# Score should be limited by the weaker edge (01->7e)
score = candidates[0][1]
assert score < 1.0 # Should be less than perfect due to weak link
def test_find_intermediate_nodes_self_loop_prevention(self, mesh_graph):
"""Test that paths don't loop back to source."""
mesh_graph.add_edge('01', '7e')
mesh_graph.add_edge('7e', '01') # Loop back
mesh_graph.add_edge('7e', '86')
candidates = mesh_graph.find_intermediate_nodes('01', '86')
# Should still find valid path through 7e
assert len(candidates) > 0
assert candidates[0][0] == '7e'