Skip to content

Tests fail when run on hardware with a bluetooth adaptor #118

@EdwardBetts

Description

@EdwardBetts

I tried running the test suite on my laptop. It fails because the tests are picking up the laptop's Bluetooth adapter.

Here's the test output.

$ python3 -m pytest tests -vv
=================================================================================================================================================================================== test session starts ===================================================================================================================================================================================
platform linux -- Python 3.11.8, pytest-8.0.2, pluggy-1.4.0 -- /usr/bin/python3.11
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase(PosixPath('/home/edward/src/debian/new-python/python-bluetooth-adapters/.pybuild/cpython3_3.11_bluetooth-adapters/build/.hypothesis/examples'))
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/edward/src/debian/new-python/python-bluetooth-adapters/.pybuild/cpython3_3.11_bluetooth-adapters/build
configfile: pyproject.toml
plugins: remotedata-0.4.1, astropy-header-0.2.2, flaky-3.7.0, forked-1.6.0, openfiles-0.5.0, console-scripts-1.4.1, astropy-0.11.0, mock-3.12.0, timeout-2.2.0, xdist-3.4.0, kgb-7.1.1, asyncio-0.20.3, arraydiff-0.6.1, doctestplus-1.1.0, hypothesis-6.98.12, django-4.5.2, twisted-1.14.0, Faker-22.0.0, requests-mock-1.11.0, httpx-0.21.3, filter-subpackage-0.1.2, cov-4.1.0, tornasync-0.6.0.post2, trio-0.8.0, anyio-4.2.0, None-None, benchmark-4.0.0, pylama-8.4.1
asyncio: mode=Mode.STRICT
collected 25 items                                                                                                                                                                                                                                                                                                                                                                        

tests/test_init.py::test_get_bluetooth_adapters_file_not_found PASSED                                                                                                                                                                                                                                                                                                               [  4%]
tests/test_init.py::test_get_bluetooth_adapters_connection_refused PASSED                                                                                                                                                                                                                                                                                                           [  8%]
tests/test_init.py::test_get_bluetooth_adapters_connect_refused_docker PASSED                                                                                                                                                                                                                                                                                                       [ 12%]
tests/test_init.py::test_get_bluetooth_adapters_connect_fails PASSED                                                                                                                                                                                                                                                                                                                [ 16%]
tests/test_init.py::test_get_bluetooth_adapters_connect_fails_docker PASSED                                                                                                                                                                                                                                                                                                         [ 20%]
tests/test_init.py::test_get_bluetooth_adapters_connect_broken_pipe PASSED                                                                                                                                                                                                                                                                                                          [ 24%]
tests/test_init.py::test_get_bluetooth_adapters_connect_broken_pipe_docker PASSED                                                                                                                                                                                                                                                                                                   [ 28%]
tests/test_init.py::test_get_bluetooth_adapters_connect_eof_error PASSED                                                                                                                                                                                                                                                                                                            [ 32%]
tests/test_init.py::test_get_bluetooth_adapters_no_call_return PASSED                                                                                                                                                                                                                                                                                                               [ 36%]
tests/test_init.py::test_get_bluetooth_adapters_times_out PASSED                                                                                                                                                                                                                                                                                                                    [ 40%]
tests/test_init.py::test_get_bluetooth_adapters_no_wrong_return PASSED                                                                                                                                                                                                                                                                                                              [ 44%]
tests/test_init.py::test_get_bluetooth_adapters_correct_return_valid_message PASSED                                                                                                                                                                                                                                                                                                 [ 48%]
tests/test_init.py::test_get_dbus_managed_objects PASSED                                                                                                                                                                                                                                                                                                                            [ 52%]
tests/test_init.py::test_BlueZDBusObjects PASSED                                                                                                                                                                                                                                                                                                                                    [ 56%]
tests/test_init.py::test_get_adapters_linux PASSED                                                                                                                                                                                                                                                                                                                                  [ 60%]
tests/test_init.py::test_get_adapters_linux_no_usb_device FAILED                                                                                                                                                                                                                                                                                                                    [ 64%]
tests/test_init.py::test_get_adapters_macos PASSED                                                                                                                                                                                                                                                                                                                                  [ 68%]
tests/test_init.py::test_get_adapters_windows PASSED                                                                                                                                                                                                                                                                                                                                [ 72%]
tests/test_init.py::test_adapter_human_name PASSED                                                                                                                                                                                                                                                                                                                                  [ 76%]
tests/test_init.py::test_adapter_unique_name PASSED                                                                                                                                                                                                                                                                                                                                 [ 80%]
tests/test_init.py::test_adapter_model PASSED                                                                                                                                                                                                                                                                                                                                       [ 84%]
tests/test_init.py::test_discovered_device_advertisement_data_to_dict PASSED                                                                                                                                                                                                                                                                                                        [ 88%]
tests/test_init.py::test_discovered_device_advertisement_data_from_dict PASSED                                                                                                                                                                                                                                                                                                      [ 92%]
tests/test_init.py::test_expire_stale_scanner_discovered_device_advertisement_data PASSED                                                                                                                                                                                                                                                                                           [ 96%]
tests/test_init.py::test_discovered_device_advertisement_data_from_dict_corrupt PASSED                                                                                                                                                                                                                                                                                              [100%]

======================================================================================================================================================================================== FAILURES =========================================================================================================================================================================================
__________________________________________________________________________________________________________________________________________________________________________ test_get_adapters_linux_no_usb_device __________________________________________________________________________________________________________________________________________________________________________

    @pytest.mark.asyncio
    @pytest.mark.skipif(
        MessageType is None or get_dbus_managed_objects is None,
        reason="dbus_fast is not available",
    )
    async def test_get_adapters_linux_no_usb_device():
        """Test get_adapters."""
    
        class MockMessageBus:
            def __init__(self, *args, **kwargs):
                pass
    
            async def connect(self):
                return AsyncMock(
                    disconnect=MagicMock(),
                    call=AsyncMock(
                        return_value=MagicMock(
                            body=[
                                {
                                    "/other": {},
                                    "/org/bluez/hci3": {
                                        "org.bluez.Adapter1": {
                                            "Address": "00:1A:7D:DA:71:04",
                                            "AddressType": "public",
                                            "Alias": "homeassistant",
                                            "Class": 2883584,
                                            "Discoverable": False,
                                            "DiscoverableTimeout": 180,
                                            "Discovering": True,
                                            "Modalias": "usb:v1D6Bp0246d053F",
                                            "Name": "homeassistant",
                                            "Pairable": False,
                                            "PairableTimeout": 0,
                                            "Powered": True,
                                            "Roles": ["central", "peripheral"],
                                            "UUIDs": [
                                                "0000110e-0000-1000-8000-00805f9b34fb",
                                                "0000110a-0000-1000-8000-00805f9b34fb",
                                                "00001200-0000-1000-8000-00805f9b34fb",
                                                "0000110b-0000-1000-8000-00805f9b34fb",
                                                "00001108-0000-1000-8000-00805f9b34fb",
                                                "0000110c-0000-1000-8000-00805f9b34fb",
                                                "00001800-0000-1000-8000-00805f9b34fb",
                                                "00001801-0000-1000-8000-00805f9b34fb",
                                                "0000180a-0000-1000-8000-00805f9b34fb",
                                                "00001112-0000-1000-8000-00805f9b34fb",
                                            ],
                                        },
                                        "org.bluez.GattManager1": {},
                                        "org.bluez.LEAdvertisingManager1": {
                                            "ActiveInstances": 0,
                                            "SupportedIncludes": [
                                                "tx-power",
                                                "appearance",
                                                "local-name",
                                            ],
                                            "SupportedInstances": 5,
                                        },
                                        "org.bluez.Media1": {},
                                        "org.bluez.NetworkServer1": {},
                                        "org.freedesktop.DBus.Introspectable": {},
                                        "org.freedesktop.DBus.Properties": {},
                                    },
                                    "/org/bluez/hci4": {},
                                    "/org/bluez/hci5/any": {},
                                    "/org/bluez/hci3/dev_54_D2_72_AB_35_95": {
                                        "org.freedesktop.DBus.Introspectable": {},
                                        "org.bluez.Device1": {
                                            "Address": "54:D2:72:AB:35:95",
                                            "AddressType": "public",
                                            "Name": "Nuki_1EAB3595",
                                            "Alias": "Nuki_1EAB3595",
                                            "Paired": False,
                                            "Trusted": False,
                                            "Blocked": False,
                                            "LegacyPairing": False,
                                            "RSSI": -78,
                                            "Connected": False,
                                            "UUIDs": [],
                                            "Adapter": "/org/bluez/hci3",
                                            "ManufacturerData": {
                                                "76": b"\\x02\\x15\\xa9.\\xe2\\x00U\\x01\\x11\\xe4\\x91l\\x08\\x00 \\x0c\\x9af\\x1e\\xab5\\x95\\xc4"
                                            },
                                            "ServicesResolved": False,
                                            "AdvertisingFlags": {
                                                "__type": "<class 'bytearray'>",
                                                "repr": "bytearray(b'\\x06')",
                                            },
                                        },
                                        "org.freedesktop.DBus.Properties": {},
                                    },
                                    "/org/bluez/hci1/dev_54_D2_72_AB_35_95": {
                                        "org.freedesktop.DBus.Introspectable": {},
                                        "org.bluez.Device1": {
                                            "Address": "54:D2:72:AB:35:95",
                                            "AddressType": "public",
                                            "Name": "Nuki_1EAB3595",
                                            "Alias": "Nuki_1EAB3595",
                                            "Paired": False,
                                            "Trusted": False,
                                            "Blocked": False,
                                            "LegacyPairing": False,
                                            "RSSI": -100,
                                            "Connected": False,
                                            "UUIDs": [],
                                            "Adapter": "/org/bluez/hci0",
                                            "ManufacturerData": {
                                                "76": b"\\x02\\x15\\xa9.\\xe2\\x00U\\x01\\x11\\xe4\\x91l\\x08\\x00 \\x0c\\x9af\\x1e\\xab5\\x95\\xc4"
                                            },
                                            "ServicesResolved": False,
                                            "AdvertisingFlags": {
                                                "__type": "<class 'bytearray'>",
                                                "repr": "bytearray(b'\\x06')",
                                            },
                                        },
                                        "org.freedesktop.DBus.Properties": {},
                                    },
                                }
                            ],
                            message_type=MessageType.METHOD_RETURN,
                        )
                    ),
                )
    
        class NoMfrMockUSBDevice(USBDevice):
            def __init__(self, *args, **kwargs):
                self.manufacturer = None
                self.product = "Bluetooth 4.0 USB Adapter"
                self.vendor_id = "0a12"
                self.product_id = "0001"
                pass
    
        class NoMfrMockBluetoothDevice(BluetoothDevice):
            def __init__(self, *args, **kwargs):
                self.usb_device = NoMfrMockUSBDevice()
                pass
    
            def setup(self, *args, **kwargs):
                pass
    
        with patch("platform.system", return_value="Linux"), patch(
            "bluetooth_adapters.dbus.MessageBus", MockMessageBus
        ), patch(
            "bluetooth_adapters.systems.linux.BluetoothDevice", NoMfrMockBluetoothDevice
        ):
            bluetooth_adapters = get_adapters()
            await bluetooth_adapters.refresh()
            assert bluetooth_adapters.default_adapter == "hci0"
            assert bluetooth_adapters.history == {
                "54:D2:72:AB:35:95": AdvertisementHistory(
                    device=ANY, advertisement_data=ANY, source="hci3"
                )
            }
>           assert bluetooth_adapters.adapters == {
                "hci3": {
                    "address": "00:1A:7D:DA:71:04",
                    "manufacturer": "cyber-blue(HK)Ltd",
                    "product": "Bluetooth 4.0 USB Adapter",
                    "vendor_id": "0a12",
                    "product_id": "0001",
                    "hw_version": "usb:v1D6Bp0246d053F",
                    "passive_scan": False,
                    "sw_version": "homeassistant",
                },
            }
E           AssertionError: assert {'hci0': {'address': '5C:E4:2A:C4:E6:12', 'sw_version': 'Unknown', 'hw_version': None, 'passive_scan': False, 'manufacturer': 'Intel Corporate', 'product': None, 'vendor_id': None, 'product_id': None}, 'hci3': {'address': '00:1A:7D:DA:71:04', 'sw_version': 'homeassistant', 'hw_version': 'usb:v1D6Bp0246d053F', 'passive_scan': False, 'manufacturer': 'cyber-blue(HK)Ltd', 'product': 'Bluetooth 4.0 USB Adapter', 'vendor_id': '0a12', 'product_id': '0001'}} == {'hci3': {'address': '00:1A:7D:DA:71:04', 'manufacturer': 'cyber-blue(HK)Ltd', 'product': 'Bluetooth 4.0 USB Adapter', 'vendor_id': '0a12', 'product_id': '0001', 'hw_version': 'usb:v1D6Bp0246d053F', 'passive_scan': False, 'sw_version': 'homeassistant'}}
E             
E             Common items:
E             {'hci3': {'address': '00:1A:7D:DA:71:04',
E                       'hw_version': 'usb:v1D6Bp0246d053F',
E                       'manufacturer': 'cyber-blue(HK)Ltd',
E                       'passive_scan': False,
E                       'product': 'Bluetooth 4.0 USB Adapter',
E                       'product_id': '0001',
E                       'sw_version': 'homeassistant',
E                       'vendor_id': '0a12'}}
E             Left contains 1 more item:
E             {'hci0': {'address': '5C:E4:2A:C4:E6:12',
E                       'hw_version': None,
E                       'manufacturer': 'Intel Corporate',
E                       'passive_scan': False,
E                       'product': None,
E                       'product_id': None,
E                       'sw_version': 'Unknown',
E                       'vendor_id': None}}
E             
E             Full diff:
E               {
E             +     'hci0': {
E             +         'address': '5C:E4:2A:C4:E6:12',
E             +         'hw_version': None,
E             +         'manufacturer': 'Intel Corporate',
E             +         'passive_scan': False,
E             +         'product': None,
E             +         'product_id': None,
E             +         'sw_version': 'Unknown',
E             +         'vendor_id': None,
E             +     },
E                   'hci3': {
E                       'address': '00:1A:7D:DA:71:04',
E                       'hw_version': 'usb:v1D6Bp0246d053F',
E                       'manufacturer': 'cyber-blue(HK)Ltd',
E                       'passive_scan': False,
E                       'product': 'Bluetooth 4.0 USB Adapter',
E                       'product_id': '0001',
E                       'sw_version': 'homeassistant',
E                       'vendor_id': '0a12',
E                   },
E               }

tests/test_init.py:870: AssertionError
==================================================================================================================================================================================== warnings summary =====================================================================================================================================================================================
tests/test_init.py::test_BlueZDBusObjects
  /home/edward/src/debian/new-python/python-bluetooth-adapters/.pybuild/cpython3_3.11_bluetooth-adapters/build/tests/test_init.py:441: FutureWarning: BLEDevice.rssi is deprecated and will be removed in a future version of Bleak, use AdvertisementData.rssi instead
    assert bluez.history["54:D2:72:AB:35:95"].device.rssi == -78

tests/test_init.py::test_discovered_device_advertisement_data_from_dict
  /home/edward/src/debian/new-python/python-bluetooth-adapters/.pybuild/cpython3_3.11_bluetooth-adapters/build/tests/test_init.py:1088: FutureWarning: BLEDevice.rssi is deprecated and will be removed in a future version of Bleak, use AdvertisementData.rssi instead
    assert out_ble_device.rssi == expected_ble_device.rssi

tests/test_init.py::test_discovered_device_advertisement_data_from_dict
  /home/edward/src/debian/new-python/python-bluetooth-adapters/.pybuild/cpython3_3.11_bluetooth-adapters/build/tests/test_init.py:1089: FutureWarning: BLEDevice.metadata is deprecated and will be removed in a future version of Bleak, use AdvertisementData instead
    assert out_ble_device.metadata == expected_ble_device.metadata

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------- coverage: platform linux, python 3.11.8-final-0 -----------
Name                                      Stmts   Miss Branch BrPart  Cover   Missing
-------------------------------------------------------------------------------------
bluetooth_adapters/__init__.py               13      0      2      1    93%   15->23
bluetooth_adapters/dbus.py                   95      6     38      0    95%   12-18
bluetooth_adapters/systems/linux.py          73      6     28      2    88%   48-53, 63->111, 65->80
bluetooth_adapters/systems/linux_hci.py      59     10     17      5    78%   7-9, 79, 88, 98-103, 105->107, 105->exit, 106->exit
bluetooth_adapters/util.py                   15      1      4      1    89%   15
-------------------------------------------------------------------------------------
TOTAL                                       460     23    157      9    94%

8 files skipped due to complete coverage.

================================================================================================================================================================================= short test summary info =================================================================================================================================================================================
FAILED tests/test_init.py::test_get_adapters_linux_no_usb_device - AssertionError: assert {'hci0': {'address': '5C:E4:2A:C4:E6:12', 'sw_version': 'Unknown', 'hw_version': None, 'passive_scan': False, 'manufacturer': 'Intel Corporate', 'product': None, 'vendor_id': None, 'product_id': None}, 'hci3': {'address': '00:1A:7D:DA:71:04', 'sw_version': 'homeassistant', 'hw_version': 'usb:v1D6Bp0246d053F', 'passive_scan': False, 'manufacturer': '...
======================================================================================================================================================================== 1 failed, 24 passed, 3 warnings in 0.33s =========================================================================================================================================================================
$ 

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions