diff --git a/.claude/commands/fix-ci.md b/.claude/commands/fix-ci.md new file mode 100644 index 0000000..2af0629 --- /dev/null +++ b/.claude/commands/fix-ci.md @@ -0,0 +1,10 @@ +Check the GitHub Actions CI status and fix any failures: + +1. Use `gh run list --limit 1` to get the latest run +2. Use `gh run view --log` to see what failed +3. Analyze the error logs +4. Fix the issues in the code +5. Run tests locally to verify +6. Commit and push the fix +7. Monitor the new CI run with `gh run watch` +8. If it fails again, iterate until it passes diff --git a/.claude/commands/fix-issue.md b/.claude/commands/fix-issue.md new file mode 100644 index 0000000..9dc77a1 --- /dev/null +++ b/.claude/commands/fix-issue.md @@ -0,0 +1,8 @@ +Please analyze and fix the GitHub issue: $ARGUMENTS. Follow these steps: +1. Use `gh issue view` to get the issue details +2. Understand the problem described in the issue +3. Search the codebase for relevant files +4. Implement the necessary changes to fix the issue +5. Run tests to verify the fix works +6. Create a PR with `gh pr create` with a clear description +7. Link the PR to the issue diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 60f5a7e..1e910ae 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -137,7 +137,7 @@ jobs: mkdir -p ~/.reticulum/interfaces || exit 1 echo ' [6/8] Copying interface files...' - cp -v src/RNS/Interfaces/*.py ~/.reticulum/interfaces/ || exit 1 + cp -v src/ble_reticulum/*.py ~/.reticulum/interfaces/ || exit 1 echo ' [7/8] Stopping rnsd and clearing logs...' RNSD_BIN=\"\$HOME/.local/bin/rnsd\" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f2e528..4b6e8cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -155,9 +155,7 @@ jobs: pip install rns bleak bluezero dbus-python - name: Create package structure - run: | - touch src/RNS/__init__.py - touch src/RNS/Interfaces/__init__.py + run: touch src/ble_reticulum/__init__.py - name: Run tests run: | @@ -165,7 +163,7 @@ jobs: --ignore=tests/test_v2_2_identity_handshake.py \ --ignore=tests/test_v2_2_mac_sorting.py \ --ignore=tests/test_v2_2_race_conditions.py \ - --cov=src/RNS/Interfaces \ + --cov=src/ble_reticulum \ --cov-report=term-missing \ --tb=short diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2744c37..7dfc077 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -80,15 +80,13 @@ jobs: pip install rns bleak bluezero dbus-python - name: Create package structure - run: | - touch src/RNS/__init__.py - touch src/RNS/Interfaces/__init__.py + run: touch src/ble_reticulum/__init__.py - name: Run unit tests run: | # Run only unit tests (fragmentation and prioritization) python -m pytest tests/test_fragmentation.py tests/test_prioritization.py -v \ - --cov=src/RNS/Interfaces/BLEFragmentation.py \ + --cov=src/ble_reticulum/BLEFragmentation.py \ --cov-report=term-missing \ --cov-report=xml:coverage-unit.xml continue-on-error: false @@ -133,9 +131,7 @@ jobs: pip install rns bleak bluezero dbus-python - name: Create package structure - run: | - touch src/RNS/__init__.py - touch src/RNS/Interfaces/__init__.py + run: touch src/ble_reticulum/__init__.py - name: Run integration tests run: | @@ -145,7 +141,7 @@ jobs: --ignore=tests/test_v2_2_identity_handshake.py \ --ignore=tests/test_v2_2_mac_sorting.py \ --ignore=tests/test_v2_2_race_conditions.py \ - --cov=src/RNS/Interfaces \ + --cov=src/ble_reticulum \ --cov-report=term-missing \ --cov-report=xml:coverage-integration.xml \ --tb=short diff --git a/examples/ble_minimal_test.py b/examples/ble_minimal_test.py index e9f6f0c..08f0e73 100755 --- a/examples/ble_minimal_test.py +++ b/examples/ble_minimal_test.py @@ -21,7 +21,7 @@ import asyncio # Add parent directory to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src')) -from RNS.Interfaces.BLEFragmentation import BLEFragmenter, BLEReassembler +from ble_reticulum.BLEFragmentation import BLEFragmenter, BLEReassembler def test_fragmentation(): diff --git a/install.sh b/install.sh index 86f4ec3..5a08af9 100755 --- a/install.sh +++ b/install.sh @@ -254,8 +254,24 @@ if command -v rnsd &> /dev/null; then if [ -n "$RNS_LOCATION" ]; then print_success "Found RNS Python package at: $RNS_LOCATION" - # Check if it's a pipx installation (most specific, check first) - if [[ "$RNS_LOCATION" == *"/pipx/venvs/"* ]]; then + # Check if it's a uv tool installation (most specific, check first) + if [[ "$RNS_LOCATION" == *"/uv/tools/"* ]]; then + print_info "RNS appears to be installed via uv tool" + + # Extract uv tools path (e.g., ~/.local/share/uv/tools/rns) + UV_RNS_PATH=$(echo "$RNS_LOCATION" | grep -oP '^.*?/uv/tools/rns') + RNS_PYTHON="$UV_RNS_PATH/bin/python" + + if [ ! -f "$RNS_PYTHON" ]; then + print_error "uv Python not found at: $RNS_PYTHON" + exit 1 + fi + + INSTALL_MODE="uv" + print_success "Detected uv tool installation at: $UV_RNS_PATH" + + # Check if it's a pipx installation + elif [[ "$RNS_LOCATION" == *"/pipx/venvs/"* ]]; then print_info "RNS appears to be installed via pipx" # Verify pipx command is available @@ -308,6 +324,55 @@ if command -v rnsd &> /dev/null; then INSTALL_MODE="system" RNS_PYTHON="python3" fi + else + # rnsd exists but python3 can't import RNS + # This happens with uv/pipx when system python3 differs from tool's python + print_warning "rnsd found but RNS not importable by system python3" + print_info "Checking rnsd shebang for isolated environment..." + + RNSD_PATH=$(which rnsd) + RNSD_SHEBANG=$(head -1 "$RNSD_PATH" 2>/dev/null) + + if [[ "$RNSD_SHEBANG" == *"/uv/tools/rns/"* ]]; then + # uv tool installation + print_info "RNS appears to be installed via uv tool" + UV_RNS_PATH=$(echo "$RNSD_SHEBANG" | grep -oP '^#!\K.*?/uv/tools/rns' || echo "$HOME/.local/share/uv/tools/rns") + RNS_PYTHON="$UV_RNS_PATH/bin/python" + + if [ -f "$RNS_PYTHON" ]; then + INSTALL_MODE="uv" + print_success "Detected uv tool installation at: $UV_RNS_PATH" + else + print_error "uv Python not found at: $RNS_PYTHON" + exit 1 + fi + + elif [[ "$RNSD_SHEBANG" == *"/pipx/venvs/rns/"* ]]; then + # pipx installation + print_info "RNS appears to be installed via pipx" + PIPX_RNS_PATH=$(echo "$RNSD_SHEBANG" | grep -oP '^#!\K.*?/pipx/venvs/rns' || echo "$HOME/.local/pipx/venvs/rns") + RNS_PYTHON="$PIPX_RNS_PATH/bin/python3" + + if [ -f "$RNS_PYTHON" ]; then + INSTALL_MODE="pipx" + print_success "Detected pipx installation at: $PIPX_RNS_PATH" + else + print_error "pipx Python not found at: $RNS_PYTHON" + exit 1 + fi + + else + print_error "Could not determine RNS installation type from rnsd shebang" + print_info "Shebang: $RNSD_SHEBANG" + echo + echo "Please ensure RNS is properly installed and accessible to python3:" + echo " pip install rns" + echo " # or" + echo " uv tool install rns" + echo " # or" + echo " pipx install rns" + exit 1 + fi fi else print_warning "Reticulum (rnsd) not found" @@ -400,7 +465,42 @@ if [[ "$ARCH" == "armhf" ]] || [[ "$(uname -m)" =~ ^(armv6l|armv7l)$ ]]; then fi fi -if [ "$INSTALL_MODE" = "pipx" ]; then +if [ "$INSTALL_MODE" = "uv" ]; then + print_info "Installing dependencies into uv tool environment..." + echo + + # uv tool environments are at ~/.local/share/uv/tools/ + # We install directly using the tool's pip + DEPS=("bleak==1.1.1" "bluezero" "dbus-python") + + for dep in "${DEPS[@]}"; do + print_info "Installing $dep into RNS environment..." + + if uv pip install --python "$RNS_PYTHON" "$dep" 2>/dev/null; then + print_success "Installed $dep" + else + print_error "Failed to install $dep" + echo + echo "Try manually:" + echo " uv pip install --python $RNS_PYTHON $dep" + exit 1 + fi + echo + done + + # Verify all modules can be imported + print_info "Verifying dependencies..." + if "$RNS_PYTHON" -c "import bleak, bluezero, dbus" 2>/dev/null; then + print_success "All dependencies verified and working" + else + print_error "Dependency verification failed" + echo + echo "Test imports manually:" + echo " $RNS_PYTHON -c 'import bleak, bluezero, dbus'" + exit 1 + fi + +elif [ "$INSTALL_MODE" = "pipx" ]; then print_info "Installing dependencies via pipx inject..." print_warning "dbus-python will be compiled from source (may take 2-3 minutes)" echo @@ -494,9 +594,9 @@ mkdir -p "$INTERFACES_DIR" # Copy interface files print_info "Copying BLE interface files to: $INTERFACES_DIR" -cp src/RNS/Interfaces/BLE*.py \ - src/RNS/Interfaces/bluetooth_driver.py \ - src/RNS/Interfaces/linux_bluetooth_driver.py \ +cp src/ble_reticulum/BLE*.py \ + src/ble_reticulum/bluetooth_driver.py \ + src/ble_reticulum/linux_bluetooth_driver.py \ "$INTERFACES_DIR/" # Create __init__.py if it doesn't exist @@ -568,7 +668,10 @@ else print_info "Root user already has all required Bluetooth permissions" elif command -v setcap &> /dev/null; then # Determine correct Python path based on installation mode - if [ "$INSTALL_MODE" = "pipx" ]; then + if [ "$INSTALL_MODE" = "uv" ]; then + PYTHON_PATH="$UV_RNS_PATH/bin/python" + print_info "Using uv Python: $PYTHON_PATH" + elif [ "$INSTALL_MODE" = "pipx" ]; then PYTHON_PATH="$PIPX_RNS_PATH/bin/python3" print_info "Using pipx Python: $PYTHON_PATH" elif [ "$INSTALL_MODE" = "venv" ]; then diff --git a/pyproject.toml b/pyproject.toml index 9dad4e5..aa24bc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,11 +58,11 @@ Repository = "https://github.com/torlando-tech/ble-reticulum" Issues = "https://github.com/torlando-tech/ble-reticulum/issues" [tool.setuptools] -packages = ["RNS.Interfaces"] +packages = ["ble_reticulum"] package-dir = {"" = "src"} [tool.setuptools.package-data] -"RNS.Interfaces" = ["*.py"] +"ble_reticulum" = ["*.py"] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/src/RNS/__init__.py b/src/RNS/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/RNS/Interfaces/BLEAgent.py b/src/ble_reticulum/BLEAgent.py similarity index 100% rename from src/RNS/Interfaces/BLEAgent.py rename to src/ble_reticulum/BLEAgent.py diff --git a/src/RNS/Interfaces/BLEFragmentation.py b/src/ble_reticulum/BLEFragmentation.py similarity index 100% rename from src/RNS/Interfaces/BLEFragmentation.py rename to src/ble_reticulum/BLEFragmentation.py diff --git a/src/RNS/Interfaces/BLEGATTServer.py b/src/ble_reticulum/BLEGATTServer.py similarity index 99% rename from src/RNS/Interfaces/BLEGATTServer.py rename to src/ble_reticulum/BLEGATTServer.py index 848b308..a359342 100644 --- a/src/RNS/Interfaces/BLEGATTServer.py +++ b/src/ble_reticulum/BLEGATTServer.py @@ -36,7 +36,7 @@ try: HAS_BLE_AGENT = True except ImportError: try: - from RNS.Interfaces.BLEAgent import register_agent, unregister_agent + from ble_reticulum.BLEAgent import register_agent, unregister_agent HAS_BLE_AGENT = True except ImportError: HAS_BLE_AGENT = False diff --git a/src/RNS/Interfaces/BLEInterface.py b/src/ble_reticulum/BLEInterface.py similarity index 99% rename from src/RNS/Interfaces/BLEInterface.py rename to src/ble_reticulum/BLEInterface.py index 293699e..7c4b1db 100644 --- a/src/RNS/Interfaces/BLEInterface.py +++ b/src/ble_reticulum/BLEInterface.py @@ -67,10 +67,7 @@ except NameError: if _interface_dir not in sys.path: sys.path.insert(0, _interface_dir) -# Import base Interface class -# When integrated into Reticulum, this will be: -# from RNS.Interfaces.Interface import Interface -# For now, we'll need to handle the import path +# Import base Interface class from Reticulum try: from RNS.Interfaces.Interface import Interface except ImportError: @@ -85,7 +82,7 @@ try: from BLEFragmentation import BLEFragmenter, BLEReassembler except ImportError: # Fallback for when loaded as part of RNS package - from RNS.Interfaces.BLEFragmentation import BLEFragmenter, BLEReassembler + from ble_reticulum.BLEFragmentation import BLEFragmenter, BLEReassembler # Import GATT server for peripheral mode try: @@ -93,7 +90,7 @@ try: HAS_GATT_SERVER = True except ImportError: try: - from RNS.Interfaces.BLEGATTServer import BLEGATTServer + from ble_reticulum.BLEGATTServer import BLEGATTServer HAS_GATT_SERVER = True except ImportError: HAS_GATT_SERVER = False @@ -102,7 +99,7 @@ except ImportError: try: from bluetooth_driver import BLEDriverInterface, BLEDevice except ImportError: - from RNS.Interfaces.bluetooth_driver import BLEDriverInterface, BLEDevice + from ble_reticulum.bluetooth_driver import BLEDriverInterface, BLEDevice # Import platform-specific driver (optional - can be overridden by subclasses) try: @@ -110,7 +107,7 @@ try: HAS_LINUX_DRIVER = True except ImportError: try: - from RNS.Interfaces.linux_bluetooth_driver import LinuxBluetoothDriver + from ble_reticulum.linux_bluetooth_driver import LinuxBluetoothDriver HAS_LINUX_DRIVER = True except ImportError: HAS_LINUX_DRIVER = False diff --git a/src/RNS/Interfaces/__init__.py b/src/ble_reticulum/__init__.py similarity index 100% rename from src/RNS/Interfaces/__init__.py rename to src/ble_reticulum/__init__.py diff --git a/src/RNS/Interfaces/bluetooth_driver.py b/src/ble_reticulum/bluetooth_driver.py similarity index 100% rename from src/RNS/Interfaces/bluetooth_driver.py rename to src/ble_reticulum/bluetooth_driver.py diff --git a/src/RNS/Interfaces/linux_bluetooth_driver.py b/src/ble_reticulum/linux_bluetooth_driver.py similarity index 99% rename from src/RNS/Interfaces/linux_bluetooth_driver.py rename to src/ble_reticulum/linux_bluetooth_driver.py index 83ed0dd..b2200c3 100644 --- a/src/RNS/Interfaces/linux_bluetooth_driver.py +++ b/src/ble_reticulum/linux_bluetooth_driver.py @@ -184,7 +184,7 @@ try: HAS_BLE_AGENT = True except ImportError: try: - from RNS.Interfaces.BLEAgent import register_agent, unregister_agent + from ble_reticulum.BLEAgent import register_agent, unregister_agent HAS_BLE_AGENT = True except ImportError: HAS_BLE_AGENT = False diff --git a/tests/conftest.py b/tests/conftest.py index b6014a1..4c5c96a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ project_root = os.path.dirname(tests_dir) src_dir = os.path.join(project_root, 'src') # Add src/ to path for BLE interface modules -# This allows tests to import from src/RNS/Interfaces/ +# This allows tests to import from src/ble_reticulum/ if src_dir not in sys.path: sys.path.insert(0, src_dir) @@ -237,7 +237,7 @@ def sample_configuration(): def sample_discovered_peers(): """Sample DiscoveredPeer objects for testing.""" try: - from RNS.Interfaces.BLEInterface import DiscoveredPeer + from ble_reticulum.BLEInterface import DiscoveredPeer except ImportError: # Create a simple mock DiscoveredPeer for testing import time diff --git a/tests/test_ble_peer_interface.py b/tests/test_ble_peer_interface.py index fc14ef0..c3d0925 100644 --- a/tests/test_ble_peer_interface.py +++ b/tests/test_ble_peer_interface.py @@ -12,7 +12,7 @@ from unittest.mock import Mock, AsyncMock, patch, MagicMock # Import fragmentation for testing try: - from RNS.Interfaces.BLEFragmentation import BLEFragmenter, BLEReassembler + from ble_reticulum.BLEFragmentation import BLEFragmenter, BLEReassembler except ImportError: BLEFragmenter = None BLEReassembler = None diff --git a/tests/test_bluez_state_cleanup.py b/tests/test_bluez_state_cleanup.py index 5895764..16b39bd 100644 --- a/tests/test_bluez_state_cleanup.py +++ b/tests/test_bluez_state_cleanup.py @@ -220,7 +220,7 @@ class TestRemoveBlueZDeviceMethod: @pytest.mark.asyncio async def test_requires_dbus(self): """Test that method returns False when D-Bus is not available.""" - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver # Mock HAS_DBUS to False with patch.object(linux_bluetooth_driver, 'HAS_DBUS', False): diff --git a/tests/test_breddr_fallback_prevention.py b/tests/test_breddr_fallback_prevention.py index 08d5d29..0a93720 100644 --- a/tests/test_breddr_fallback_prevention.py +++ b/tests/test_breddr_fallback_prevention.py @@ -61,7 +61,7 @@ class TestBREDRFallbackPrevention: This tests the pure logic of parameter building, which is fully unit-testable without D-Bus. """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver # Mock driver driver = Mock() @@ -97,7 +97,7 @@ class TestBREDRFallbackPrevention: This test verifies that we handle the object path return value properly instead of ignoring it. """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver # Mock the D-Bus call to return an object path (what BlueZ actually returns) mock_object_path = "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF" diff --git a/tests/test_config_directory.py b/tests/test_config_directory.py index 287d575..4335c41 100644 --- a/tests/test_config_directory.py +++ b/tests/test_config_directory.py @@ -20,7 +20,7 @@ class TestConfigDirectoryResolution(unittest.TestCase): # Remove BLEInterface from sys.modules if it was imported modules_to_remove = [ 'BLEInterface', - 'RNS.Interfaces.BLEInterface' + 'ble_reticulum.BLEInterface' ] for module in modules_to_remove: if module in sys.modules: diff --git a/tests/test_dbus_disconnect_monitoring.py b/tests/test_dbus_disconnect_monitoring.py index 8576718..5bd03c5 100644 --- a/tests/test_dbus_disconnect_monitoring.py +++ b/tests/test_dbus_disconnect_monitoring.py @@ -56,7 +56,7 @@ class TestDBusDisconnectMonitoring: @pytest.fixture def mock_gatt_server(self, mock_driver): """Create mock GATT server with monitoring setup.""" - from RNS.Interfaces.linux_bluetooth_driver import BluezeroGATTServer + from ble_reticulum.linux_bluetooth_driver import BluezeroGATTServer server = Mock(spec=BluezeroGATTServer) server.driver = mock_driver @@ -304,7 +304,7 @@ class TestDBusDisconnectMonitoring: def test_error_handling_no_dbus(self, mock_gatt_server): """Test that monitoring returns early when D-Bus is not available.""" - with patch('RNS.Interfaces.linux_bluetooth_driver.HAS_DBUS', False): + with patch('ble_reticulum.linux_bluetooth_driver.HAS_DBUS', False): # Simulate the early return logic HAS_DBUS = False diff --git a/tests/test_error_recovery.py b/tests/test_error_recovery.py index 4d40497..e7067f4 100644 --- a/tests/test_error_recovery.py +++ b/tests/test_error_recovery.py @@ -13,7 +13,7 @@ from unittest.mock import Mock, AsyncMock, patch, MagicMock # conftest.py handles path setup - imports should work after that # Import only what we need for testing try: - from RNS.Interfaces.BLEFragmentation import BLEFragmenter, BLEReassembler + from ble_reticulum.BLEFragmentation import BLEFragmenter, BLEReassembler except ImportError: # If imports fail, tests will be skipped BLEFragmenter = None diff --git a/tests/test_fragmentation.py b/tests/test_fragmentation.py index 56d6eaa..d31370f 100755 --- a/tests/test_fragmentation.py +++ b/tests/test_fragmentation.py @@ -10,7 +10,7 @@ import os # Add parent directory to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src')) -from RNS.Interfaces.BLEFragmentation import BLEFragmenter, BLEReassembler, HDLCFramer +from ble_reticulum.BLEFragmentation import BLEFragmenter, BLEReassembler, HDLCFramer class TestBLEFragmenter: diff --git a/tests/test_gatt_server.py b/tests/test_gatt_server.py index cf661e4..0c396d7 100644 --- a/tests/test_gatt_server.py +++ b/tests/test_gatt_server.py @@ -11,7 +11,7 @@ import os # Add src to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) -from RNS.Interfaces.BLEGATTServer import BLEGATTServer, BLESS_AVAILABLE +from ble_reticulum.BLEGATTServer import BLEGATTServer, BLESS_AVAILABLE class MockInterface: diff --git a/tests/test_hci_error_fixes.py b/tests/test_hci_error_fixes.py index 0408150..3bd90ff 100644 --- a/tests/test_hci_error_fixes.py +++ b/tests/test_hci_error_fixes.py @@ -56,7 +56,7 @@ class TestEventDrivenDBusMonitor: @pytest.fixture def mock_gatt_server(self, mock_driver): """Create mock GATT server with event-driven monitoring setup.""" - from RNS.Interfaces.linux_bluetooth_driver import BluezeroGATTServer + from ble_reticulum.linux_bluetooth_driver import BluezeroGATTServer server = Mock(spec=BluezeroGATTServer) server.driver = mock_driver @@ -729,7 +729,7 @@ class TestCodeVerification: # Read the actual source file source_path = os.path.join( os.path.dirname(__file__), - '../src/RNS/Interfaces/linux_bluetooth_driver.py' + '../src/ble_reticulum/linux_bluetooth_driver.py' ) with open(source_path, 'r') as f: @@ -748,7 +748,7 @@ class TestCodeVerification: source_path = os.path.join( os.path.dirname(__file__), - '../src/RNS/Interfaces/linux_bluetooth_driver.py' + '../src/ble_reticulum/linux_bluetooth_driver.py' ) with open(source_path, 'r') as f: @@ -776,7 +776,7 @@ class TestCodeVerification: """Verify that stop() uses call_soon_threadsafe.""" source_path = os.path.join( os.path.dirname(__file__), - '../src/RNS/Interfaces/linux_bluetooth_driver.py' + '../src/ble_reticulum/linux_bluetooth_driver.py' ) with open(source_path, 'r') as f: diff --git a/tests/test_identity_hash.py b/tests/test_identity_hash.py index 5c120fd..32bdfca 100644 --- a/tests/test_identity_hash.py +++ b/tests/test_identity_hash.py @@ -107,7 +107,7 @@ class TestComputeIdentityHash: # Read the actual BLEInterface.py source ble_interface_path = os.path.join( os.path.dirname(__file__), - '../src/RNS/Interfaces/BLEInterface.py' + '../src/ble_reticulum/BLEInterface.py' ) with open(ble_interface_path, 'r') as f: diff --git a/tests/test_integration.py b/tests/test_integration.py index 583dd5b..17fc9e4 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -23,12 +23,12 @@ def test_config_options(): def test_interface_has_gatt_integration(): """Test that BLEInterface.py uses driver abstraction for peripheral mode.""" - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() # Check for driver-based architecture - assert 'from RNS.Interfaces.bluetooth_driver import BLEDriverInterface' in code or 'bluetooth_driver' in code + assert 'from ble_reticulum.bluetooth_driver import BLEDriverInterface' in code or 'bluetooth_driver' in code # Check for peripheral mode configuration assert 'enable_peripheral' in code @@ -48,7 +48,7 @@ def test_interface_has_gatt_integration(): def test_peer_interface_has_routing(): """Test that BLEPeerInterface uses driver for sending.""" - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() @@ -64,7 +64,7 @@ def test_peer_interface_has_routing(): def test_gatt_server_file_exists(): """Test that BLEGATTServer module exists.""" - server_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEGATTServer.py') + server_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEGATTServer.py') assert os.path.exists(server_path) with open(server_path, 'r') as f: @@ -80,7 +80,7 @@ def test_gatt_server_file_exists(): def test_driver_abstraction_exists(): """Test that driver abstraction layer is properly implemented.""" # Check driver interface exists - driver_interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/bluetooth_driver.py') + driver_interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/bluetooth_driver.py') assert os.path.exists(driver_interface_path) with open(driver_interface_path, 'r') as f: @@ -91,7 +91,7 @@ def test_driver_abstraction_exists(): assert 'ABC' in code or 'abstractmethod' in code # Check Linux driver implementation exists - linux_driver_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/linux_bluetooth_driver.py') + linux_driver_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/linux_bluetooth_driver.py') assert os.path.exists(linux_driver_path) with open(linux_driver_path, 'r') as f: @@ -118,7 +118,7 @@ def test_identity_based_fragmenter_keying(): Reference: BLE_PROTOCOL_v2.2.md ยง7 Identity-Based Keying """ - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() diff --git a/tests/test_peripheral_disconnect_cleanup.py b/tests/test_peripheral_disconnect_cleanup.py index de4ba49..e57f32c 100644 --- a/tests/test_peripheral_disconnect_cleanup.py +++ b/tests/test_peripheral_disconnect_cleanup.py @@ -456,7 +456,7 @@ class TestRealWorldScenario: Verifies that cleanup is idempotent - if both mechanisms detect the same disconnect, cleanup should only happen once without errors. """ - from RNS.Interfaces.linux_bluetooth_driver import BluezeroGATTServer + from ble_reticulum.linux_bluetooth_driver import BluezeroGATTServer # Setup GATT server with monitoring server = Mock(spec=BluezeroGATTServer) @@ -502,7 +502,7 @@ class TestRealWorldScenario: Simulates scenario where D-Bus signal fails or is delayed, but polling fallback detects and triggers cleanup within 30 seconds. """ - from RNS.Interfaces.linux_bluetooth_driver import BluezeroGATTServer + from ble_reticulum.linux_bluetooth_driver import BluezeroGATTServer # Setup GATT server server = Mock(spec=BluezeroGATTServer) diff --git a/tests/test_prioritization.py b/tests/test_prioritization.py index 30771fe..86232eb 100644 --- a/tests/test_prioritization.py +++ b/tests/test_prioritization.py @@ -431,7 +431,7 @@ class TestImplementationValidation: def test_discovered_peer_class_exists(self): """Test that DiscoveredPeer class is in the source file""" - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() @@ -444,7 +444,7 @@ class TestImplementationValidation: def test_prioritization_methods_exist(self): """Test that prioritization methods exist in BLEInterface.py""" - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() @@ -458,7 +458,7 @@ class TestImplementationValidation: def test_configuration_options_exist(self): """Test that prioritization configuration options exist""" - interface_path = os.path.join(os.path.dirname(__file__), '../src/RNS/Interfaces/BLEInterface.py') + interface_path = os.path.join(os.path.dirname(__file__), '../src/ble_reticulum/BLEInterface.py') with open(interface_path, 'r') as f: code = f.read() diff --git a/tests/test_scanner_connection_coordination.py b/tests/test_scanner_connection_coordination.py index 02c1c2e..d8cb8ea 100644 --- a/tests/test_scanner_connection_coordination.py +++ b/tests/test_scanner_connection_coordination.py @@ -70,7 +70,7 @@ class TestScannerConnectionCoordination: if scanning should be paused based on connection state. """ # Import the actual driver to test real method - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver # Create minimal driver instance driver = Mock() @@ -103,7 +103,7 @@ class TestScannerConnectionCoordination: This test reproduces the core bug - scanner doesn't know to pause when connections are active. """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver driver = Mock() driver._connecting_peers = {"AA:BB:CC:DD:EE:FF"} @@ -126,7 +126,7 @@ class TestScannerConnectionCoordination: PASSES AFTER FIX: Method correctly handles multiple connections """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver driver = Mock() driver._connecting_peers = { @@ -156,7 +156,7 @@ class TestScannerConnectionCoordination: This test verifies the coordination logic is actually used in the scan loop. We mock BleakScanner to avoid real Bluetooth operations. """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver # Create mock driver driver = Mock() @@ -196,7 +196,7 @@ class TestScannerConnectionCoordination: PASSES AFTER FIX: Scanner starts when _connecting_peers is empty """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver driver = Mock() driver._connecting_peers = set() # No connections @@ -231,7 +231,7 @@ class TestScannerConnectionCoordination: 2. Connection completes -> peer removed from _connecting_peers 3. Next scan loop iteration -> scanner resumes """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver driver = Mock() driver._connecting_peers = {"AA:BB:CC:DD:EE:FF"} @@ -280,7 +280,7 @@ class TestScannerConnectionCoordination: - It correctly identifies when to pause - It prevents scanner.start() calls during connections """ - from RNS.Interfaces import linux_bluetooth_driver + from ble_reticulum import linux_bluetooth_driver driver = Mock() driver._log = Mock() diff --git a/tests/test_stale_connection_polling.py b/tests/test_stale_connection_polling.py index d296edd..22ba253 100644 --- a/tests/test_stale_connection_polling.py +++ b/tests/test_stale_connection_polling.py @@ -56,7 +56,7 @@ class TestStaleConnectionPolling: @pytest.fixture def mock_gatt_server(self, mock_driver): """Create mock GATT server with polling setup.""" - from RNS.Interfaces.linux_bluetooth_driver import BluezeroGATTServer + from ble_reticulum.linux_bluetooth_driver import BluezeroGATTServer server = Mock(spec=BluezeroGATTServer) server.driver = mock_driver diff --git a/tests/test_v2_2_identity_handshake.py b/tests/test_v2_2_identity_handshake.py index 1ee89ff..0f9d87a 100644 --- a/tests/test_v2_2_identity_handshake.py +++ b/tests/test_v2_2_identity_handshake.py @@ -53,11 +53,11 @@ if not hasattr(RNS, 'Identity'): RNS.Identity = MagicMock() RNS.Identity.full_hash = lambda x: (x * 2)[:16] # Simple mock -# Mock RNS.Interfaces.Interface (required by BLEInterface.py) +# Mock ble_reticulum.Interface (required by BLEInterface.py) # First, ensure mock is in place BEFORE any imports that need it rns_interfaces_mock = MagicMock() -_sys.modules['RNS.Interfaces'] = rns_interfaces_mock -_sys.modules['RNS.Interfaces.Interface'] = MagicMock() +_sys.modules['ble_reticulum'] = rns_interfaces_mock +_sys.modules['ble_reticulum.Interface'] = MagicMock() # Create mock Interface base class class MockInterface: @@ -89,7 +89,7 @@ class MockInterface: return ConfigObj(configuration) rns_interfaces_mock.Interface = MockInterface -_sys.modules['RNS.Interfaces.Interface'].Interface = MockInterface +_sys.modules['ble_reticulum.Interface'].Interface = MockInterface from tests.mock_ble_driver import MockBLEDriver diff --git a/tests/test_v2_2_mac_sorting.py b/tests/test_v2_2_mac_sorting.py index 9ca5038..81eee45 100644 --- a/tests/test_v2_2_mac_sorting.py +++ b/tests/test_v2_2_mac_sorting.py @@ -59,9 +59,9 @@ if not hasattr(RNS, 'Identity'): RNS.Identity = MagicMock() RNS.Identity.full_hash = lambda x: (x * 2)[:16] -# Mock RNS.Interfaces.Interface module (the base class module, not the whole namespace) +# Mock ble_reticulum.Interface module (the base class module, not the whole namespace) # We only mock the Interface.py module, allowing BLEInterface.py to be imported from src/ -if 'RNS.Interfaces.Interface' not in _sys.modules: +if 'ble_reticulum.Interface' not in _sys.modules: # Create mock Interface base class class MockInterface: MODE_FULL = 1 @@ -100,13 +100,13 @@ if 'RNS.Interfaces.Interface' not in _sys.modules: return bool(val) if val is not None else default return ConfigObj(configuration) - # Create a mock module for RNS.Interfaces.Interface + # Create a mock module for ble_reticulum.Interface interface_module = MagicMock() interface_module.Interface = MockInterface - _sys.modules['RNS.Interfaces.Interface'] = interface_module + _sys.modules['ble_reticulum.Interface'] = interface_module from tests.mock_ble_driver import MockBLEDriver -from RNS.Interfaces.BLEInterface import BLEInterface, DiscoveredPeer +from ble_reticulum.BLEInterface import BLEInterface, DiscoveredPeer import time diff --git a/tests/test_v2_2_race_conditions.py b/tests/test_v2_2_race_conditions.py index 7d4bca2..afa13a2 100644 --- a/tests/test_v2_2_race_conditions.py +++ b/tests/test_v2_2_race_conditions.py @@ -64,10 +64,10 @@ if not hasattr(RNS, 'Identity'): RNS.Identity = MagicMock() RNS.Identity.full_hash = lambda x: (x * 2)[:16] -# Mock RNS.Interfaces.Interface (required by BLEInterface.py) -if 'RNS.Interfaces' not in _sys.modules: +# Mock ble_reticulum.Interface (required by BLEInterface.py) +if 'ble_reticulum' not in _sys.modules: rns_interfaces_mock = MagicMock() - _sys.modules['RNS.Interfaces'] = rns_interfaces_mock + _sys.modules['ble_reticulum'] = rns_interfaces_mock # Create mock Interface base class class MockInterface: @@ -80,7 +80,7 @@ if 'RNS.Interfaces' not in _sys.modules: rns_interfaces_mock.Interface = MockInterface from tests.mock_ble_driver import MockBLEDriver -from RNS.Interfaces.BLEInterface import BLEInterface, DiscoveredPeer +from ble_reticulum.BLEInterface import BLEInterface, DiscoveredPeer class MockOwner: