ble-reticulum/TESTING.md
2025-10-26 19:14:14 -04:00

9.5 KiB

Testing Guide

This document describes how to test the Reticulum BLE Interface.

Test Suite Overview

The test suite includes:

  • Unit tests: Test individual components in isolation
  • Integration tests: Test component interactions and simulated multi-device scenarios
  • Coverage: 98+ tests covering core functionality

Quick Start

# Create and activate virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate  # On Linux/macOS

# Install test dependencies
pip install -r requirements-dev.txt

# Run all tests
pytest

# Run with verbose output
pytest -v

# Run with coverage report
pytest --cov=src/RNS/Interfaces --cov-report=html

Test Organization

Test Files

  • conftest.py - Pytest fixtures and shared test utilities
  • test_fragmentation.py - Packet fragmentation and reassembly
  • test_gatt_server.py - GATT server functionality
  • test_ble_peer_interface.py - Per-peer connection management
  • test_error_recovery.py - Error handling and recovery
  • test_prioritization.py - Connection prioritization logic
  • test_multi_device_simulation.py - Multi-node mesh simulation
  • test_integration.py - Configuration and integration tests

Running Specific Tests

# Run single test file
pytest tests/test_fragmentation.py

# Run single test function
pytest tests/test_fragmentation.py::test_fragment_single_packet

# Run tests matching pattern
pytest -k "fragment"

# Run with specific markers
pytest -m "not slow"

Test Categories

1. Fragmentation Tests

Tests for packet fragmentation and reassembly:

pytest tests/test_fragmentation.py -v

Key tests:

  • Single packet fragmentation
  • Large packet handling (multiple fragments)
  • Packet reassembly
  • Fragment ordering
  • Error cases (corrupted fragments, timeout)

2. GATT Server Tests

Tests for peripheral mode (GATT server):

pytest tests/test_gatt_server.py -v

Key tests:

  • GATT server initialization
  • Service registration
  • Characteristic read/write
  • Notification handling
  • Multiple client connections

3. Connection Management Tests

Tests for peer discovery and connection:

pytest tests/test_ble_peer_interface.py -v

Key tests:

  • Peer discovery
  • Connection establishment
  • Disconnection handling
  • Connection state management
  • Data transmission

4. Error Recovery Tests

Tests for error handling:

pytest tests/test_error_recovery.py -v

Key tests:

  • Connection timeout handling
  • Retry logic
  • Exponential backoff
  • Blacklist management
  • Recovery from errors

5. Prioritization Tests

Tests for connection prioritization:

pytest tests/test_prioritization.py -v

Key tests:

  • RSSI-based scoring
  • Connection history tracking
  • Peer selection algorithm
  • Blacklist expiration

6. Multi-Device Simulation

Tests for multi-node mesh networking:

pytest tests/test_multi_device_simulation.py -v

Key tests:

  • Multiple simultaneous connections
  • Packet routing through mesh
  • Network topology changes
  • Connection rotation

Coverage

Generate Coverage Report

# HTML report (recommended)
pytest --cov=src/RNS/Interfaces --cov-report=html
# Open htmlcov/index.html in browser

# Terminal report
pytest --cov=src/RNS/Interfaces --cov-report=term-missing

# XML report (for CI)
pytest --cov=src/RNS/Interfaces --cov-report=xml

Coverage Goals

  • Overall coverage: >90%
  • Core modules (BLEInterface, BLEFragmentation): >95%
  • Error handling paths: >85%

Integration Testing

Prerequisites

For integration testing with real BLE hardware:

  • 2+ BLE-enabled devices (e.g., Raspberry Pi Zero W)
  • BlueZ 5.x installed
  • Devices on same network (for coordination)

Setup

  1. Install on each device:

    pip install -r requirements.txt
    cp src/RNS/Interfaces/BLE*.py ~/.reticulum/interfaces/
    
  2. Configure interface on each device (same service_uuid):

    [[BLE Interface]]
      type = BLEInterface
      enabled = yes
      device_name = Device-1  # Unique per device
      service_uuid = 00000001-5824-4f48-9e1a-3b3e8f0c1234
    
  3. Start Reticulum on each device:

    rnsd --verbose
    

Integration Test Scenarios

Test 1: Peer Discovery

Objective: Verify devices discover each other

  1. Start rnsd on both devices
  2. Monitor logs for discovery messages
  3. Verify: Each device discovers the other within 10 seconds

Expected output:

[2025-10-26 10:00:15] [INFO] Discovered peer: Device-2 (RSSI: -65 dBm)

Test 2: Connection Establishment

