ble-reticulum/tests/test_installer.sh
torlando-tech 0e00fbf2d6 feat: enable BlueZ experimental mode by default to fix BLE connection issues
Fixes #3

BlueZ experimental mode is required for proper BLE connectivity. Without it,
BlueZ attempts Classic Bluetooth (BR/EDR) connections instead of BLE (LE)
connections, causing connection errors like "br-connection-profile-unavailable"
and immediate disconnections after pairing.

Changes:
- install.sh: Automatically enables BlueZ experimental mode during installation
  - Detects BlueZ version (requires >= 5.49)
  - Creates systemd override to add -E flag to bluetoothd
  - Checks if already enabled to avoid duplicate configuration
  - Shows strong warning if user skips with --skip-experimental flag
- Added --skip-experimental flag to opt-out (not recommended)
- Updated help text to document new flag
- tests/test_installer.sh: Added tests for experimental mode configuration
- README.md: Documented BlueZ experimental mode in installation sections
  - Added to automated installation description
  - Added as required step in manual installation
  - Added troubleshooting section for BR/EDR connection errors
- examples/config_example.toml: Added troubleshooting entry for BR/EDR errors

The installer now:
1. Detects BlueZ version >= 5.49 (required for experimental mode)
2. Checks if already enabled (graceful skip)
3. Enables experimental mode by default unless --skip-experimental is used
4. Shows prominent warning if skipped (may cause BLE to break)
5. Handles edge cases (no systemd, old BlueZ, container environments)

This addresses the root cause reported in issue #3 where devices were
connecting then immediately disconnecting with BR/EDR profile errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 23:25:52 -04:00

217 lines
8.1 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Integration test for install.sh on fresh Linux systems
# This script tests that install.sh works correctly on a completely fresh system
# with no prerequisites installed
# Supports: Debian, Ubuntu, Arch Linux
set -e
# Detect OS type
if command -v apt-get &> /dev/null; then
OS_TYPE="debian"
elif command -v pacman &> /dev/null; then
OS_TYPE="arch"
else
echo "ERROR: Unsupported OS (no apt-get or pacman found)"
exit 1
fi
# Configure non-interactive mode for CI/container environments
if [ "$OS_TYPE" = "debian" ]; then
# Debian/Ubuntu-specific environment setup
export DEBIAN_FRONTEND=noninteractive
export DEBCONF_NONINTERACTIVE_SEEN=true
export TZ=UTC
# Pre-configure timezone to prevent interactive prompts
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
fi
echo "=== Testing install.sh on fresh system ==="
echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')"
echo "OS Type: $OS_TYPE"
echo ""
echo "NOTE: install.sh will handle all prerequisites (Python, pip, Reticulum, etc.)"
echo ""
# Helper function: Check if a package is installed (OS-agnostic)
check_package() {
local pkg="$1"
if [ "$OS_TYPE" = "debian" ]; then
# Match package with or without architecture suffix (e.g., python3-cairo:amd64)
dpkg -l | grep -q "^ii $pkg" || { echo "FAIL: $pkg not installed"; exit 1; }
elif [ "$OS_TYPE" = "arch" ]; then
pacman -Q "$pkg" &> /dev/null || { echo "FAIL: $pkg not installed"; exit 1; }
fi
}
# Run installer - it now handles everything from basic packages to Reticulum
echo "Running install.sh (self-contained installer)..."
# Navigate to repository root (script is in tests/ directory)
cd "$(dirname "$0")/.."
chmod +x install.sh
mkdir -p /tmp/test-config
# Run non-interactively (answer 'n' to bluetooth permissions prompt)
# Note: BlueZ experimental mode will be enabled by default (no prompt)
./install.sh --config /tmp/test-config <<EOF
n
EOF
echo ""
# Verify installation
echo "=== Verifying Installation ==="
echo ""
# Check system packages
echo "Checking system packages..."
if [ "$OS_TYPE" = "debian" ]; then
check_package python3-gi
echo " ✓ python3-gi installed"
check_package python3-dbus
echo " ✓ python3-dbus installed"
check_package python3-cairo
echo " ✓ python3-cairo installed"
check_package bluez
echo " ✓ bluez installed"
elif [ "$OS_TYPE" = "arch" ]; then
# Note: python-gobject NOT installed on Arch to avoid version conflict
# PyGObject compiled from pip instead
check_package python-dbus
echo " ✓ python-dbus installed"
check_package python-cairo
echo " ✓ python-cairo installed"
check_package bluez
echo " ✓ bluez installed"
check_package bluez-utils
echo " ✓ bluez-utils installed"
fi
echo ""
# Check Python imports (verify system packages work)
echo "Checking Python module imports..."
python3 -c "import gi; print(' ✓ gi version:', gi.__version__)" || { echo "FAIL: Cannot import gi"; exit 1; }
python3 -c "import dbus; print(' ✓ dbus version:', dbus.__version__)" || { echo "FAIL: Cannot import dbus"; exit 1; }
python3 -c "import cairo; print(' ✓ cairo imported successfully')" || { echo "FAIL: Cannot import cairo"; exit 1; }
echo ""
# Check Reticulum installation
echo "Checking Reticulum installation..."
command -v rnsd || { echo "FAIL: rnsd command not found"; exit 1; }
echo " ✓ rnsd command available"
python3 -c "import RNS; print(' ✓ RNS version:', RNS.version)" || { echo "FAIL: Cannot import RNS"; exit 1; }
echo ""
# Check pip packages
echo "Checking pip-installed packages..."
python3 -c "import bleak; print(' ✓ bleak imported successfully')" || { echo "FAIL: Cannot import bleak"; exit 1; }
python3 -c "import bluezero; print(' ✓ bluezero imported successfully')" || { echo "FAIL: Cannot import bluezero"; exit 1; }
echo ""
# Check build tools status
if [ "$OS_TYPE" = "debian" ]; then
echo "Verifying no build dependencies were required..."
if dpkg -l | grep -q meson; then
echo " ⚠ WARNING: meson was installed (should not be needed)"
fi
if dpkg -l | grep -q cmake; then
echo " ⚠ WARNING: cmake was installed (should not be needed)"
fi
if dpkg -l | grep -q libglib2.0-dev; then
echo " ⚠ WARNING: libglib2.0-dev was installed (should not be needed)"
fi
echo " ✓ No build tools required"
elif [ "$OS_TYPE" = "arch" ]; then
echo "Verifying build tools installed (required on Arch for PyGObject compilation)..."
check_package base-devel
echo " ✓ base-devel installed (includes gcc, make, etc.)"
fi
echo ""
# Check files were copied
echo "Checking BLE interface files..."
test -f /tmp/test-config/interfaces/BLEInterface.py || { echo "FAIL: BLEInterface.py not installed"; exit 1; }
echo " ✓ BLEInterface.py"
test -f /tmp/test-config/interfaces/BLEGATTServer.py || { echo "FAIL: BLEGATTServer.py not installed"; exit 1; }
echo " ✓ BLEGATTServer.py"
test -f /tmp/test-config/interfaces/BLEFragmentation.py || { echo "FAIL: BLEFragmentation.py not installed"; exit 1; }
echo " ✓ BLEFragmentation.py"
test -f /tmp/test-config/interfaces/BLEAgent.py || { echo "FAIL: BLEAgent.py not installed"; exit 1; }
echo " ✓ BLEAgent.py"
echo ""
# Test import of installed BLE interface
echo "Testing BLE interface import..."
cd /tmp/test-config/interfaces
python3 -c "import sys; sys.path.insert(0, '.'); from BLEInterface import BLEInterface; print(' ✓ BLEInterface imported successfully')" || { echo "FAIL: Cannot import BLEInterface"; exit 1; }
echo ""
# Check BlueZ experimental mode configuration
echo "Checking BlueZ experimental mode..."
if command -v systemctl &> /dev/null && command -v bluetoothctl &> /dev/null; then
# systemctl is available - check if experimental mode was configured
if [ -f /etc/systemd/system/bluetooth.service.d/override.conf ]; then
echo " ✓ Systemd override file created"
if grep -q -- "-E" /etc/systemd/system/bluetooth.service.d/override.conf; then
echo " ✓ Experimental mode flag (-E) configured"
else
echo " ⚠ WARNING: Override file exists but -E flag not found"
fi
else
# No override file - may have been already enabled or not supported
if systemctl status bluetooth 2>/dev/null | grep -q -- "-E\|--experimental"; then
echo " ✓ Experimental mode already enabled (not via installer)"
else
echo " ⚠ WARNING: Experimental mode not configured"
fi
fi
else
# systemctl or bluetoothctl not available (container environment)
echo " Systemd/BlueZ not available (container environment - OK)"
fi
echo ""
# Test --skip-experimental flag
echo "Testing --skip-experimental flag..."
cd "$(dirname "$0")/.."
# Run with --skip-experimental to verify it doesn't fail
./install.sh --config /tmp/test-config-skip --skip-experimental > /tmp/skip-test.log 2>&1 <<EOF
n
EOF
# Check that warning was shown
if grep -q "WARNING: Skipping BlueZ experimental mode" /tmp/skip-test.log; then
echo " ✓ --skip-experimental flag works (warning displayed)"
else
echo " ⚠ WARNING: --skip-experimental flag may not be working correctly"
fi
echo ""
echo "=== SUCCESS: All tests passed ==="
echo ""
echo "Installation summary:"
echo " • install.sh is fully self-contained (handles all prerequisites)"
echo " • Reticulum Network Stack: installed via pip"
if [ "$OS_TYPE" = "debian" ]; then
echo " • System packages: python3, python3-pip, git, python3-gi, python3-dbus, python3-cairo, bluez"
echo " • Pip packages: rns, bleak, bluezero"
echo " • Install method: System packages (no compilation)"
echo " • Installation time: < 1 minute"
elif [ "$OS_TYPE" = "arch" ]; then
echo " • System packages: python, python-pip, git, python-dbus, python-cairo, bluez, bluez-utils, base-devel"
echo " • Pip packages: rns, bleak, bluezero, PyGObject (compiled)"
echo " • Install method: System packages + PyGObject compilation (version compatibility)"
echo " • Installation time: ~2-3 minutes (PyGObject compilation)"
fi
echo ""