470 lines
9.5 KiB
Markdown
470 lines
9.5 KiB
Markdown
|
|
# 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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
```bash
|
||
|
|
pip install -r requirements.txt
|
||
|
|
cp src/RNS/Interfaces/BLE*.py ~/.reticulum/interfaces/
|
||
|
|
```
|
||
|
|
|
||
|
|
2. Configure interface on each device (same `service_uuid`):
|
||
|
|
```toml
|
||
|
|
[[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:
|
||
|
|
```bash
|
||
|
|
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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
|
||
|
|
```python
|
||
|
|
# 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**:
|
||
|
|
```bash
|
||
|
|
# 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**:
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
|
||
|
|
```python
|
||
|
|
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`:
|
||
|
|
|
||
|
|
```python
|
||
|
|
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:
|
||
|
|
|
||
|
|
```python
|
||
|
|
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**
|
||
|
|
```bash
|
||
|
|
pytest
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Check coverage for new code**
|
||
|
|
```bash
|
||
|
|
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**
|
||
|
|
```python
|
||
|
|
# 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
|
||
|
|
|
||
|
|
- [pytest documentation](https://docs.pytest.org/)
|
||
|
|
- [pytest-asyncio documentation](https://pytest-asyncio.readthedocs.io/)
|
||
|
|
- [Coverage.py documentation](https://coverage.readthedocs.io/)
|
||
|
|
|
||
|
|
## Questions?
|
||
|
|
|
||
|
|
If you have questions about testing, please open an issue with the `testing` label.
|