Objective: Verify devices connect successfully

  1. Wait for discovery
  2. Monitor logs for connection
  3. Check rnstatus for active connections

Expected output:

BLE Interface [Enabled]
  Peers: 1 connected, 0 discovered
  Active connections: Device-2 (RSSI: -65 dBm)

Test 3: Packet Exchange

Objective: Verify data transmission

  1. Establish connection
  2. Send announces from one device
  3. Monitor reception on other device
# On Device 1
rnid -a

# On Device 2 - should receive announce
tail -f ~/.reticulum/logfile

Test 4: Multi-Hop Routing

Objective: Verify mesh routing (requires 3+ devices)

  1. Place devices in line: A <-> B <-> C
  2. Ensure A and C can only connect via B
  3. Send packets from A to C
  4. Verify routing through B

Test 5: Connection Recovery

Objective: Verify reconnection after disconnection

  1. Establish connection
  2. Move devices out of range or restart one device
  3. Return to range
  4. Verify: Automatic reconnection within 60 seconds

Performance Testing

Throughput Test

Measure packet transmission rate:

# Run from examples/
python ble_minimal_test.py test

Expected results:

  • BLE 4.2 (185 byte MTU): ~15-20 KB/s
  • BLE 5.0 (512 byte MTU): ~30-40 KB/s

Latency Test

Measure round-trip time:

  1. Send echo request from Device A
  2. Device B responds immediately
  3. Measure time from send to receive

Expected latency:

  • Local (same room): 50-200ms
  • Medium range (10-15m): 100-500ms

Connection Scaling

Test maximum connections:

  1. Configure max_connections = 7
  2. Connect 7 devices simultaneously
  3. Verify all connections stable

Expected: All 7 connections maintained for >5 minutes

Troubleshooting Tests

Test Not Running

Problem: Pytest can't find tests

Solution:

# Ensure you're in project root
cd /path/to/ble-reticulum

# Run from root directory
pytest

# Or specify path explicitly
pytest tests/

Import Errors

Problem: ModuleNotFoundError: No module named 'RNS'

Solution:

# Install in development mode
pip install -e .

# Or set PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)/src"
pytest

Async Warnings

Problem: Warnings about unclosed asyncio resources

Solution: These are usually harmless in tests, but can be suppressed:

pytest -W ignore::DeprecationWarning

BLE Hardware Tests Skipped

Problem: Integration tests marked as skipped

Reason: Unit tests don't require real BLE hardware (they use mocks)

Info: This is expected behavior. Integration tests with real hardware should be run manually.

Continuous Integration

GitHub Actions

The repository includes CI configuration in .github/workflows/test.yml:

  • Runs on: Python 3.8, 3.9, 3.10, 3.11
  • Tests: All unit tests
  • Coverage: Generates coverage report
  • Linting: Code style checks (if configured)

Running Locally

Simulate CI environment:

# Test on specific Python version
python3.9 -m pytest

# Test with clean environment
python -m venv test-env
source test-env/bin/activate
pip install -r requirements-dev.txt
pytest
deactivate

Test Development

Writing New Tests

  1. Create test file in tests/ directory
  2. Import required fixtures from conftest.py
  3. Write test functions (prefix with test_)
  4. Use descriptive names and docstrings

Example:

import pytest
from RNS.Interfaces.BLEFragmentation import BLEFragmenter

def test_fragmenter_handles_empty_packet():
    """Test that fragmenter raises error for empty packets"""
    fragmenter = BLEFragmenter(mtu=185)

    with pytest.raises(ValueError, match="empty"):
        fragmenter.fragment_packet(b"")

Using Fixtures

Common fixtures available in conftest.py:

def test_with_fragmenter(ble_fragmenter):
    """Use fragmenter fixture from conftest.py"""
    fragments = ble_fragmenter.fragment_packet(b"test data")
    assert len(fragments) >= 1

Async Tests

For async code:

import pytest

@pytest.mark.asyncio
async def test_async_operation():
    """Test asynchronous BLE operations"""
    result = await some_async_function()
    assert result is not None

Best Practices

  1. Run tests before committing

    pytest
    
  2. Check coverage for new code

    pytest --cov=src/RNS/Interfaces --cov-report=term-missing
    
  3. Test both success and failure cases

    • Happy path
    • Error conditions
    • Edge cases
  4. Use meaningful assertions

    # Good
    assert len(fragments) == 3, "Expected 3 fragments for 500-byte packet"
    
    # Less helpful
    assert len(fragments) == 3
    
  5. Keep tests independent

    • Each test should work in isolation
    • Don't rely on test execution order
    • Clean up resources in teardown

Additional Resources

Questions?

If you have questions about testing, please open an issue with the testing label.