Files
meshcore-bot/tests
agessaman 2a1c2f86d8 feat(web_viewer): rebuild Real-time as one tape of what the radio heard
Real-time was three equal panels (commands, packets, messages) that each scrolled on their own, couldn't be held still, and showed the same transmission up to three times. It's now one tape with one row per transmission: a packet, the channel message decrypted from it and a command it triggered share a row, joined by packet hash, and the bot's reply hangs under the command with how many times a repeater was heard echoing it. Those echoes fold into the reply instead of getting rows of their own, and a packet heard several times is one row with a count and every reception (SNR, RSSI, hops, path) when opened.

A receiver strip at the top says whether the bot is listening or the radio is offline or not responding (from the banner poll base.html already runs, now published as a banner-status event), when it last heard a packet, the packet rate and a 10-minute activity bar. The tape holds still while you read it: Pause (P), scrolling down, a moving mouse pointer or keyboard focus queue new rows behind an "N new" button. Rows can be kept (safe from the 300-row limit and from Clear), filtered to messages or commands, by packet type or channel, and searched (/). Replayed history sits under a "Heard before you opened this page" divider, and adverts and keyed group text are decoded in the browser and labeled as such. Each row's glyph chip carries its packet type's icon in the dashboard chart's color for that type; decoded messages get a stronger tint, and the bot's commands and replies are violet.

Server side, command rows carry trigger_packet_hash (from the message's routing info) and, once the transmission tracker matches a repeat, reply_packet_hash. Replayed rows carry stream_ts and replayed, and live rows stream_ts. Commands stored before this pair with their message only on an exact sender, channel and text match within 20 seconds.

Real-time is admin-only now: its socket already was, so anonymous visitors got three "Admin login required" badges over spinners that never filled. They're redirected to login and the nav link is hidden from them.

The byte breakdown sliced multibyte paths by hop count, so 2- and 3-byte hops spilled into the payload; it uses the path's byte count and shows the raw path-length byte. Route types 0 and 2 were swapped, and the channel key store was often built before the decoder had loaded, so it never decrypted anything. js-sha256 is vendored under static/vendor instead of loading from cdnjs.
2026-10-17 19:40:23 -07:00
..
…

MeshCore Bot Test Suite

This directory contains the test suite for the MeshCore Bot, focusing on graph-based path guessing functionality.

Structure

tests/
├── README.md              # This file
├── conftest.py            # Pytest fixtures and configuration
├── helpers.py             # Test data factories and helper functions
├── unit/                  # Unit tests (isolated, with mocks)
│   ├── test_mesh_graph_edges.py
│   ├── test_mesh_graph_validation.py
│   ├── test_mesh_graph_scoring.py
│   ├── test_mesh_graph_multihop.py
│   └── test_path_command_graph_selection.py
└── integration/          # Integration tests (with real database)
    └── test_path_resolution.py

Running Tests

Run all tests

pytest

Run only unit tests

pytest tests/unit/

Run only integration tests

pytest tests/integration/

Run specific test file

pytest tests/unit/test_mesh_graph_edges.py

Run specific test

pytest tests/unit/test_mesh_graph_edges.py::TestMeshGraphEdges::test_add_new_edge

Run with coverage

pytest --cov=modules --cov-report=html --cov-report=term-missing

Run with verbose output

pytest -v

Run with markers

pytest -m unit          # Run only unit tests
pytest -m integration  # Run only integration tests
pytest -m slow          # Run slow tests

Test Coverage

Unit Tests

test_mesh_graph_edges.py (15 tests)

Tests for MeshGraph edge management:

  • Adding new edges
  • Updating existing edges
  • Public key handling
  • Hop position tracking
  • Geographic distance
  • Edge queries (get, has, outgoing, incoming)
  • Prefix normalization

test_mesh_graph_validation.py (12 tests)

Tests for path validation:

  • Path segment validation
  • Confidence calculation
  • Recency checks
  • Bidirectional edge validation
  • Full path validation
  • Minimum observations filtering

test_mesh_graph_scoring.py (11 tests)

Tests for candidate scoring:

  • Score calculation with various edge combinations
  • Bidirectional bonuses
  • Hop position matching
  • Geographic distance bonuses
  • Minimum observations filtering

test_mesh_graph_multihop.py (12 tests)

Tests for multi-hop path inference:

  • 2-hop and 3-hop path finding
  • Intermediate node discovery
  • Minimum observations filtering
  • Bidirectional path bonuses
  • Score reduction for longer paths

test_path_command_graph_selection.py (8 tests)

Tests for PathCommand._select_repeater_by_graph:

  • Direct edge selection
  • Stored public key bonus
  • Star bias multiplier
  • Multi-hop inference
  • Confidence conversion

Integration Tests

test_path_resolution.py (5 tests)

End-to-end tests for full path resolution:

  • Path resolution with graph edges from database
  • Prefix collision resolution using graph data
  • Edge persistence across graph restarts
  • Graph vs geographic selection
  • Real-world multi-hop scenarios

Test Fixtures

Fixtures are defined in conftest.py:

  • mock_logger: Mock logger for testing
  • test_config: Test configuration with Path_Command settings
  • test_db: In-memory SQLite database for testing
  • mock_bot: Mock bot instance with all necessary attributes
  • mesh_graph: Clean MeshGraph instance for testing
  • populated_mesh_graph: MeshGraph instance with sample edges

Test Helpers

Helper functions in helpers.py:

  • create_test_repeater(): Factory for creating test repeater data
  • create_test_edge(): Factory for creating test edge data
  • create_test_path(): Factory for creating test path data
  • populate_test_graph(): Helper to populate a graph with test edges

Writing New Tests

Unit Test Example

import pytest
from tests.helpers import create_test_edge

@pytest.mark.unit
class TestMyFeature:
    def test_my_feature(self, mesh_graph):
        """Test description."""
        mesh_graph.add_edge('01', '7e')
        assert mesh_graph.has_edge('01', '7e')

Integration Test Example

import pytest

@pytest.mark.integration
class TestMyIntegration:
    def test_my_integration(self, mock_bot, test_db):
        """Test description."""
        # Use real database and bot components
        pass

Test Markers

Tests are marked with:

  • @pytest.mark.unit: Unit tests (isolated, with mocks)
  • @pytest.mark.integration: Integration tests (with real database)
  • @pytest.mark.slow: Slow-running tests

Dependencies

Test dependencies are in requirements.txt:

  • pytest>=7.0.0
  • pytest-asyncio>=0.21.0
  • pytest-mock>=3.10.0
  • pytest-cov>=4.0.0

Configuration

Pytest configuration is in pytest.ini:

  • Test discovery patterns
  • Async test support
  • Output options
  • Test markers

Notes

  • Unit tests use in-memory SQLite databases for speed
  • Integration tests may use real database connections
  • All tests should be deterministic and not depend on external services
  • Tests should clean up after themselves (fixtures handle this automatically)