mirror of
https://github.com/smittix/intercept.git
synced 2026-04-25 07:10:00 -07:00
- Fix SSE fanout thread AttributeError when source queue is None during interpreter shutdown by snapshotting to local variable with null guard - Fix branded "i" logo rendering oversized on first page load (FOUC) by adding inline width/height to SVG elements across 10 templates - Bump version to 2.26.0 in config.py, pyproject.toml, and CHANGELOG.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
130 lines
4.2 KiB
Python
130 lines
4.2 KiB
Python
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from flask import Flask
|
|
|
|
from routes.bluetooth import bluetooth_bp, classify_bt_device, detect_tracker
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_app_module(mocker):
|
|
mock_app = mocker.patch("routes.bluetooth.app_module")
|
|
mock_app.bt_devices = {}
|
|
mock_app.bt_beacons = {}
|
|
mock_app.bt_services = {}
|
|
mock_app.bt_queue = MagicMock()
|
|
mock_app.bt_lock = MagicMock()
|
|
mock_app.bt_process = None
|
|
mock_app.bt_interface = "hci0"
|
|
return mock_app
|
|
|
|
|
|
@pytest.fixture
|
|
def app():
|
|
app = Flask(__name__)
|
|
app.register_blueprint(bluetooth_bp)
|
|
return app
|
|
|
|
|
|
@pytest.fixture
|
|
def client(app):
|
|
return app.test_client()
|
|
|
|
|
|
def test_classify_bt_device_by_name():
|
|
"""Test classification based on common naming patterns."""
|
|
assert classify_bt_device("Sony WH-1000XM4", None, None) == "audio"
|
|
assert classify_bt_device("iPhone 15", None, None) == "phone"
|
|
assert classify_bt_device("Garmin Fenix", None, None) == "wearable"
|
|
assert classify_bt_device("Microsoft Mouse", None, None) == "input"
|
|
assert classify_bt_device("AirTag", None, None) == "tracker"
|
|
assert classify_bt_device("Generic Device", None, None) == "other"
|
|
|
|
|
|
def test_classify_bt_device_by_class():
|
|
"""Test classification based on Bluetooth Class of Device (CoD)."""
|
|
assert classify_bt_device(None, 0x0100, None) == "computer"
|
|
assert classify_bt_device(None, 0x0200, None) == "phone"
|
|
assert classify_bt_device(None, 0x0400, None) == "audio"
|
|
|
|
|
|
def test_detect_tracker_by_mac():
|
|
"""Test tracker detection using MAC OUI prefixes."""
|
|
# Assuming 'FF:FF:FF' is a mock prefix in patterns for testing
|
|
with patch("routes.bluetooth.TILE_PREFIXES", ["FF:FF"]):
|
|
result = detect_tracker("FF:FF:00:11:22:33", "Unknown")
|
|
assert result["type"] == "tile"
|
|
|
|
|
|
def test_detect_tracker_by_name():
|
|
"""Test tracker detection using name strings."""
|
|
result = detect_tracker("00:11:22:33:44:55", "My AirTag")
|
|
assert result["type"] == "airtag"
|
|
assert result["risk"] == "high"
|
|
|
|
|
|
# --- Route Tests ---
|
|
|
|
|
|
def test_get_interfaces_route(client, mocker):
|
|
"""Test the /interfaces endpoint with mocked system output."""
|
|
mock_run = mocker.patch("subprocess.run")
|
|
# Mocking hciconfig output for a Linux system
|
|
mock_run.return_value = MagicMock(
|
|
stdout="hci0:\tType: Primary Bus: USB\n\tBD Address: 00:11:22:33:44:55 ACL MTU: 1021:8 SCO MTU: 64:1\n\tUP RUNNING\n"
|
|
)
|
|
mocker.patch("platform.system", return_value="Linux")
|
|
mocker.patch("routes.bluetooth.check_tool", return_value=True)
|
|
|
|
response = client.get("/bt/interfaces")
|
|
data = response.get_json()
|
|
|
|
assert response.status_code == 200
|
|
assert data["interfaces"][0]["name"] == "hci0"
|
|
assert data["interfaces"][0]["status"] == "up"
|
|
assert data["tools"]["hcitool"] is True
|
|
|
|
|
|
def test_stop_scan_route(client, mock_app_module):
|
|
"""Test stopping a running scan process."""
|
|
mock_process = MagicMock()
|
|
mock_app_module.bt_process = mock_process
|
|
|
|
response = client.post("/bt/scan/stop")
|
|
|
|
assert response.status_code == 200
|
|
assert response.get_json()["status"] == "stopped"
|
|
mock_process.terminate.assert_called_once()
|
|
|
|
|
|
def test_enum_services_error_no_mac(client):
|
|
"""Test service enumeration validation."""
|
|
response = client.post("/bt/enum", json={})
|
|
assert response.status_code == 200
|
|
assert response.get_json()["status"] == "error"
|
|
|
|
|
|
def test_get_devices_route(client, mock_app_module):
|
|
"""Test retrieving the current device list from memory."""
|
|
mock_app_module.bt_devices = {"00:11:22:33:44:55": {"mac": "00:11:22:33:44:55", "name": "Test Device"}}
|
|
|
|
response = client.get("/bt/devices")
|
|
data = response.get_json()
|
|
|
|
assert response.status_code == 200
|
|
assert len(data["devices"]) == 1
|
|
assert data["devices"][0]["name"] == "Test Device"
|
|
|
|
|
|
def test_reload_oui_route(client, mocker):
|
|
"""Test the OUI database reload functionality."""
|
|
mocker.patch("routes.bluetooth.load_oui_database", return_value={"001122": "Test Corp"})
|
|
|
|
response = client.post("/bt/reload-oui")
|
|
data = response.get_json()
|
|
|
|
assert response.status_code == 200
|
|
assert data["status"] == "success"
|
|
assert data["entries"] > 0
|
|
|