Functional/integration testing
Subsystems (2)
v5 cover Functional/integration testing
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
*** v5 ***
https://github.com/pv/bluez/compare/func-test-v4-r..func-test-v5
* Factor out the pytest-bluezenv plugin, to be maintained separately.
https://pypi.org/project/pytest-bluezenv/
It could in principle be moved under the BlueZ organization, but there's no particular reason why it should be in bluez repository.
Generally, it's better to have the pytest plugin separate so it's easier to reuse and can have its own version cycle.
* Pipewire tests are moved to pipewire repository where they probably belong to.
They can be run easily vs. given BlueZ build dir.
We are currently running them in Pipewire CI, but at frozen kernel/BlueZ version, so it is not testing BlueZ/kernel upstream development.
* No changes in the emulator/test-runner patches since v4
They are stand-alone bug fixes / improvements, and make sense also separately from the rest.
*** v4 ***
https://github.com/pv/bluez/compare/func-test-v3-r..func-test-v4
* Use virtconsole for simpler HCI forwarding to the vm
* Fix typoed vm_module -> vm_once
* Skip tests for some pipewire versions
*** v3 ***
https://github.com/pv/bluez/compare/func-test-v2-r..func-test-v3
* fix configure.ac openpty() detection to match TOOLS conditional, to fix make distcheck
* properly retry virtio RPC connection if it fails initially
* properly restart VM if previous test hangs
* allow custom parent host side proxy objects, use them for pexpect
* improve --list with out-of-tree test files
* fix missing bus.set_exit_on_disconnect(False) for obex tests
* have --vm-timeout etc. change values also on VM host side
* use larger-memory VM instances for Pipewire, in case ASAN enabled
* set reasonable inside-VM ASAN_OPTION default values
* don't run btvirt under stdbuf, since not compatible with ASAN
*** v2 ***
https://github.com/pv/bluez/compare/func-test-v1-r..func-test-v2
* move unit/func_test -> test/functional & test/pytest_bluez
The pytest_bluez plugin is in principle reusable for other projects, so we can eg. have more complete Pipewire integration tests that can live in Pipewire repository.
* openpty() is in -lutil on some platforms, detect this in autoconf
* more emulator adjustments:
- fix SCO data packet support in btvirt
- more complete Reset command
* improve logging: get timestamps from kernel, and reorder logs to timestamp order, so that lines from different hosts, btmon, and parent tester appear in right order regardless of whether VM console / btmon is lagging
- this requires accurate clock sync in the VM, so enable KVM PTP in config and run chronyd inside the VMs
- use virtio port instead of qemu console to export logs, since the console has fixed baud rate and is too slow
* add --btmon & export btsnoop dumps from VM hosts
* fix compatibility with older Python versions
* add parametrized_host_config()
* split Pipewire test to A2DP/BAP/HFP and really stream audio. These catch the 5.86 regression fixed in 066a164a524e498 and the 5.84 one in 6b0a08776a
* add support for tests that reuse tester environment, so they can run faster without needing Bluetoothd teardown/setup in between
* add HostPlugin.presetup (mainly for test skipping)
* deal with RPC virtio port buffer possibly containing unflushed commands from previous failed test
* add some Agent1 interface tests
* add basic Obex file transfer tests
* add support for logging in to a running test instance (for gdb etc)
* export any core dumps out from test environ
Some bells & whistles:
* add --kernel-build for kernel image build
* test suite Python code formatting checks
***
Implements:
- RPC communication with tester instances running each of the VM hosts. Tests run on parent host, which instructs VM hosts what to do.
- Extensible way to add stateful test-specific code inside the VM instances
- Logging control: output from different processes running inside the VM are separated and can be filtered.
- Test runner framework with Pytest (more convenient than Python/unittest)
- Automatic grouping of tests to minimize VM reboots
- Redirecting USB controllers to use for testing in addition to btvirt
- Fairly straightforward, ~1600 sloc for the framework
There is no requirement that the tests spawn VM instances, the test runner can be used for any tests written in Python.
See doc/test-functional.rst for various examples.
Also test/functional/test_bluetoothctl_vm.py has some simple cases, and test/functional/test_pipewire.py for a more complicated setup
host0(qemu): Pipewire <-> BlueZ <-> kernel
<-> btvirt
host1(qemu): kernel <-> BlueZ <-> PipewireThe framework allows easily passing any data and code between the parent and VM hosts, so writing tests is straightforward.
***
Some examples:
$ test/test-functional --list -q
test/functional/lib/tests/test_rpc.py::test_basic test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_script_show[hosts1-vm1] test/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] test/functional/test_pipewire.py::test_pipewire[hosts3-vm2]
$ test/test-functional -v --no-header ======================================= test session starts ======================================== collected 5 items
test/functional/lib/tests/test_rpc.py::test_basic PASSED [ 20%] test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_script_show[hosts1-vm1] SKIPPED [ 40%] test/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] SKIPPED (No kernel image) [ 60%]
test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] SKIPPED (No k...) [ 80%]
test/functional/test_pipewire.py::test_pipewire[hosts3-vm2] SKIPPED (No kernel image) [100%]
=================================== 1 passed, 4 skipped in 0.19s ===================================
$ test/test-functional --kernel=../linux ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items
test/functional/lib/tests/test_rpc.py . [ 20%] test/functional/test_bluetoothctl_vm.py . [ 40%] test/functional/test_btmgmt_vm.py . [ 60%] test/functional/test_bluetoothctl_vm.py . [ 80%] test/functional/test_pipewire.py . [100%]
============================== 5 passed in 41.92s ==============================
$ test/test-functional --kernel=../linux -k test_btmgmt ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_btmgmt_vm.py . [100%]
======================= 1 passed, 4 deselected in 9.15s ========================
$ grep btmgmt test-functional.log
13:15:42 INFO rpc.host.0.0 : client: call_plugin ('call', '__call__', <function run at 0x7f27b81ce140>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'}
13:15:42 INFO host.0.0.rpc : server: call_plugin ('call', '__call__', <function run at 0x7fd5e35a1010>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'}
13:15:42 INFO host.0.0.run : $ /home/pauli/prj/external/bluez/build/tools/btmgmt --index 0 info$ test/test-functional --kernel=../linux -k test_btmgmt --log-cli-level=0 ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] -------------------------------- live log setup --------------------------------
13:00:31 INFO func_test.lib.env : Starting btvirt: /usr/bin/stdbuf -o L -e L /home/pauli/prj/external/bluez/build/emulator/btvirt --server=/tmp/bluez-func-test-8t6ychy8
13:00:31 OUT btvirt : Bluetooth emulator ver 5.86
13:00:31 INFO func_test.lib.env : Starting host: /home/pauli/prj/external/bluez/build/tools/test-runner --kernel=../linux/arch/x86/boot/bzImage -u/tmp/bluez-func-test-8t6ychy8/bt-server-bredrle -o -chardev -o socket,id=ser0,path=/tmp/bluez-func-test-8t6ychy8/bluez-func-test-rpc-0,server=on,wait=off -o -device -o virtio-serial -o -device -o virtserialport,chardev=ser0,name=bluez-func-test-rpc -H -- /usr/bin/python3 -P /home/pauli/prj/external/bluez/test/functional/lib/runner.py /dev/ttyS2
13:00:31 OUT btvirt : Request for /tmp/bluez-func-test-8t6ychy8/bt-server-bredrle
13:00:32 OUT host.0.0 : early console in extract_kernel
13:00:32 OUT host.0.0 : input_data: 0x000000000425c2c4
...
13:00:39 INFO rpc.host.0.0 : client: call_plugin ('call', '__call__', <function run at 0x7f7547472140>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'}
13:00:39 DEBUG host.0.0.rpc : server: done
13:00:39 INFO host.0.0.rpc : server: call_plugin ('call', '__call__', <function run at 0x7f77dcc81010>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'}
13:00:39 INFO host.0.0.run : $ /home/pauli/prj/external/bluez/build/tools/btmgmt --index 0 info
13:00:40 OUT host.0.0.run.out : hci0: Primary controller
13:00:40 OUT host.0.0.run.out : addr 00:AA:01:00:00:42 version 11 manufacturer 1521 class 0x000000
13:00:40 OUT host.0.0.run.out : supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver
13:00:40 OUT host.0.0.run.out : current settings: br/edr
13:00:40 OUT host.0.0.run.out : name
13:00:40 OUT host.0.0.run.out : short name
13:00:40 INFO host.0.0.run : (return code 0)
13:00:40 DEBUG rpc.host.0.0 : client-replyPASSED [100%]
13:00:40 OUT host.0.0 : qemu-system-x86_64: terminating on signal 15 from pid 149047 (python3)
======================= 1 passed, 4 deselected in 8.84s ========================
$ test/test-functional --kernel=../linux -k test_bluetoothctl_pair --log-cli-level=0 --log-filter=*.bluetoothctl,rpc.* --force-usb ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] -------------------------------- live log setup --------------------------------
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bdaddr object at 0x7f268712d160>,) {}
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Call object at 0x7f268712d2b0>,) {}
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.DbusSystem object at 0x7f2687aa30e0>,) {}
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bluetoothd object at 0x7f2687aa3230>,) {}
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bluetoothctl object at 0x7f268712d010>,) {}
13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bdaddr object at 0x7f26871542d0>,) {}
13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Call object at 0x7f2687154410>,) {}
13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.DbusSystem object at 0x7f2687aa30e0>,) {}
13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bluetoothd object at 0x7f2687aa3230>,) {}
13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bluetoothctl object at 0x7f2687154190>,) {}
13:03:20 INFO rpc.host.0.0 : client: wait_load () {}
13:03:21 DEBUG rpc.host.0.0 : client-reply
13:03:21 INFO rpc.host.0.1 : client: wait_load () {}
13:03:21 DEBUG rpc.host.0.1 : client-reply
-------------------------------- live log call ---------------------------------
13:03:21 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'show\n') {}
13:03:21 DEBUG rpc.host.0.0 : client-reply
13:03:21 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Powered: yes') {}
...
13:03:23 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'pair 70:1a:b8:73:99:bb\n') {}
13:03:23 OUT host.0.0.bluetoothctl: pair 70:1a:b8:73:99:bb
13:03:23 DEBUG rpc.host.0.0 : client-reply
13:03:23 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Confirm passkey (\\d+).*:') {}
13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> pair 70:1a:b8:73:99:bb
13:03:23 OUT host.0.0.bluetoothctl: Attempting to pair with 70:1A:B8:73:99:BB
13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 device_flags_changed: 70:1A:B8:73:99:BB (BR/EDR)
13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> supp: 0x00000007 curr: 0x00000000
13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 type 7 discovering off
13:03:25 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 70:1A:B8:73:99:BB type BR/EDR connected eir_len 12
13:03:25 OUT host.0.0.bluetoothctl: [bluetoothctl]> [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB Connected: yes
13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> Request confirmation
13:03:25 DEBUG rpc.host.0.0 : client-reply
13:03:25 INFO rpc.host.0.1 : client: call_plugin ('bluetoothctl', 'expect', 'Confirm passkey 237345') {}
13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> hci0 84:5C:F3:77:31:19 type BR/EDR connected eir_len 12
13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> [NEW] Device 84:5C:F3:77:31:19 BlueZ 5.86
13:03:25 DEBUG rpc.host.0.1 : client-reply
13:03:25 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'yes\n') {}
13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> [BlueZ 5.86]> Request confirmation
13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [agent] Confirm passkey 237345 (yes/no): yes
13:03:25 DEBUG rpc.host.0.0 : client-reply
13:03:25 INFO rpc.host.0.1 : client: call_plugin ('bluetoothctl', 'send', 'yes\n') {}
13:03:25 OUT host.0.1.bluetoothctl: [BlueZ 5.86]> [agent] Confirm passkey 237345 (yes/no): yes
13:03:25 DEBUG rpc.host.0.1 : client-reply
13:03:25 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Pairing successful') {}
13:03:25 OUT host.0.0.bluetoothctl: yes
13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> hci0 new_link_key 70:1A:B8:73:99:BB type 0x08 pin_len 0 store_hint 1
13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB Bonded: yes
13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB AddressType: public
13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
13:03:26 DEBUG rpc.host.0.0 : client-replyPASSED [100%]
------------------------------ live log teardown -------------------------------
13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:98:FF:qemu-system-x86_64: terminating on signal 15 from pid 149357 (python3)
======================= 1 passed, 4 deselected in 13.22s =======================
$ test/test-functional -k test_btmgmt --kernel=../linux --trace ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_btmgmt_vm.py
Quoted 2 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
PDB runcall (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(19)test_btmgmt_info()
-> (host,) = hosts
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(21)test_btmgmt_info()
-> result = host.call(
(Pdb) p host.bdaddr
'00:aa:01:00:00:42'
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(22)test_btmgmt_info()
-> run,
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(23)test_btmgmt_info()
-> [btmgmt, "--index", "0", "info"],
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(24)test_btmgmt_info()
-> stdout=subprocess.PIPE,
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(25)test_btmgmt_info()
-> stdin=subprocess.DEVNULL,
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(26)test_btmgmt_info()
-> encoding="utf-8",
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(21)test_btmgmt_info()
-> result = host.call(
(Pdb) n
Quoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(28)test_btmgmt_info()
-> assert result.returncode == 0
(Pdb) p result
CompletedProcess(args=['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info'], returncode=0, stdout='hci0:\tPrimary controller\n\taddr 00:AA:01:00:00:42 version 11 manufacturer 1521 class 0x000000\n\tsupported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver \n\tcurrent settings: br/edr \n\tname \n\tshort name \n') (Pdb) print(result.stdout)
hci0: Primary controller
addr 00:AA:01:00:00:42 version 11 manufacturer 1521 class 0x000000
supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver
current settings: br/edr
name
short name
(Pdb) q
!!!!!!!!!!!!!!!!!!! _pytest.outcomes.Exit: Quitting debugger !!!!!!!!!!!!!!!!!!! ======================= 4 deselected in 75.91s (0:01:15) =======================
Pauli Virtanen (16):
emulator: btvirt: check pkt lengths, don't get stuck on malformed
emulator: btvirt: allow specifying where server unix sockets are made
emulator: btvirt: support SCO data packets
emulator: btdev: clear more state on Reset
test-runner: enable path argument for --unix
test-runner: Add -o/--option option
test-runner: allow source tree root for -k
test-runner: use virtio-serial for implementing -u device forwarding
doc: enable CONFIG_VIRTIO_CONSOLE in tester config
doc: enable KVM paravirtualization & clock support in tester kernel
config
doc: add functional/integration testing documentation
test: add functional/integration testing framework
build: add functional testing target
test: functional: impose Python code formatting
test: functional: add some Agent1 interface tests
test: functional: add basic obex file transfer tests
Makefile.am | 10 + configure.ac | 22 ++ doc/ci.config | 9 + doc/test-functional.rst | 299 ++++++++++++++++++++++++ doc/test-runner.rst | 17 ++ doc/tester.config | 9 + emulator/btdev.c | 117 ++++++---- emulator/main.c | 37 +-- emulator/server.c | 21 ++ test/functional/__init__.py | 2 + test/functional/conftest.py | 48 ++++ test/functional/requirements.txt | 2 + test/functional/test_agent.py | 46 ++++ test/functional/test_bluetoothctl_vm.py | 152 ++++++++++++ test/functional/test_btmgmt_vm.py | 30 +++ test/functional/test_obex.py | 285 ++++++++++++++++++++++ test/functional/test_tests.py | 23 ++ test/pytest.ini | 17 ++ test/test-functional | 21 ++ test/test-functional-attach | 7 + tools/test-runner.c | 89 ++++--- 21 files changed, 1177 insertions(+), 86 deletions(-) create mode 100644 doc/test-functional.rst create mode 100644 test/functional/__init__.py create mode 100644 test/functional/conftest.py create mode 100644 test/functional/requirements.txt create mode 100644 test/functional/test_agent.py create mode 100644 test/functional/test_bluetoothctl_vm.py create mode 100644 test/functional/test_btmgmt_vm.py create mode 100644 test/functional/test_obex.py create mode 100644 test/functional/test_tests.py create mode 100644 test/pytest.ini create mode 100755 test/test-functional create mode 100755 test/test-functional-attach
Signature · 1 line
2.54.0
PATCH v5 1/16 emulator: btvirt: check pkt lengths, don't get stuck on malformed
Don't try to parse packet before whole header is received.
If received data has unknown packet type, reset buffer so that we don't get stuck.
--- emulator/server.c | 9 +++++++++ 1 file changed, 9 insertions(+)
emulator/server.c +9 -0
@@ -136,12 +136,20 @@ again: client->pkt_len =0 ;break ;case HCI_ACLDATA_PKT : +if (count <HCI_ACL_HDR_SIZE +1 ) { + client->pkt_offset += len; +return ; + } acl_hdr = (hci_acl_hdr *)(ptr +1 ); client->pkt_expect =HCI_ACL_HDR_SIZE + acl_hdr->dlen +1 ; client->pkt_data =malloc (client->pkt_expect); client->pkt_len =0 ;break ;case HCI_ISODATA_PKT : +if (count <HCI_ISO_HDR_SIZE +1 ) { + client->pkt_offset += len; +return ; + } iso_hdr = (hci_iso_hdr *)(ptr +1 ); client->pkt_expect =HCI_ISO_HDR_SIZE + iso_hdr->dlen +1 ;
@@ -151,6 +159,7 @@ again:default :printf ("packet error, unknown type: %d\n" , client->pkt_type); + client->pkt_offset =0 ;return ; }
Signature · 1 line
2.54.0
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1094320
---Test result---
Test Summary:
CheckPatch FAIL 6.03 seconds GitLint FAIL 4.35 seconds BuildEll PASS 20.01 seconds BluezMake PASS 608.25 seconds MakeCheck PASS 19.22 seconds MakeDistcheck PASS 232.69 seconds CheckValgrind PASS 272.79 seconds CheckSmatch WARNING 322.12 seconds bluezmakeextell PASS 165.37 seconds IncrementalBuild PASS 658.64 seconds ScanBuild PASS 916.62 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v5,12/16] test: add functional/integration testing framework ERROR:EXECUTE_PERMISSIONS: do not set execute permissions for source files #422: FILE: test/test-functional
ERROR:EXECUTE_PERMISSIONS: do not set execute permissions for source files #449: FILE: test/test-functional-attach
/github/workspace/src/patch/14571682.patch total: 2 errors, 0 warnings, 279 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14571682.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v5,01/16] emulator: btvirt: check pkt lengths, don't get stuck on malformed
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (82>80): "[BlueZ,v5,01/16] emulator: btvirt: check pkt lengths, don't get stuck on malformed"
[BlueZ,v5,02/16] emulator: btvirt: allow specifying where server unix sockets are made
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (86>80): "[BlueZ,v5,02/16] emulator: btvirt: allow specifying where server unix sockets are made"
[BlueZ,v5,08/16] test-runner: use virtio-serial for implementing -u device forwarding
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (85>80): "[BlueZ,v5,08/16] test-runner: use virtio-serial for implementing -u device forwarding"
[BlueZ,v5,10/16] doc: enable KVM paravirtualization & clock support in tester kernel config
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (91>80): "[BlueZ,v5,10/16] doc: enable KVM paravirtualization & clock support in tester kernel config"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:emulator/btdev.c:478:29: warning: Variable length array is used.
https://github.com/bluez/bluez/pull/2123
---
Regards,
Linux Bluetooth
PATCH v5 2/16 emulator: btvirt: allow specifying where server unix sockets are made
In reply to Pauli VirtanenMake --server to take optional path name where to create the various server sockets.
--- emulator/main.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-)
emulator/main.c +24 -13
@@ -18,6 +18,7 @@#include <stdbool.h> #include <getopt.h> #include <sys/uio.h> +#include <limits.h> #include "src/shared/mainloop.h" #include "src/shared/util.h"
@@ -46,7 +47,7 @@ static void usage(void)printf ("options:\n" "\t-d Enable debug\n" "\t-S Create local serial port\n" -"\t-s Create local server sockets\n" +"\t-s[path=/tmp] Create local server sockets\n" "\t-t[port=45550] Create a TCP server\n" "\t-l[num] Number of local controllers\n" "\t-L Create LE only controller\n"
@@ -60,7 +61,7 @@ static void usage(void)static const struct option main_options[] = { {"debug" , no_argument,NULL ,'d' }, {"serial" , no_argument,NULL ,'S' }, - {"server" , no_argument,NULL ,'s' }, + {"server" , optional_argument,NULL ,'s' }, {"tcp" , optional_argument,NULL ,'t' }, {"local" , optional_argument,NULL ,'l' }, {"le" , no_argument,NULL ,'L' },
@@ -88,6 +89,7 @@ int main(int argc, char *argv[])struct server *server5;bool debug_enabled = false;bool server_enabled = false; +const char *server_path ="/tmp" ;uint16_t tcp_port =0 ;bool serial_enabled = false;int letest_count =0 ;
@@ -100,7 +102,7 @@ int main(int argc, char *argv[])for (;;) {int opt; - opt =getopt_long (argc, argv,"dSst::l::LBAU::T::vh" , + opt =getopt_long (argc, argv,"dSs::t::l::LBAU::T::vh" , main_options,NULL );if (opt <0 )break ;
@@ -114,6 +116,8 @@ int main(int argc, char *argv[])break ;case 's' : server_enabled = true; +if (optarg) + server_path = optarg;break ;case 't' :if (optarg)
@@ -196,28 +200,35 @@ int main(int argc, char *argv[]) }if (server_enabled) { - server1 =server_open_unix (SERVER_TYPE_BREDRLE , -"/tmp/bt-server-bredrle" ); +char path[PATH_MAX ]; + +snprintf (path,sizeof (path),"%s/%s" , server_path, +"bt-server-bredrle" ); + server1 =server_open_unix (SERVER_TYPE_BREDRLE , path);if (!server1)fprintf (stderr,"Failed to open BR/EDR/LE server\n" ); - server2 =server_open_unix (SERVER_TYPE_BREDR , -"/tmp/bt-server-bredr" ); +snprintf (path,sizeof (path),"%s/%s" , server_path, +"bt-server-bredr" ); + server2 =server_open_unix (SERVER_TYPE_BREDR , path);if (!server2)fprintf (stderr,"Failed to open BR/EDR server\n" ); - server3 =server_open_unix (SERVER_TYPE_AMP , -"/tmp/bt-server-amp" ); +snprintf (path,sizeof (path),"%s/%s" , server_path, +"bt-server-amp" ); + server3 =server_open_unix (SERVER_TYPE_AMP , path);if (!server3)fprintf (stderr,"Failed to open AMP server\n" ); - server4 =server_open_unix (SERVER_TYPE_LE , -"/tmp/bt-server-le" ); +snprintf (path,sizeof (path),"%s/%s" , server_path, +"bt-server-le" ); + server4 =server_open_unix (SERVER_TYPE_LE , path);if (!server4)fprintf (stderr,"Failed to open LE server\n" ); - server5 =server_open_unix (SERVER_TYPE_MONITOR , -"/tmp/bt-server-mon" ); +snprintf (path,sizeof (path),"%s/%s" , server_path, +"bt-server-mon" ); + server5 =server_open_unix (SERVER_TYPE_MONITOR , path);if (!server5)fprintf (stderr,"Failed to open monitor server\n" ); }
Signature · 1 line
2.54.0
PATCH v5 3/16 emulator: btvirt: support SCO data packets
In reply to Pauli VirtanenSupport also SCO data packets in btvirt.
--- emulator/server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
emulator/server.c +12 -0
@@ -119,6 +119,7 @@ again:hci_command_hdr *cmd_hdr;hci_acl_hdr *acl_hdr;hci_iso_hdr *iso_hdr; +hci_sco_hdr *sco_hdr;if (!client->pkt_data) { client->pkt_type = ptr[0 ];
@@ -156,6 +157,17 @@ again: client->pkt_data =malloc (client->pkt_expect); client->pkt_len =0 ;break ; +case HCI_SCODATA_PKT : +if (count <HCI_SCO_HDR_SIZE +1 ) { + client->pkt_offset += len; +return ; + } + sco_hdr = (hci_sco_hdr *)(ptr +1 ); + client->pkt_expect =HCI_SCO_HDR_SIZE + + sco_hdr->dlen +1 ; + client->pkt_data =malloc (client->pkt_expect); + client->pkt_len =0 ; +break ;default :printf ("packet error, unknown type: %d\n" , client->pkt_type);
Signature · 1 line
2.54.0
PATCH v5 4/16 emulator: btdev: clear more state on Reset
In reply to Pauli VirtanenOn controller Reset command, initialize most fields in struct btdev to zero, similarly to the state just after btdev_create().
This excludes some fields like command bitmasks, which hciemu may have adjusted.
To make this easier, add struct_group() macro similar to what kernel uses.
--- emulator/btdev.c | 117 ++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 47 deletions(-)
emulator/btdev.c +70 -47
@@ -50,6 +50,12 @@#define has_bredr (btdev) (!((btdev)->features[4] & 0x20))#define has_le (btdev) (!!((btdev)->features[4] & 0x40)) +#define struct_group(NAME, MEMBERS...) \ + union { \ + struct { MEMBERS }; \ + struct { MEMBERS } NAME; \ + } +#define ACL_HANDLE BIT(0)#define SCO_HANDLE BIT(8)#define CIS_HANDLE SCO_HANDLE
@@ -149,15 +155,6 @@ struct btdev {struct queue *conns; -bool auth_init; -uint8_t link_key[16 ]; -uint16_t pin[16 ]; -uint8_t pin_len; -uint8_t io_cap; -uint8_t auth_req; -bool ssp_auth_complete; -uint8_t ssp_status; -btdev_command_func command_handler;void *command_data;
@@ -196,6 +193,18 @@ struct btdev {const struct btdev_cmd *emu_cmds;bool aosp_capable; +/* State zeroed on reset */ +struct_group (reset_group, + + bool auth_init; + uint8_t link_key[16]; +uint16_t pin[16 ]; +uint8_t pin_len; +uint8_t io_cap; +uint8_t auth_req; +bool ssp_auth_complete; +uint8_t ssp_status; +uint16_t default_link_policy;uint8_t event_mask[8 ];uint8_t event_mask_page2[8 ];
@@ -249,25 +258,26 @@ struct btdev {struct le_cig le_cig[CIG_SIZE ];uint8_t le_iso_path[2 ]; -/* Real time length of AL array */ -uint8_t le_al_len; -/* Real time length of RL array */ -uint8_t le_rl_len; -struct btdev_al le_al[AL_SIZE ]; -struct btdev_rl le_rl[RL_SIZE ];uint8_t le_rl_enable; -uint16_t le_rl_timeout;struct pending_conn pending_conn[MAX_PENDING_CONN ]; -uint8_t le_local_sk256[32 ]; -uint16_t sync_train_interval;uint32_t sync_train_timeout;uint8_t sync_train_service_data;uint16_t le_ext_adv_type; + ); /* reset_group */ + +/* Real time length of AL array */ +uint8_t le_al_len; +/* Real time length of RL array */ +uint8_t le_rl_len; +struct btdev_al le_al[AL_SIZE ]; +struct btdev_rl le_rl[RL_SIZE ]; +uint16_t le_rl_timeout; +struct queue *le_ext_adv;struct queue *le_per_adv;struct queue *le_big;
@@ -617,15 +627,52 @@ static void le_big_free(void *data)free (big); } +static void btdev_init_param (struct btdev *btdev) +{ +unsigned int i; + + btdev->page_scan_interval =0x0800 ; + btdev->page_scan_window =0x0012 ; + btdev->page_scan_type =0x00 ; + + btdev->sync_train_interval =0x0080 ; + btdev->sync_train_timeout =0x0002ee00 ; + btdev->sync_train_service_data =0x00 ; + + btdev->acl_mtu =192 ; + btdev->acl_max_pkt =1 ; + + btdev->sco_mtu =72 ; + btdev->sco_max_pkt =1 ; + + btdev->iso_mtu =251 ; + btdev->iso_max_pkt =1 ; + +for (i =0 ; i <ARRAY_SIZE (btdev->le_cig); ++i) + btdev->le_cig[i].params.cig_id =0xff ; + + btdev->country_code =0x00 ; +} +static void btdev_reset (struct btdev *btdev) {/* FIXME: include here clearing of all states that should be * cleared upon HCI_Reset */ - btdev->le_scan_enable =0x00 ; - btdev->le_adv_enable =0x00 ; - btdev->le_pa_enable =0x00 ; +if (btdev->inquiry_id >0 ) { +timeout_remove (btdev->inquiry_id); + btdev->inquiry_id =0 ; + } + +queue_remove_all (btdev->conns,NULL ,NULL , conn_remove); +queue_remove_all (btdev->le_ext_adv,NULL ,NULL , le_ext_adv_free); +queue_remove_all (btdev->le_per_adv,NULL ,NULL , free); +queue_remove_all (btdev->le_big,NULL ,NULL , le_big_free); + +memset (&btdev->reset_group,0 ,sizeof (btdev->reset_group)); + +btdev_init_param (btdev);al_clear (btdev);rl_clear (btdev);
@@ -633,10 +680,7 @@ static void btdev_reset(struct btdev *btdev) btdev->le_al_len =AL_SIZE ; btdev->le_rl_len =RL_SIZE ; -queue_remove_all (btdev->conns,NULL ,NULL , conn_remove); -queue_remove_all (btdev->le_ext_adv,NULL ,NULL , le_ext_adv_free); -queue_remove_all (btdev->le_per_adv,NULL ,NULL , free); -queue_remove_all (btdev->le_big,NULL ,NULL , le_big_free); + btdev->le_rl_timeout =0x0384 ; }static int cmd_reset (struct btdev *dev,const void *data,uint8_t len)
@@ -8130,7 +8174,6 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) {struct btdev *btdev;int index; -unsigned int i; btdev =malloc (sizeof (*btdev));if (!btdev)
@@ -8195,27 +8238,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)break ; } - btdev->page_scan_interval =0x0800 ; - btdev->page_scan_window =0x0012 ; - btdev->page_scan_type =0x00 ; - - btdev->sync_train_interval =0x0080 ; - btdev->sync_train_timeout =0x0002ee00 ; - btdev->sync_train_service_data =0x00 ; - - btdev->acl_mtu =192 ; - btdev->acl_max_pkt =1 ; - - btdev->sco_mtu =72 ; - btdev->sco_max_pkt =1 ; - - btdev->iso_mtu =251 ; - btdev->iso_max_pkt =1 ; - -for (i =0 ; i <ARRAY_SIZE (btdev->le_cig); ++i) - btdev->le_cig[i].params.cig_id =0xff ; - - btdev->country_code =0x00 ; +btdev_init_param (btdev); index =add_btdev (btdev);if (index <0 ) {
Signature · 1 line
2.54.0
PATCH v5 5/16 test-runner: enable path argument for --unix
In reply to Pauli VirtanenAllow specifying the path for the controller socket to be used.
--- tools/test-runner.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
tools/test-runner.c +8 -6
@@ -54,6 +54,7 @@ static bool start_monitor = false;static bool qemu_host_cpu = false;static int num_devs =0 ;static int num_emulator =0 ; +static const char *device_path ="/tmp/bt-server-bredr" ;static const char *qemu_binary =NULL ;static const char *kernel_image =NULL ;static char *audio_server;
@@ -313,11 +314,10 @@ static void start_qemu(void) argv[pos++] = (char *) cmdline;for (i =0 ; i < num_devs; i++) { -const char *path ="/tmp/bt-server-bredr" ;char *chrdev, *serdev; - chrdev =alloca (48 +strlen (path)); -sprintf (chrdev,"socket,path=%s,id=bt%d" , path, i); + chrdev =alloca (48 +strlen (device_path)); +sprintf (chrdev,"socket,path=%s,id=bt%d" , device_path, i); serdev =alloca (48 );sprintf (serdev,"pci-serial,chardev=bt%d" , i);
@@ -1198,7 +1198,7 @@ static void usage(void)"\t-m, --monitor Start btmon\n" "\t-l, --emulator[=num] Start btvirt\n" "\t-A, --audio[=path] Start audio server\n" -"\t-u, --unix [path] Provide serial device\n" +"\t-u, --unix[=path] Provide serial device\n" "\t-U, --usb [qemu_args] Provide USB device\n" "\t-q, --qemu <path> QEMU binary\n" "\t-H, --qemu-host-cpu Use host CPU (requires KVM support)\n"
@@ -1211,7 +1211,7 @@ static const struct option main_options[] = { { "auto", no_argument, NULL, 'a' }, { "dbus", no_argument, NULL, 'b' }, { "dbus-session", no_argument, NULL, 's' }, - { "unix", no_argument, NULL, 'u' }, + { "unix", optional_argument, NULL, 'u' }, { "daemon", no_argument, NULL, 'd' }, { "emulator", no_argument, NULL, 'l' }, { "monitor", no_argument, NULL, 'm' },
@@ -1239,7 +1239,7 @@ int main(int argc, char *argv[])for (;;) {int opt; - opt =getopt_long (argc, argv,"aubdsl::mq:Hk:A::U:vh" , + opt =getopt_long (argc, argv,"au::bdsl::mq:Hk:A::U:vh" , main_options,NULL );if (opt <0 )break ;
@@ -1250,6 +1250,8 @@ int main(int argc, char *argv[])break ;case 'u' : num_devs =1 ; +if (optarg) + device_path = optarg;break ;case 'b' : start_dbus = true;
Signature · 1 line
2.54.0
PATCH v5 6/16 test-runner: Add -o/--option option
In reply to Pauli VirtanenAllow passing arbitrary arguments to QEMU.
--- tools/test-runner.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
tools/test-runner.c +19 -3
@@ -41,6 +41,7 @@#endif #define CMDLINE_MAX (2048 * 10) +#define EXTRA_OPT_MAX 64static const char *own_binary;static char **test_argv;
@@ -59,6 +60,8 @@ static const char *qemu_binary = NULL;static const char *kernel_image =NULL ;static char *audio_server;static char *usb_dev; +static char *extra_opts[EXTRA_OPT_MAX ]; +static int num_extra_opts;static const char *qemu_table[] = {"qemu-system-x86_64" ,
@@ -291,7 +294,8 @@ static void start_qemu(void) argv =alloca (sizeof (qemu_argv) + (sizeof (char *) * (6 + (num_devs *4 ))) + - (sizeof (char *) * (usb_dev ?4 :0 ))); + (sizeof (char *) * (usb_dev ?4 :0 )) + + (sizeof (char *) * num_extra_opts));memcpy (argv, qemu_argv,sizeof (qemu_argv)); pos = (sizeof (qemu_argv) /sizeof (char *)) -1 ;
@@ -335,6 +339,9 @@ static void start_qemu(void) argv[pos++] = usb_dev; } +for (i =0 ; i < num_extra_opts; ++i) + argv[pos++] = extra_opts[i]; + argv[pos] =NULL ;execve (argv[0 ], argv, qemu_envp);
@@ -1199,10 +1206,11 @@ static void usage(void)"\t-l, --emulator[=num] Start btvirt\n" "\t-A, --audio[=path] Start audio server\n" "\t-u, --unix[=path] Provide serial device\n" -"\t-U, --usb [qemu_args] Provide USB device\n" +"\t-U, --usb <qemu_args> Provide USB device\n" "\t-q, --qemu <path> QEMU binary\n" "\t-H, --qemu-host-cpu Use host CPU (requires KVM support)\n" "\t-k, --kernel <image> Kernel image (bzImage)\n" +"\t-o, --option <opt> Additional argument passed to QEMU\n" "\t-h, --help Show help options\n"); }
@@ -1220,6 +1228,7 @@ static const struct option main_options[] = { { "kernel", required_argument, NULL, 'k' }, { "audio", optional_argument, NULL, 'A' }, { "usb", required_argument, NULL, 'U' }, + { "option", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { }
@@ -1239,7 +1248,7 @@ int main(int argc, char *argv[])for (;;) {int opt; - opt =getopt_long (argc, argv,"au::bdsl::mq:Hk:A::U:vh" , + opt =getopt_long (argc, argv,"au::bdsl::mq:Hk:A::U:o:vh" , main_options,NULL );if (opt <0 )break ;
@@ -1284,6 +1293,13 @@ int main(int argc, char *argv[])case 'U' : usb_dev = optarg;break ; +case 'o' : +if (num_extra_opts >=EXTRA_OPT_MAX ) { +fprintf (stderr,"Too many -o\n" ); +return EXIT_FAILURE ; + } + extra_opts[num_extra_opts++] = optarg; +break ;case 'v' :printf ("%s\n" ,VERSION );return EXIT_SUCCESS ;
Signature · 1 line
2.54.0
PATCH v5 7/16 test-runner: allow source tree root for -k
In reply to Pauli VirtanenAllow passing source tree root for -k option, look up kernel below it.
--- tools/test-runner.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-)
tools/test-runner.c +28 -14
@@ -93,18 +93,31 @@ static const char *kernel_table[] = {NULL }; -static const char *find_kernel (void ) +static bool find_kernel (const char *root,char path[PATH_MAX ]) { +struct stat st;int i; -for (i =0 ; kernel_table[i]; i++) { -struct stat st; - -if (!stat (kernel_table[i], &st)) -return kernel_table[i]; +if (root) { +snprintf (path,PATH_MAX ,"%s" , root); +if (stat (path, &st)) +return false; +if (!(st.st_mode &S_IFDIR )) +return true; } -return NULL ; +for (i =0 ; kernel_table[i]; i++) { +if (root) +snprintf (path,PATH_MAX ,"%s/%s" , root, + kernel_table[i]); +else +snprintf (path,PATH_MAX ,"%s" , + kernel_table[i]); +if (!stat (path, &st)) +return true; + } + +return false; } static const struct {
@@ -1209,7 +1222,7 @@ static void usage(void)"\t-U, --usb <qemu_args> Provide USB device\n" "\t-q, --qemu <path> QEMU binary\n" "\t-H, --qemu-host-cpu Use host CPU (requires KVM support)\n" -"\t-k, --kernel <image> Kernel image (bzImage)\n" +"\t-k, --kernel <image> Kernel bzImage or source tree path\n" "\t-o, --option <opt> Additional argument passed to QEMU\n" "\t-h, --help Show help options\n"); }
@@ -1236,6 +1249,8 @@ static const struct option main_options[] = {int main (int argc,char *argv[]) { +char kernel_path[PATH_MAX ]; +if (getpid () ==1 &&getppid () ==0 ) {prepare_sandbox ();run_tests ();
@@ -1335,14 +1350,13 @@ int main(int argc, char *argv[]) } } -if (!kernel_image) { - kernel_image =find_kernel (); -if (!kernel_image) { -fprintf (stderr,"No default kernel image found\n" ); -return EXIT_FAILURE ; - } +if (!find_kernel (kernel_image, kernel_path)) { +fprintf (stderr,"No kernel image found\n" ); +return EXIT_FAILURE ; } + kernel_image = kernel_path; +printf ("Using QEMU binary %s\n" , qemu_binary);printf ("Using kernel image %s\n" , kernel_image);
Signature · 1 line
2.54.0
PATCH v5 8/16 test-runner: use virtio-serial for implementing -u device forwarding
In reply to Pauli VirtanenUsing pci-serial to forward eg. btvirt sockets is unreliable, as qemu or kernel seems to be sometimes dropping part of the sent data or insert spurious \0 bytes, leading to sporadic errors like:
kernel: Bluetooth: hci0: command 0x0c52 tx timeout
kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110
btvirt: packet error, unknown type: 0This appears to occur most often when host system is under load, e.g. due to multiple test-runners running at the same time. The problem is not specific to btvirt, but seems to be in the qemu serial device layer vs. kernel interaction.
Change test-runner to use virtserialport to forward the btvirt connection inside the VM, as virtio-serial doesn't appear to have these problems.
--- tools/test-runner.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
tools/test-runner.c +9 -4
@@ -306,7 +306,7 @@ static void start_qemu(void) testargs); argv =alloca (sizeof (qemu_argv) + - (sizeof (char *) * (6 + (num_devs *4 ))) + + (sizeof (char *) * (8 + (num_devs *4 ))) + (sizeof (char *) * (usb_dev ?4 :0 )) + (sizeof (char *) * num_extra_opts));memcpy (argv, qemu_argv,sizeof (qemu_argv));
@@ -330,14 +330,19 @@ static void start_qemu(void) argv[pos++] ="-append" ; argv[pos++] = (char *) cmdline; +if (num_devs) { + argv[pos++] ="-device" ; + argv[pos++] ="virtio-serial" ; + } +for (i =0 ; i < num_devs; i++) {char *chrdev, *serdev; chrdev =alloca (48 +strlen (device_path));sprintf (chrdev,"socket,path=%s,id=bt%d" , device_path, i); - serdev =alloca (48 ); -sprintf (serdev,"pci-serial,chardev=bt%d" , i); + serdev =alloca (64 ); +sprintf (serdev,"virtconsole,chardev=bt%d,name=bt.%d" , i, i); argv[pos++] ="-chardev" ; argv[pos++] = chrdev;
@@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home) }if (num_devs) { -const char *node ="/dev/ttyS1" ; +const char *node ="/dev/hvc0" ;unsigned int basic_flags, extra_flags;printf ("Attaching BR/EDR controller to %s\n" , node);
Signature · 1 line
2.54.0
Luiz Augusto von Dentz
maintainerRe: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
Hi Pauli,
Quoted 57 lines · Pauli Virtanen
Using pci-serial to forward eg. btvirt sockets is unreliable, as qemu or kernel seems to be sometimes dropping part of the sent data or insert spurious \0 bytes, leading to sporadic errors like:
kernel: Bluetooth: hci0: command 0x0c52 tx timeout kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110 btvirt: packet error, unknown type: 0This appears to occur most often when host system is under load, e.g. due to multiple test-runners running at the same time. The problem is not specific to btvirt, but seems to be in the qemu serial device layer vs. kernel interaction.
Change test-runner to use virtserialport to forward the btvirt connection inside the VM, as virtio-serial doesn't appear to have these problems.
--- tools/test-runner.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)tools/test-runner.c +8
-3@@ -306,7 +306,7 @@ static void start_qemu(void) testargs); argv =alloca (sizeof (qemu_argv) + - (sizeof (char *) * (6 + (num_devs *4 ))) + + (sizeof (char *) * (8 + (num_devs *4 ))) + (sizeof (char *) * (usb_dev ?4 :0 )) + (sizeof (char *) * num_extra_opts));memcpy (argv, qemu_argv,sizeof (qemu_argv));@@ -330,14 +330,19 @@ static void start_qemu(void) argv[pos++] ="-append" ; argv[pos++] = (char *) cmdline; +if (num_devs) { + argv[pos++] ="-device" ; + argv[pos++] ="virtio-serial" ; + } +for (i =0 ; i < num_devs; i++) {char *chrdev, *serdev; chrdev =alloca (48 +strlen (device_path));sprintf (chrdev,"socket,path=%s,id=bt%d" , device_path, i); - serdev =alloca (48 ); -sprintf (serdev,"pci-serial,chardev=bt%d" , i); + serdev =alloca (64 ); +sprintf (serdev,"virtconsole,chardev=bt%d,name=bt.%d" , i, i); argv[pos++] ="-chardev" ; argv[pos++] = chrdev;
tools/test-runner.c static void run_command(char *cmdname, char *home) · line 918
Quoted 5 lines
tools/test-runner.c +1
-1@@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home) }if (num_devs) { -const char *node ="/dev/ttyS1" ; +const char *node ="/dev/hvc0" ;
Im getting and error with these changes:
Attaching BR/EDR controller to /dev/hvc0 Failed to open serial port: No such file or directory
I tried adding the kernel config options but it didn't make any difference.
Quoted 7 lines
tools/test-runner.c +0
-1unsigned int basic_flags, extra_flags;printf ("Attaching BR/EDR controller to %s\n" , node); --2.54.0
Signature · 1 line
Luiz Augusto von Dentz
Re: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
Hi Luiz,
ti, 2026-06-02 kello 15:35 -0400, Luiz Augusto von Dentz kirjoitti:
Quoted 77 lines
Hi Pauli,
Quoted 65 lines · Pauli Virtanen
Using pci-serial to forward eg. btvirt sockets is unreliable, as qemu or
kernel seems to be sometimes dropping part of the sent data or insert
spurious \0 bytes, leading to sporadic errors like:kernel: Bluetooth: hci0: command
0x0c52tx timeout
kernel: Bluetooth: hci0: Opcode0x0c52failed: -110
btvirt: packet error, unknown type: 0This appears to occur most often when host system is under load, e.g.
due to multiple test-runners running at the same time. The problem is
not specific to btvirt, but seems to be in the qemu serial device layer
vs. kernel interaction.Change test-runner to use virtserialport to forward the btvirt connection inside the VM, as virtio-serial doesn't appear to have these
problems.
---
tools/test-runner.c | 13 +++++++++----1 file changed, 9 insertions(+), 4 deletions(-)tools/test-runner.c +0
-0@@ -306,7 +306,7 @@ static void start_qemu(void) testargs);argv = alloca(sizeof(qemu_argv) +
- (sizeof(char *)* (6 + (num_devs* 4))) + + (sizeof(char *)* (8 + (num_devs* 4))) + (sizeof(char *)* (usb_dev? 4 : 0)) + (sizeof(char *)*num_extra_opts));memcpy(argv, qemu_argv, sizeof(qemu_argv));tools/test-runner.c +7
-2@@ -330,14 +330,19 @@ static void start_qemu(void) argv[pos++] = "-append"; argv[pos++] = (char *) cmdline; + if (num_devs) { + argv[pos++] = "-device"; + argv[pos++] = "virtio-serial"; + } + for (i = 0; i < num_devs; i++) { char *chrdev, *serdev; chrdev = alloca(48 + strlen(device_path)); sprintf(chrdev, "socket,path=%s,id=bt%d", device_path, i); - serdev = alloca(48); - sprintf(serdev, "pci-serial,chardev=bt%d", i); + serdev = alloca(64); + sprintf(serdev,"virtconsole,chardev=bt%d,name=bt.%d" , i, i);argv[pos++] = "-chardev";
argv[pos++] = chrdev;tools/test-runner.c static void run_command(char *cmdname, char · line 919
Quoted 6 lines
tools/test-runner.c +1
-1@@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home) } if (num_devs) { - const char *node = "/dev/ttyS1"; + const char *node = "/dev/hvc0";Im getting and error with these changes:
Quoted 5 lines
Attaching BR/EDR controller to
/dev/hvc0Failed to open serial port: No such file or directoryI tried adding the kernel config options but it didn't make any difference.
We have test-runner with this patch in Pipewire CI, and it is working
https://gitlab.freedesktop.org/pipewire/pipewire/-/jobs/101256448
on Fedora 44 + Qemu 10.2.2. Kernel configuration is here:
https://github.com/pv/bluez-test-functional-kernel/blob/main/tester.config
I've also used with this for USB redirection.
Not sure what is different for you, do you get any virtio serial devices from the virtconsole?
Quoted 10 lines
Quoted 9 lines
tools/test-runner.c +0
-0unsigned int basic_flags, extra_flags;
printf("Attaching BR/EDR controller to %s\n", node);
--
2.54.0
Signature · 1 line
Pauli Virtanen
Re: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
ti, 2026-06-02 kello 19:51 +0000, Pauli Virtanen kirjoitti:
Quoted 89 lines
Hi Luiz,
ti, 2026-06-02 kello 15:35 -0400, Luiz Augusto von Dentz kirjoitti:
Quoted 78 lines
Hi Pauli,
Quoted 66 lines · Pauli Virtanen
Using pci-serial to forward eg. btvirt sockets is unreliable, as qemu or
kernel seems to be sometimes dropping part of the sent data or insert
spurious \0 bytes, leading to sporadic errors like:kernel: Bluetooth: hci0: command
0x0c52tx timeout
kernel: Bluetooth: hci0: Opcode0x0c52failed: -110
btvirt: packet error, unknown type: 0This appears to occur most often when host system is under load, e.g.
due to multiple test-runners running at the same time. The problem
is
not specific to btvirt, but seems to be in the qemu serial device layer
vs. kernel interaction.Change test-runner to use virtserialport to forward the btvirt connection inside the VM, as virtio-serial doesn't appear to have these
problems.
---
tools/test-runner.c | 13 +++++++++----1 file changed, 9 insertions(+), 4 deletions(-)tools/test-runner.c +0
-0@@ -306,7 +306,7 @@ static void start_qemu(void) testargs);argv = alloca(sizeof(qemu_argv) +
- (sizeof(char *)* (6 + (num_devs* 4))) + + (sizeof(char *)* (8 + (num_devs* 4))) + (sizeof(char *)* (usb_dev? 4 : 0)) + (sizeof(char *)*num_extra_opts));memcpy(argv, qemu_argv, sizeof(qemu_argv));tools/test-runner.c +7
-2@@ -330,14 +330,19 @@ static void start_qemu(void) argv[pos++] = "-append"; argv[pos++] = (char *) cmdline; + if (num_devs) { + argv[pos++] = "-device"; + argv[pos++] = "virtio-serial"; + } + for (i = 0; i < num_devs; i++) { char *chrdev, *serdev; chrdev = alloca(48 + strlen(device_path)); sprintf(chrdev, "socket,path=%s,id=bt%d", device_path, i); - serdev = alloca(48); - sprintf(serdev, "pci-serial,chardev=bt%d", i); + serdev = alloca(64); + sprintf(serdev,"virtconsole,chardev=bt%d,name=bt.%d" , i, i);argv[pos++] = "-chardev";
argv[pos++] = chrdev;tools/test-runner.c static void run_command(char *cmdname, char · line 919
Quoted 6 lines
tools/test-runner.c +1
-1@@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home) } if (num_devs) { - const char *node = "/dev/ttyS1"; + const char *node = "/dev/hvc0";Im getting and error with these changes:
Quoted 5 lines
Attaching BR/EDR controller to
/dev/hvc0Failed to open serial port: No such file or directoryI tried adding the kernel config options but it didn't make any difference.
We have test-runner with this patch in Pipewire CI, and it is working
Quoted 7 lines
https://gitlab.freedesktop.org/pipewire/pipewire/-/jobs/101256448
on Fedora 44 + Qemu 10.2.2. Kernel configuration is here:
https://github.com/pv/bluez-test-functional-kernel/blob/main/tester.config
I've also used with this for USB redirection.
Also, the exact kernel image we are using built from that config is here:
https://github.com/pv/bluez-test-functional-kernel/releases/tag/2026-05-08.1
at bluez 07b6fc156348bb515ac0a876d49644312c9476d6 I can then do
$ ./emulator/btvirt -s & $ ./tools/test-runner -u/tmp/bt-server-bredrle -k bzImage -- bash ... Attachment of devices requested Attaching BR/EDR controller to /dev/hvc0 Switched line discipline from 0 to 15 Device index 0 attached Running command bash
Quoted 14 lines
Not sure what is different for you, do you get any virtio serial devices from the virtconsole?
Quoted 10 lines
Quoted 9 lines
tools/test-runner.c +0
-0unsigned int basic_flags, extra_flags;
printf("Attaching BR/EDR controller to %s\n", node);
--
2.54.0
Luiz Augusto von Dentz
maintainerRe: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
Hi Pauli,
Quoted 106 lines · Pauli Virtanen
ti, 2026-06-02 kello 19:51 +0000, Pauli Virtanen kirjoitti:
Quoted 89 lines
Hi Luiz,
ti, 2026-06-02 kello 15:35 -0400, Luiz Augusto von Dentz kirjoitti:
Quoted 78 lines
Hi Pauli,
Quoted 66 lines · Pauli Virtanen
Using pci-serial to forward eg. btvirt sockets is unreliable, as qemu or
kernel seems to be sometimes dropping part of the sent data or insert
spurious \0 bytes, leading to sporadic errors like:kernel: Bluetooth: hci0: command 0x0c52 tx timeout kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110 btvirt: packet error, unknown type: 0This appears to occur most often when host system is under load, e.g.
due to multiple test-runners running at the same time. The problem
is
not specific to btvirt, but seems to be in the qemu serial device layer
vs. kernel interaction.Change test-runner to use virtserialport to forward the btvirt connection inside the VM, as virtio-serial doesn't appear to have these
problems.--- tools/test-runner.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)tools/test-runner.c +8
-3@@ -306,7 +306,7 @@ static void start_qemu(void) testargs); argv =alloca (sizeof (qemu_argv) + - (sizeof (char *) * (6 + (num_devs *4 ))) + + (sizeof (char *) * (8 + (num_devs *4 ))) + (sizeof (char *) * (usb_dev ?4 :0 )) + (sizeof (char *) * num_extra_opts));memcpy (argv, qemu_argv,sizeof (qemu_argv));@@ -330,14 +330,19 @@ static void start_qemu(void) argv[pos++] ="-append" ; argv[pos++] = (char *) cmdline; +if (num_devs) { + argv[pos++] ="-device" ; + argv[pos++] ="virtio-serial" ; + } +for (i =0 ; i < num_devs; i++) {char *chrdev, *serdev; chrdev =alloca (48 +strlen (device_path));sprintf (chrdev,"socket,path=%s,id=bt%d" , device_path, i); - serdev =alloca (48 ); -sprintf (serdev,"pci-serial,chardev=bt%d" , i); + serdev =alloca (64 ); +sprintf (serdev,"virtconsole,chardev=bt%d,name=bt.%d" , i, i);argv[pos++] = "-chardev"; argv[pos++] = chrdev;tools/test-runner.c static void run_command(char *cmdname, char · line 919
Quoted 6 lines
tools/test-runner.c +1
-1@@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home) }if (num_devs) { -const char *node ="/dev/ttyS1" ; +const char *node ="/dev/hvc0" ;Im getting and error with these changes:
Quoted 5 lines
Attaching BR/EDR controller to
/dev/hvc0Failed to open serial port: No such file or directoryI tried adding the kernel config options but it didn't make any difference.
We have test-runner with this patch in Pipewire CI, and it is working
Quoted 7 lines
https://gitlab.freedesktop.org/pipewire/pipewire/-/jobs/101256448
on Fedora 44 + Qemu 10.2.2. Kernel configuration is here:
https://github.com/pv/bluez-test-functional-kernel/blob/main/tester.config
I've also used with this for USB redirection.
Also, the exact kernel image we are using built from that config is here:
https://github.com/pv/bluez-test-functional-kernel/releases/tag/2026-05-08.1
at bluez
07b6fc156348bb515ac0a876d49644312c9476d6I can then do
Quoted 8 lines
$ ./emulator/btvirt -s & $ ./tools/test-runner -u/tmp/bt-server-bredrle -k bzImage -- bash ... Attachment of devices requested Attaching BR/EDR controller to /dev/hvc0 Switched line discipline from 0 to 15 Device index 0 attached Running command bash
Seem that CONFIG_VIRTIO_CONSOLE was not enabled for some reason, once I enabled it works as intended.
Quoted 7 lines
Quoted 7 lines
Not sure what is different for you, do you get any virtio serial devices from the virtconsole?
Quoted 3 lines
Quoted 3 lines
tools/test-runner.c +0
-0unsigned int basic_flags, extra_flags;
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
printf("Attaching BR/EDR controller to %s\n",
node);
--
2.54.0
--
Luiz Augusto von Dentz
PATCH v5 9/16 doc: enable CONFIG_VIRTIO_CONSOLE in tester config
In reply to Pauli VirtanenEnable kernel option that allows using -device virtserialport in qemu. This is easier to make work reliably than pci-serial channel.
--- doc/ci.config | 1 + doc/test-runner.rst | 1 + doc/tester.config | 1 + 3 files changed, 3 insertions(+)
doc/ci.config +1 -0
@@ -6,6 +6,7 @@ CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_CONSOLE=y CONFIG_NET=y CONFIG_INET=y
doc/test-runner.rst +1 -0
@@ -45,6 +45,7 @@ option (like the Bluetooth subsystem) can be enabled on top of this. CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y + CONFIG_VIRTIO_CONSOLE=y CONFIG_NET=y CONFIG_INET=y
doc/tester.config +1 -0
@@ -1,6 +1,7 @@ CONFIG_PCI=y CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_CONSOLE=y CONFIG_NET=y CONFIG_INET=y
Signature · 1 line
2.54.0
PATCH v5 10/16 doc: enable KVM paravirtualization & clock support in tester kernel config
In reply to Pauli VirtanenEnable KVM guest and PTP options in tester kernel config.
This allows synchronizing tester VM guest with host clock, needed for testers that want to compare timestamps outside the VM guest.
--- doc/ci.config | 8 ++++++++ doc/test-runner.rst | 16 ++++++++++++++++ doc/tester.config | 8 ++++++++ 3 files changed, 32 insertions(+)
doc/ci.config +8 -0
@@ -8,6 +8,14 @@ CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_CONSOLE=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_KVM_GUEST=y + +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_KVM=y +CONFIG_PTP_1588_CLOCK_VMCLOCK=y + CONFIG_NET=y CONFIG_INET=y
doc/test-runner.rst +16 -0
@@ -122,6 +122,22 @@ options may be useful: CONFIG_DEBUG_MUTEXES=y CONFIG_KASAN=y +Other +----- + +For tests requiring accurate time inside the VM, possible with KVM: + +.. code-block:: + + CONFIG_HYPERVISOR_GUEST=y + CONFIG_PARAVIRT=y + CONFIG_KVM_GUEST=y + + CONFIG_PTP_1588_CLOCK=y + CONFIG_PTP_1588_CLOCK_KVM=y + CONFIG_PTP_1588_CLOCK_VMCLOCK=y + + EXAMPLES ========
doc/tester.config +8 -0
@@ -3,6 +3,14 @@ CONFIG_VIRTIO=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_CONSOLE=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_KVM_GUEST=y + +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_KVM=y +CONFIG_PTP_1588_CLOCK_VMCLOCK=y + CONFIG_NET=y CONFIG_INET=y
Signature · 1 line
2.54.0
PATCH v5 11/16 doc: add functional/integration testing documentation
In reply to Pauli VirtanenAdd documentation for functional/integration test suite.
--- doc/test-functional.rst | 299 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 doc/test-functional.rst
doc/test-functional.rst new file +299 -0
@@ -0,0 +1,299 @@ +=============== +test-functional +=============== + +**test-functional** [*OPTIONS*] + +DESCRIPTION +=========== + +**test-functional(1)** is used for functional testing of BlueZ and +kernel using multiple virtual machine environments, connected by real +or virtual controllers. + +It uses https://pypi.org/project/pytest-bluezenv as VM-based test +framework. For details, see its documentation. + +QUICK EXAMPLE +============= + +Install `qemu-system-x86_64` first. Then, + +.. code-block:: + + $ ./configure --enable-functional-testing --enable-testing --enable-tools + $ make -j8 + $ python3 -mpip install -r test/functional/requirements.txt + $ test/test-functional --kernel-build -v + +OPTIONS +======= + +The `test-functional` script simply runs `Pytest +<https://pytest.org>`__ which can take the following options: +https://docs.pytest.org/en/stable/reference/reference.html#command-line-flags + +The following additional options apply: + +:--kernel=<image>: Kernel image (or built Linux source tree root) to + use. See **test-runner(1)** and `tester.config` for required + kernel config. + + If not provided, value from `FUNCTIONAL_TESTING_KERNEL` + environment variable is used. If none, no image is used. + +:--usb=hci0,hci1: USB controllers to use in tests that require use of + real controllers. + + If not provided, value from `FUNCTIONAL_TESTING_CONTROLLERS` + environment variable is used. If none, all USB controllers + with suitable permissions are considered. + +:--btmon: Launch btmon on all hosts to log events, and dump traffic to + test-functional-\*.btsnoop + +:--force-usb: Force tests to use USB controllers instead of `btvirt`. + +:--vm-timeout=<seconds>: Specify timeout for communication with VM hosts. + +:--log-filter=[+-]<pattern>,[+-]<pattern>,...: Allow/deny lists + for filtering logging output. The pattern is a shell glob matching + to the logger names. + +:--build-dir=<path>: Path to build directory where to search for BlueZ + executables. + +:--list: Output brief lists of existing tests. + +:--kernel-build=no/use/auto/force: Build a suitable kernel image from source. + +:--kernel-upstream=<GIT_URL>: URL for Git clone of kernel sources. + +:--kernel-branch=<GIT_BRANCH>: Git branch to build from. + +Tests that require kernel image or USB controllers are skipped if none +are available. Normally, tests use `btvirt`. + +VM instances share a directory ``/run/shared`` with host machine, +located on host usually in ``/tmp/bluez-func-test-*/shared-*``. Core +dumps etc. are copied out from it before test instance is shut down. + +REQUIREMENTS +============ + +General +------- + +The following are needed: + +- QEmu (x86_64) +- ``dbus-daemon`` available + +Recommended: + +- KVM-enabled x86_64 host system +- Preferably built BlueZ source tree +- ``chronyd`` available +- ``util-linux`` tools available +- ``agetty`` available + +Python +------ + +The following Python packages are required: + +.. code-block:: + + pytest>=8 + pytest-bluezenv==0.1.5 + +To install them via pip:: + + python3 -m pip install -r test/functional/requirements.txt + +On Fedora / RHEL, the dependencies aside from `pytest-bluezenv` can be +installed via:: + + sudo dnf install python3-pytest python3-pexpect python3-dbus + +Kernel +------ + +The **test-functional(1)** tool requires a kernel image with similar +config as **test-runner(1)**. If given `--kernel-build` option, a +suitable image is built from sources downloaded under +`test/.pytest_cache`. + +Simplest setup is + +.. code-block:: + + cp ../bluez/doc/tester.config .config + make olddefconfig + make -j8 + +To get log timestamps right, the kernel should have the following +configuration enabled: + +.. code-block:: + + CONFIG_HYPERVISOR_GUEST=y + CONFIG_PARAVIRT=y + CONFIG_KVM_GUEST=y + + CONFIG_PTP_1588_CLOCK=y + CONFIG_PTP_1588_CLOCK_KVM=y + CONFIG_PTP_1588_CLOCK_VMCLOCK=y + +USB +--- + +Some tests may require a hardware controller instead of the virtual `btvirt` one. + +EXAMPLES +======== + +Run all tests +------------- + +.. code-block:: + + $ test/test-functional --kernel=/pathto/bzImage + + $ export FUNCTIONAL_TESTING_KERNEL=/pathto/bzImage + $ test/test-functional + +Show output during run +---------------------- + +.. code-block:: + + $ test/test-functional --log-cli-level=0 + +Show only specific loggers: + +.. code-block:: + + $ test/test-functional --log-cli-level=0 --log-filter=rpc,host + + $ test/test-functional --log-cli-level=0 --log-filter=*.bluetoothctl + +Filter out loggers: + +.. code-block:: + + $ test/test-functional --log-cli-level=0 --log-filter=-host + + $ test/test-functional --log-cli-level=0 --log-filter=host,-host.*.1 + +Run selected tests +------------------ + +.. code-block:: + + $ test/test-functional test/functional/test_cli_simple.py::test_bluetoothctl_script_show + + $ test/test-functional -k test_bluetoothctl_script_show + + $ test/test-functional -k 'test_btmgmt or test_bluetoothctl' + +Don't run tests with a given marker: + +.. code-block:: + + $ test/test-functional -m "not pipewire" + +Don't run known-failing tests: + +.. code-block:: + + $ test/test-functional -m "not xfail" + +Note that otherwise known-failing tests would be run, but with +failures suppressed. + +Run previously failed and stop on failure +----------------------------------------- + +.. code-block:: + + $ test/test-functional -x --ff + +List all tests +-------------- + +.. code-block:: + + $ test/test-functional --list + +Show errors from know-failing test +---------------------------------- + +.. code-block:: + + $ test/test-functional --runxfail -k test_btmgmt_info + +Redirect USB devices +-------------------- + +.. code-block:: + + $ test/test-functional --usb=hci0,hci1 + + $ export FUNCTIONAL_TESTING_CONTROLLERS=hci0,hci1 + $ test/test-functional -vv + +This does not require running as root. Changing device permissions is +sufficient. In verbose mode (``-vv``) some instructions are printed. + +Run all tests using the USB controllers: + +.. code-block:: + + $ test/test-functional --usb=hci0,hci1 --force-usb + +Run tests in parallel +--------------------- + +pytest-xdist is required for parallel execution. To run: + +.. code-block:: + + $ test/test-functional -n auto + +To reduce VM setup/teardowns: + +.. code-block:: + + $ test/test-functional -n auto --dist loadgroup + +Logging in to a test VM instance +-------------------------------- + +While test is running: + +.. code-block:: + + $ test/test-functional-attach + +For this to be useful, usually, you need to pause the test +e.g. by running with ``--trace`` option. + +To do it manually, when starting the tester will log a line like:: + + TTY: socat /tmp/bluez-func-test-q658swgi/bluez-func-test-tty-0 STDIO,rawer + +with the location of the socket where the serial is connected to. + +WRITING TESTS +============= + +The functional tests are written in files (test modules) names +`test/functional/test_*.py`. They are written using standard Pytest +style. See https://docs.pytest.org/en/stable/getting-started.html + +See https://pypi.org/project/pytest-bluezenv/ for documentation of +how to write VM-using tests. + +Use `Black <https://black.readthedocs.io/en/stable/>`__ to autoformat +Python test code.
Signature · 1 line
2.54.0
PATCH v5 12/16 test: add functional/integration testing framework
In reply to Pauli VirtanenAdd framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
Add some smoke tests for bluetoothctl and btmgmt.
The implementation for the VM setup is maintained separately in the pytest-bluezenv plugin, https://pypi.org/project/pytest-bluezenv
Implements:
- RPC communication with tester instances running each of the VM hosts, so that tests can be written on the parent host which coordinates the execution.
- Extensible way to add stateful test-specific code inside the VM instances
- Logging control: output from different processes running inside the VM are separated and can be filtered.
- Test runner framework with Pytest, factored into a pytest plugin
- Grouping tests to minimize VM reboots
- Redirecting USB controllers to use for testing
There is no requirement that the tests spawn VM instances.
--- test/functional/__init__.py | 2 + test/functional/conftest.py | 48 ++++++++ test/functional/requirements.txt | 2 + test/functional/test_bluetoothctl_vm.py | 152 ++++++++++++++++++++++++ test/functional/test_btmgmt_vm.py | 30 +++++ test/pytest.ini | 17 +++ test/test-functional | 21 ++++ test/test-functional-attach | 7 ++ 8 files changed, 279 insertions(+) create mode 100644 test/functional/__init__.py create mode 100644 test/functional/conftest.py create mode 100644 test/functional/requirements.txt create mode 100644 test/functional/test_bluetoothctl_vm.py create mode 100644 test/functional/test_btmgmt_vm.py create mode 100644 test/pytest.ini create mode 100755 test/test-functional create mode 100755 test/test-functional-attach
test/functional/__init__.py new file +2 -0
@@ -0,0 +1,2 @@ +# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*- +# SPDX-License-Identifier: GPL-2.0-or-later
test/functional/conftest.py new file +48 -0
48 lines not on this page · raw message
test/functional/requirements.txt new file +2 -0
@@ -0,0 +1,2 @@ +pytest>=8 +pytest-bluezenv==0.1.5
test/functional/test_bluetoothctl_vm.py new file +152 -0
152 lines not on this page · raw message
test/functional/test_btmgmt_vm.py new file +30 -0
@@ -0,0 +1,30 @@ +# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*- +# SPDX-License-Identifier: GPL-2.0-or-later +""" +Tests for btmgmt using VM instances +""" +import sys +import pytest +import subprocess +import tempfile + +from pytest_bluezenv import host_config, find_exe, run + +pytestmark = [pytest.mark.vm] + +btmgmt = find_exe("tools", "btmgmt") + + +@host_config([]) +def test_btmgmt_info(hosts): + (host,) = hosts + + result = host.call( + run, + [btmgmt, "--index", "0", "info"], + stdout=subprocess.PIPE, + stdin=subprocess.DEVNULL, + encoding="utf-8", + ) + assert result.returncode == 0 + assert f"addr {host.bdaddr.upper()}" in result.stdout
test/pytest.ini new file +17 -0
@@ -0,0 +1,17 @@ +[pytest] +log_format = %(asctime)s %(levelname)-6s %(name)-20s: %(message)s +log_date_format = %Y-%m-%d %H:%M:%S.%f +log_level = 0 +log_file = test-functional.log +markers = + vm: tests requiring VM image + +addopts = + -p pytest_bluezenv + +# Default timeout +vm_timeout = 30 + +# Default sources for kernel-build when requested +kernel_upstream = https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git/ +kernel_branch = master
test/test-functional new file +21 -0
@@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# See doc/test-functional.rst +# +TESTDIR="$(dirname "$0")" +SRCDIR="$TESTDIR/.." + +BUILDDIR= +for d in "$SRCDIR" "$SRCDIR/build" "$SRCDIR/builddir"; do + if [ -f "$d/src/bluetoothd" ]; then + BUILDDIR="$d" + break + fi +done + +if [ -n "$BUILDDIR" -a -d "$BUILDDIR" ]; then + exec python3 -m pytest "$TESTDIR/functional" --bluez-src-dir "$SRCDIR" --bluez-build-dir "$BUILDDIR" "$@" +else + exec python3 -m pytest "$TESTDIR/functional" --bluez-src-dir "$SRCDIR" "$@" +fi
test/test-functional-attach new file +7 -0
@@ -0,0 +1,7 @@ +#!/bin/sh +# +# test-functional-attach +# +# Start Tmux and connect to active test-functional VM hosts. +# +exec python3 -mpytest_bluezenv attach "$@"
Signature · 1 line
2.54.0
PATCH v5 13/16 build: add functional testing target
In reply to Pauli VirtanenThis adds check-functional: target that runs the functional test suite.
Also add a --enable-functional-testing=<kernel-image> argument for configure that can be used to include it in the check: make target, possibly with a predefined kernel image.
--- Makefile.am | 10 ++++++++++ configure.ac | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+)
Makefile.am +10 -0
@@ -812,6 +812,16 @@ endif TESTS = $(unit_tests) AM_TESTS_ENVIRONMENT = MALLOC_CHECK_=3 MALLOC_PERTURB_=69 +check-functional: all + python3 -m pytest "$(srcdir)/test/functional" -v \ + --kernel="$(FUNCTIONAL_TESTING_KERNEL)" \ + --bluez-build-dir="$(top_builddir)" \ + --bluez-src-dir="$(srcdir)" + +if FUNCTIONAL_TESTING +check: check-functional +endif + if DBUS_RUN_SESSION AM_TESTS_ENVIRONMENT += dbus-run-session -- endif
configure.ac +22 -0
@@ -405,6 +405,28 @@ if (test "${enable_testing}" = "yes"); then #include <linux/net_tstamp.h>]]) fi +AC_ARG_ENABLE(functional-testing, AS_HELP_STRING([--enable-functional-testing], + [enable functional testing tools]), + [enable_functional_testing=yes; functional_testing_kernel=${enableval}], + [enable_functional_testing=no]) +AM_CONDITIONAL(FUNCTIONAL_TESTING, test "${enable_functional_testing}" = "yes") +AC_ARG_VAR(FUNCTIONAL_TESTING_KERNEL, [vmlinux image to use for functional testing]) +FUNCTIONAL_TESTING_KERNEL=${functional_testing_kernel} + +if (test "${enable_functional_testing}" = "yes"); then + if (test "${enable_client}" = "no" || \ + test "${enable_tools}" != "yes" || \ + test "${enable_testing}" != "yes"); then + AC_MSG_ERROR([--enable-functional-testing requires --enable-client --enable-tools --enable-testing]) + fi + AC_MSG_CHECKING([pytest and dependencies]) + python3 -m pip install --dry-run --no-index -r "${srcdir}/test/functional/requirements.txt" >/dev/null + if (test "$?" != "0"); then + AC_MSG_ERROR([pytest or dependencies missing]) + fi + AC_MSG_RESULT([ok]) +fi + AC_ARG_ENABLE(experimental, AS_HELP_STRING([--enable-experimental], [enable experimental tools]), [enable_experimental=${enableval}])
Signature · 1 line
2.54.0
PATCH v5 14/16 test: functional: impose Python code formatting
In reply to Pauli VirtanenCheck Python code formatting of the functional test suite.
--- test/functional/test_tests.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/functional/test_tests.py
test/functional/test_tests.py new file +23 -0
@@ -0,0 +1,23 @@ +# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*- +# SPDX-License-Identifier: GPL-2.0-or-later +""" +Tests for the test suite itself +""" +import sys +import subprocess +import warnings +from pathlib import Path + +import pytest + + +def test_formatting(): + pytest.importorskip("black") + + result = subprocess.run( + [sys.executable, "-mblack", "--check", "--diff", "-q", Path(__file__).parent], + stdout=subprocess.PIPE, + encoding="utf-8", + ) + if result.returncode != 0: + warnings.warn(f"Formatting incorrect:\n{result.stdout}")
Signature · 1 line
2.54.0
PATCH v5 15/16 test: functional: add some Agent1 interface tests
In reply to Pauli VirtanenAdd test
test/functional/test_agent.py::test_agent_pair_bredr
--- test/functional/test_agent.py | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/functional/test_agent.py
test/functional/test_agent.py new file +46 -0
@@ -0,0 +1,46 @@ +# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*- +# SPDX-License-Identifier: GPL-2.0-or-later +""" +Tests for bluetoothctl using VM instances +""" +import sys +import re +import pytest +import subprocess +import tempfile + +import time +import logging + + +from pytest_bluezenv import host_config, Agent, wait_until + +pytestmark = [pytest.mark.vm] + + +@host_config([Agent()], [Agent()]) [email protected]("success", [True, False], ids=["accept", "reject"]) +def test_agent_pair_bredr(hosts, success): + host0, host1 = hosts + + host0.agent.adapter_method("StartDiscovery") + host0.agent.expect("org.bluez.Adapter1.StartDiscovery:reply") + + host1.agent.adapter_set("Pairable", True) + host1.agent.adapter_set("Discoverable", True) + + wait_until(host0.agent.has_device, host1.bdaddr) + + host0.agent.device_method(host1.bdaddr, "Pair") + + confirm_0 = host0.agent.expect("org.bluez.Agent1.RequestConfirmation") + confirm_1 = host1.agent.expect("org.bluez.Agent1.RequestConfirmation") + assert confirm_0.passkey == confirm_1.passkey + host0.agent.reply() + + if success: + host1.agent.reply() + host0.agent.expect("org.bluez.Device1.Pair:reply") + else: + host1.agent.reply_error() + host0.agent.expect("org.bluez.Device1.Pair:error")
Signature · 1 line
2.54.0
PATCH v5 16/16 test: functional: add basic obex file transfer tests
In reply to Pauli VirtanenAdd tests for Obex DBus API and obexctl
test/functional/test_obex.py::test_obex_ftp_get
test/functional/test_obex.py::test_obex_ftp_list
test/functional/test_obex.py::test_obexctl_list
--- test/functional/test_obex.py | 285 +++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 test/functional/test_obex.py
test/functional/test_obex.py new file +285 -0
@@ -0,0 +1,285 @@ +# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*- +# SPDX-License-Identifier: LGPL-2.1-or-later +""" +Tests for Obex +""" +import sys +import os +import re +import pytest +import subprocess +import tempfile +import time +import logging +import json +import dbus +import threading +from pathlib import Path + +import pytest + +from pytest_bluezenv import ( + HostPlugin, + Agent, + host_config, + find_exe, + Bluetoothd, + Bluetoothctl, + Obexd, + LogStream, + wait_until, + mainloop_wrap, + mainloop_assert, + Event, + EventPluginMixin, + dbus_service_event_method, + Pexpect, + utils, +) + +pytestmark = [pytest.mark.vm] + +log = logging.getLogger(__name__) + + +BUS_NAME = "org.bluez.obex" +PATH = "/org/bluez/obex" +AGENT_MANAGER_INTERFACE = "org.bluez.obex.AgentManager1" +AGENT_INTERFACE = "org.bluez.obex.Agent1" +CLIENT_INTERFACE = "org.bluez.obex.Client1" +SESSION_INTERFACE = "org.bluez.obex.Session1" +FILE_TRANSFER_INTERFACE = "org.bluez.obex.FileTransfer1" +TRANSFER_INTERFACE = "org.bluez.obex.Transfer1" + +FTP_UUID = "00001106-0000-1000-8000-00805f9b34fb" + + +class ObexAgent(HostPlugin, EventPluginMixin): + depends = [Bluetoothd()] + name = "obex_agent" + + def __init__(self, path="/obexagent"): + self.path = path + + @mainloop_wrap + def setup(self, impl): + EventPluginMixin.setup(self, impl) + + self.bus = dbus.SessionBus() + self.bus.set_exit_on_disconnect(False) + + self.agent = ObexAgentObject(self.bus, self.path, self.events) + + bluez = self.bus.get_object(BUS_NAME, PATH) + self.manager = dbus.Interface(bluez, AGENT_MANAGER_INTERFACE) + self.manager.RegisterAgent(self.path) + + log.info("Obex agent registered") + + def cleanup(self): + path = Path("/run/obex") + for f in path.iterdir(): + f.unlink() + + +def agent_method(*a, **kw): + return dbus_service_event_method(AGENT_INTERFACE, *a, **kw) + + +class ObexAgentObject(dbus.service.Object): + @mainloop_assert + def __init__(self, bus, path, events): + self.events = events + super().__init__(bus, path) + + AuthorizePush = agent_method("AuthorizePush", ("path",), "o", "s", sync=False) + Cancel = agent_method("Cancel") + + +def write_obex_file(name, content): + with open(f"/run/obex/{name}", "w") as f: + f.write(content) + + +def read_file(name): + with open(name, "r") as f: + return f.read() + + +# +# Direct Obex Python client API tests +# + + +class ObexClient(HostPlugin, EventPluginMixin): + name = "obex" + + @mainloop_wrap + def setup(self, impl): + EventPluginMixin.setup(self, impl) + + self.transferred = 0 + self.transfer_path = None + self.transfer_size = 0 + + self.bus = dbus.SessionBus() + self.bus.set_exit_on_disconnect(False) + self.log = logging.getLogger(self.name) + self.client = dbus.Interface( + self.bus.get_object(BUS_NAME, PATH), CLIENT_INTERFACE + ) + + self.bus.add_signal_receiver( + self.properties_changed, + dbus_interface="org.freedesktop.DBus.Properties", + signal_name="PropertiesChanged", + path_keyword="path", + ) + + @mainloop_wrap + def connect(self, bdaddr): + def reply(path): + obj = self.bus.get_object(BUS_NAME, path) + self.session = dbus.Interface(obj, SESSION_INTERFACE) + self.ftp = dbus.Interface(obj, FILE_TRANSFER_INTERFACE) + + self._object_method( + self.client, "CreateSession", bdaddr, {"Target": "ftp"}, reply_handler=reply + ) + + @mainloop_assert + def properties_changed(self, interface, properties, invalidated, path): + if path != self.transfer_path: + return + + if "Status" in properties and ( + properties["Status"] == "complete" or properties["Status"] == "error" + ): + self.events.put( + Event( + f"{FILE_TRANSFER_INTERFACE}:{properties['Status']}", + properties=properties, + ) + ) + self.log.debug(f"Transfer {properties['Status']}") + + if "Transferred" not in properties: + return + + value = properties["Transferred"] + speed = (value - self.transferred) / 1000 + self.log.debug( + f"Transfer progress {value}/{self.transfer_size} at {speed} kBps" + ) + self.transferred = value + + @mainloop_wrap + def ftp_list_folder(self): + return self.ftp.ListFolder() + + @mainloop_wrap + def ftp_get_file(self, dst, src): + path, properties = self.ftp.GetFile(dst, src) + self.transfer_path = path + self.transfer_size = properties["Size"] + return properties["Filename"] + + [email protected] +def paired_hosts(hosts): + from .test_agent import test_agent_pair_bredr + + if hosts[0].agent.has_device(hosts[1].bdaddr): + return hosts + + test_agent_pair_bredr(hosts, True) + return hosts + + +obex_host_config = host_config( + [Agent(), Obexd(), ObexClient(), Pexpect()], + [Agent(), Obexd(), ObexAgent()], + reuse=True, +) + + [email protected] +def obex_hosts(paired_hosts): + host0, host1 = paired_hosts + + if hasattr(host0, "session"): + return paired_hosts + + host0.obex.connect(host1.bdaddr) + + service = host1.agent.expect("org.bluez.Agent1.AuthorizeService") + assert service.uuid == FTP_UUID + host1.agent.reply() + + host0.obex.expect("org.bluez.obex.Client1.CreateSession:reply") + + yield paired_hosts + + host1.obex_agent.cleanup() + + +@obex_host_config +def test_obex_ftp_list(obex_hosts): + host0, host1 = obex_hosts + + host1.call(write_obex_file, "test", "1234") + + (item,) = host0.obex.ftp_list_folder() + assert item["Type"] == "file" + assert item["Name"] == "test" + assert item["Size"] == 4 + + +@obex_host_config +def test_obex_ftp_get(obex_hosts): + host0, host1 = obex_hosts + + host1.call(write_obex_file, "test", "1234") + + filename = host0.obex.ftp_get_file("", "test") + host0.obex.expect("org.bluez.obex.FileTransfer1:complete") + assert host0.call(read_file, filename) == "1234" + + +# +# obexctl tests +# + + [email protected] +def obexctl(obex_hosts): + host0, host1 = obex_hosts + + exe = find_exe("tools", "obexctl") + obexctl = host0.pexpect.spawn([exe]) + + obexctl.expect("Client /org/bluez/obex") + obexctl.send(f"connect {host1.bdaddr} {FTP_UUID}\n") + + service = host1.agent.expect("org.bluez.Agent1.AuthorizeService") + assert service.uuid == FTP_UUID + host1.agent.reply() + + obexctl.expect("Connection successful") + obexctl.send(f"select /org/bluez/obex/client/session1\n") + + yield obexctl + + obexctl.close() + + +@obex_host_config +def test_obexctl_list(obex_hosts, obexctl): + host0, host1 = obex_hosts + + host1.call(write_obex_file, "test", "1234") + + obexctl.send(f"ls\n") + obexctl.expect(f"Type: file") + obexctl.expect(f"Name: test") + obexctl.expect(f"Size: 4")
Signature · 1 line
2.54.0
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Hello:
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 9 lines · On Wed, 13 May 2026 19:17:17 +0300 you wrote:
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
*** v5 ***
https://github.com/pv/bluez/compare/func-test-v4-r..func-test-v5
[...]
Here is the summary with links:
- [BlueZ,v5,01/16] emulator: btvirt: check pkt lengths, don't get stuck on malformed
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e19c771841e9 - [BlueZ,v5,02/16] emulator: btvirt: allow specifying where server unix sockets are made https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=5ee43f9993dd - [BlueZ,v5,03/16] emulator: btvirt: support SCO data packets https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=cc077e4a12dd - [BlueZ,v5,04/16] emulator: btdev: clear more state on Reset https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f1a303e1d07a - [BlueZ,v5,05/16] test-runner: enable path argument for --unix https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ff2ecb82e4c3 - [BlueZ,v5,06/16] test-runner: Add -o/--option option https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=82c635c879bf - [BlueZ,v5,07/16] test-runner: allow source tree root for -k https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1929b3a99d2f - [BlueZ,v5,08/16] test-runner: use virtio-serial for implementing -u device forwarding https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=908c14fc3abb - [BlueZ,v5,09/16] doc: enable CONFIG_VIRTIO_CONSOLE in tester config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7856de4d69d6 - [BlueZ,v5,10/16] doc: enable KVM paravirtualization & clock support in tester kernel config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=48cb22a572c7
- [BlueZ,v5,11/16] doc: add functional/integration testing documentation (no matching commit)
- [BlueZ,v5,12/16] test: add functional/integration testing framework (no matching commit)
- [BlueZ,v5,13/16] build: add functional testing target
(no matching commit)
- [BlueZ,v5,14/16] test: functional: impose Python code formatting (no matching commit)
- [BlueZ,v5,15/16] test: functional: add some Agent1 interface tests (no matching commit)
- [BlueZ,v5,16/16] test: functional: add basic obex file transfer tests (no matching commit)
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html
Luiz Augusto von Dentz
maintainerHi Pauli,
Quoted 30 lines · On Thu, May 14, 2026 at 1:51 PM <[email protected]> wrote:
Hello:
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 9 lines · On Wed, 13 May 2026 19:17:17 +0300 you wrote:
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
*** v5 ***
https://github.com/pv/bluez/compare/func-test-v4-r..func-test-v5
[...]
Here is the summary with links:
- [BlueZ,v5,01/16] emulator: btvirt: check pkt lengths, don't get stuck on malformedhttps://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e19c771841e9 - [BlueZ,v5,02/16] emulator: btvirt: allow specifying where server unix sockets are made https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=5ee43f9993dd - [BlueZ,v5,03/16] emulator: btvirt: support SCO data packets https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=cc077e4a12dd - [BlueZ,v5,04/16] emulator: btdev: clear more state on Reset https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f1a303e1d07a - [BlueZ,v5,05/16] test-runner: enable path argument for --unix https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ff2ecb82e4c3 - [BlueZ,v5,06/16] test-runner: Add -o/--option option https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=82c635c879bf
Quoted 8 lines
- [BlueZ,v5,07/16] test-runner: allow source tree root for -k
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1929b3a99d2f - [BlueZ,v5,08/16] test-runner: use virtio-serial for implementing -u device forwarding https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=908c14fc3abb - [BlueZ,v5,09/16] doc: enable CONFIG_VIRTIO_CONSOLE in tester config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7856de4d69d6 - [BlueZ,v5,10/16] doc: enable KVM paravirtualization & clock support in tester kernel config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=48cb22a572c7
Push the ones that didn't introduce new functionality, there were some complaints from the likes of checkpatch regarding scripts with execute permission, and Id like to go more in detail about how to write tests and what is the RPC message protocol since we could in teory use the same protocol used for autopts for example.
Quoted 20 lines
- [BlueZ,v5,11/16] doc: add functional/integration testing documentation (no matching commit)
- [BlueZ,v5,12/16] test: add functional/integration testing framework (no matching commit)
- [BlueZ,v5,13/16] build: add functional testing target
(no matching commit)
- [BlueZ,v5,14/16] test: functional: impose Python code formatting (no matching commit)
- [BlueZ,v5,15/16] test: functional: add some Agent1 interface tests (no matching commit)
- [BlueZ,v5,16/16] test: functional: add basic obex file transfer tests (no matching commit)You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
Signature · 1 line
Luiz Augusto von Dentz
Hi,
to, 2026-05-14 kello 15:11 -0400, Luiz Augusto von Dentz kirjoitti:
Quoted 40 lines · On Thu, May 14, 2026 at 1:51 PM <[email protected]> wrote:
Quoted 30 lines
Hello:
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 9 lines · On Wed, 13 May 2026 19:17:17 +0300 you wrote:
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
*** v5 ***
https://github.com/pv/bluez/compare/func-test-v4-r..func-test-v5
[...]
Here is the summary with links:
- [BlueZ,v5,01/16] emulator: btvirt: check pkt lengths, don't get stuck on malformedhttps://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e19c771841e9 - [BlueZ,v5,02/16] emulator: btvirt: allow specifying where server unix sockets are made https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=5ee43f9993dd - [BlueZ,v5,03/16] emulator: btvirt: support SCO data packets https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=cc077e4a12dd - [BlueZ,v5,04/16] emulator: btdev: clear more state on Reset https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f1a303e1d07a - [BlueZ,v5,05/16] test-runner: enable path argument for --unix https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ff2ecb82e4c3 - [BlueZ,v5,06/16] test-runner: Add -o/--option option https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=82c635c879bfQuoted 8 lines
- [BlueZ,v5,07/16] test-runner: allow source tree root for -k
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1929b3a99d2f - [BlueZ,v5,08/16] test-runner: use virtio-serial for implementing -u device forwarding https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=908c14fc3abb - [BlueZ,v5,09/16] doc: enable CONFIG_VIRTIO_CONSOLE in tester config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7856de4d69d6 - [BlueZ,v5,10/16] doc: enable KVM paravirtualization & clock support in tester kernel config https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=48cb22a572c7
Quoted 3 lines
Push the ones that didn't introduce new functionality, there were some complaints from the likes of checkpatch regarding scripts with execute permission,
This checkpatch warning I don't get, the repository already has a large number of executable scripts, and isn't that more convenient?
IIUC the warning is about +x bits on random source files, which is not the case here.
Quoted 3 lines
and Id like to go more in detail about how to write tests
and what is the RPC message protocol since we could in teory use the same protocol used for autopts for example.
Generally the idea in the design here is that the plugins add arbitrary test-specific capabilities to the lower tester / IUTs, and the 'test_*' functions are the upper tester which uses the plugins to orchestrate the test and obtain data to verify the outcome.
It's straightforward to write test-specific plugins, so you are not required to write something like a separate monolithic BTP client. You can reuse btpclient etc. of course if useful.
There are several examples of full-stack BlueZ<->BlueZ integration tests in the series.
Examples of PTS-style unit tests where lower tester probes specific parts should still be figured out are missing though.
The main issue here is the lower tester BT stack, it will need to have controlled mock functionality. Maybe this could be still BlueZ, but with plugins disabled and we do raw ATT / GATT, or through BlueZ GATT DBus API. Or, use something like https://google.github.io/bumble/ to talk to the btvirt controller directly.
For reusing autopts, I would just add a plugin that launches the client in the upper tester / IUT, and talks to it in their XML-RPC protocol, encapsulating any protocols used. The autopts protocols appear somewhat tied to details of the PTS implementation, doesn't seem like a good idea to use it natively as it's more complex and I don't see what would be really gained from it.
AFAIK it's not possible to use the full PTS infrastructure here, the important parts are closed source and not license compatible.
Quoted 22 lines
Quoted 21 lines
- [BlueZ,v5,11/16] doc: add functional/integration testing documentation (no matching commit)
- [BlueZ,v5,12/16] test: add functional/integration testing framework (no matching commit)
- [BlueZ,v5,13/16] build: add functional testing target
(no matching commit)
- [BlueZ,v5,14/16] test: functional: impose Python code formatting (no matching commit)
- [BlueZ,v5,15/16] test: functional: add some Agent1 interface tests (no matching commit)
- [BlueZ,v5,16/16] test: functional: add basic obex file transfer tests (no matching commit)You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
Signature · 1 line
Pauli Virtanen
Luiz Augusto von Dentz
maintainerHi Pauli,
Quoted 425 lines · Pauli Virtanen
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
*** v5 ***
https://github.com/pv/bluez/compare/func-test-v4-r..func-test-v5
* Factor out the pytest-bluezenv plugin, to be maintained separately.
https://pypi.org/project/pytest-bluezenv/It could in principle be moved under the BlueZ organization, but there's no particular reason why it should be in bluez repository.
Generally, it's better to have the pytest plugin separate so it's easier to reuse and can have its own version cycle.
* Pipewire tests are moved to pipewire repository where they probably belong to.
They can be run easily vs. given BlueZ build dir.
We are currently running them in Pipewire CI, but at frozen kernel/BlueZ version, so it is not testing BlueZ/kernel upstream development.
* No changes in the emulator/test-runner patches since v4
They are stand-alone bug fixes / improvements, and make sense also separately from the rest.
*** v4 ***
https://github.com/pv/bluez/compare/func-test-v3-r..func-test-v4
* Use virtconsole for simpler HCI forwarding to the vm
* Fix typoed
vm_module->vm_once* Skip tests for some pipewire versions
*** v3 ***
https://github.com/pv/bluez/compare/func-test-v2-r..func-test-v3
* fix configure.ac
openpty()detection to match TOOLS conditional, to fix make distcheck* properly retry virtio RPC connection if it fails initially
* properly restart VM if previous test hangs
* allow custom parent host side proxy objects, use them for pexpect
* improve --list with out-of-tree test files
* fix missing
bus.set_exit_on_disconnect(False)for obex tests* have --vm-timeout etc. change values also on VM host side
* use larger-memory VM instances for Pipewire, in case ASAN enabled
* set reasonable inside-VM
ASAN_OPTIONdefault values* don't run btvirt under stdbuf, since not compatible with ASAN
*** v2 ***
https://github.com/pv/bluez/compare/func-test-v1-r..func-test-v2
* move unit/func_test -> test/functional & test/pytest_bluez
The
pytest_bluezplugin is in principle reusable for other projects, so we can eg. have more complete Pipewire integration tests that can live in Pipewire repository.*
openpty()is in -lutil on some platforms, detect this in autoconf* more emulator adjustments:
- fix SCO data packet support in btvirt
- more complete Reset command* improve logging: get timestamps from kernel, and reorder logs to timestamp order, so that lines from different hosts, btmon, and parent tester appear in right order regardless of whether VM console / btmon is lagging
- this requires accurate clock sync in the VM, so enable KVM PTP in config and run chronyd inside the VMs
- use virtio port instead of qemu console to export logs, since the console has fixed baud rate and is too slow* add --btmon & export btsnoop dumps from VM hosts
* fix compatibility with older Python versions
* add
parametrized_host_config()* split Pipewire test to A2DP/BAP/HFP and really stream audio. These catch the 5.86 regression fixed in
066a164a524e498and the 5.84 one in6b0a08776a* add support for tests that reuse tester environment, so they can run faster without needing Bluetoothd teardown/setup in between
* add HostPlugin.presetup (mainly for test skipping)
* deal with RPC virtio port buffer possibly containing unflushed commands from previous failed test
* add some Agent1 interface tests
* add basic Obex file transfer tests
* add support for logging in to a running test instance (for gdb etc)
* export any core dumps out from test environ
Some bells & whistles:
* add --kernel-build for kernel image build
* test suite Python code formatting checks
***
Implements:
- RPC communication with tester instances running each of the VM hosts. Tests run on parent host, which instructs VM hosts what to do.
- Extensible way to add stateful test-specific code inside the VM instances
- Logging control: output from different processes running inside the VM are separated and can be filtered.
- Test runner framework with Pytest (more convenient than Python/unittest)
- Automatic grouping of tests to minimize VM reboots
- Redirecting USB controllers to use for testing in addition to btvirt
- Fairly straightforward, ~1600 sloc for the framework
There is no requirement that the tests spawn VM instances, the test runner can be used for any tests written in Python.
See
doc/test-functional.rstfor various examples.Also
test/functional/test_bluetoothctl_vm.pyhas some simple cases, andtest/functional/test_pipewire.pyfor a more complicated setuphost0(qemu): Pipewire <-> BlueZ <-> kernel <-> btvirt host1(qemu): kernel <-> BlueZ <-> PipewireThe framework allows easily passing any data and code between the parent and VM hosts, so writing tests is straightforward.
***
Some examples:
$ test/test-functional --list -qtest/functional/lib/tests/test_rpc.py::test_basic test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_script_show[hosts1-vm1] test/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] test/functional/test_pipewire.py::test_pipewire[hosts3-vm2]
$ test/test-functional -v --no-header ======================================= test session starts ======================================== collected 5 itemstest/functional/lib/tests/test_rpc.py::test_basic PASSED [ 20%] test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_script_show[hosts1-vm1] SKIPPED [ 40%] test/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] SKIPPED (No kernel image) [ 60%]test/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] SKIPPED (No k...) [ 80%]
test/functional/test_pipewire.py::test_pipewire[hosts3-vm2] SKIPPED (No kernel image) [100%]=================================== 1 passed, 4 skipped in 0.19s ===================================
$ test/test-functional --kernel=../linux ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 itemstest/functional/lib/tests/test_rpc.py . [ 20%] test/functional/test_bluetoothctl_vm.py . [ 40%] test/functional/test_btmgmt_vm.py . [ 60%] test/functional/test_bluetoothctl_vm.py . [ 80%] test/functional/test_pipewire.py . [100%]============================== 5 passed in 41.92s ==============================
$ test/test-functional --kernel=../linux -k test_btmgmt ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_btmgmt_vm.py. [100%]======================= 1 passed, 4 deselected in 9.15s ========================
$ grep btmgmt test-functional.log 13:15:42 INFO rpc.host.0.0 : client: call_plugin ('call', '__call__', <function run at 0x7f27b81ce140>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'} 13:15:42 INFO host.0.0.rpc : server: call_plugin ('call', '__call__', <function run at 0x7fd5e35a1010>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'} 13:15:42 INFO host.0.0.run : $ /home/pauli/prj/external/bluez/build/tools/btmgmt --index 0 info$ test/test-functional --kernel=../linux -k test_btmgmt --log-cli-level=0 ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selectedtest/functional/test_btmgmt_vm.py::test_btmgmt_info[hosts2-vm1] -------------------------------- live log setup --------------------------------
13:00:31 INFO func_test.lib.env : Starting btvirt: /usr/bin/stdbuf -o L -e L /home/pauli/prj/external/bluez/build/emulator/btvirt --server=/tmp/bluez-func-test-8t6ychy8 13:00:31 OUT btvirt : Bluetooth emulator ver 5.86 13:00:31 INFO func_test.lib.env : Starting host: /home/pauli/prj/external/bluez/build/tools/test-runner --kernel=../linux/arch/x86/boot/bzImage -u/tmp/bluez-func-test-8t6ychy8/bt-server-bredrle -o -chardev -o socket,id=ser0,path=/tmp/bluez-func-test-8t6ychy8/bluez-func-test-rpc-0,server=on,wait=off -o -device -o virtio-serial -o -device -o virtserialport,chardev=ser0,name=bluez-func-test-rpc -H -- /usr/bin/python3 -P /home/pauli/prj/external/bluez/test/functional/lib/runner.py /dev/ttyS2 13:00:31 OUT btvirt : Request for /tmp/bluez-func-test-8t6ychy8/bt-server-bredrle 13:00:32 OUT host.0.0 : early console in extract_kernel 13:00:32 OUT host.0.0 : input_data: 0x000000000425c2c4 ... 13:00:39 INFO rpc.host.0.0 : client: call_plugin ('call', '__call__', <function run at 0x7f7547472140>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'} 13:00:39 DEBUG host.0.0.rpc : server: done 13:00:39 INFO host.0.0.rpc : server: call_plugin ('call', '__call__', <function run at 0x7f77dcc81010>, ['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info']) {'stdout': -1, 'stdin': -3, 'encoding': 'utf-8'} 13:00:39 INFO host.0.0.run : $ /home/pauli/prj/external/bluez/build/tools/btmgmt --index 0 info 13:00:40 OUT host.0.0.run.out : hci0: Primary controller 13:00:40 OUT host.0.0.run.out : addr 00:AA:01:00:00:42 version 11 manufacturer 1521 class 0x000000 13:00:40 OUT host.0.0.run.out : supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver 13:00:40 OUT host.0.0.run.out : current settings: br/edr 13:00:40 OUT host.0.0.run.out : name 13:00:40 OUT host.0.0.run.out : short name 13:00:40 INFO host.0.0.run : (return code 0) 13:00:40 DEBUG rpc.host.0.0 : client-replyPASSED [100%]
13:00:40 OUT host.0.0 : qemu-system-x86_64: terminating on signal 15 from pid 149047 (python3)
======================= 1 passed, 4 deselected in 8.84s ========================$ test/test-functional --kernel=../linux -k test_bluetoothctl_pair --log-cli-level=0 --log-filter=*.bluetoothctl,rpc.* --force-usb ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selectedtest/functional/test_bluetoothctl_vm.py::test_bluetoothctl_pair[hosts0-vm2] -------------------------------- live log setup --------------------------------
13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bdaddr object at 0x7f268712d160>,) {} 13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Call object at 0x7f268712d2b0>,) {} 13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.DbusSystem object at 0x7f2687aa30e0>,) {} 13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bluetoothd object at 0x7f2687aa3230>,) {} 13:03:20 INFO rpc.host.0.0 : client: start_load (<func_test.lib.host_plugins.Bluetoothctl object at 0x7f268712d010>,) {} 13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bdaddr object at 0x7f26871542d0>,) {} 13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Call object at 0x7f2687154410>,) {} 13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.DbusSystem object at 0x7f2687aa30e0>,) {} 13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bluetoothd object at 0x7f2687aa3230>,) {} 13:03:20 INFO rpc.host.0.1 : client: start_load (<func_test.lib.host_plugins.Bluetoothctl object at 0x7f2687154190>,) {} 13:03:20 INFO rpc.host.0.0 : client: wait_load () {} 13:03:21 DEBUG rpc.host.0.0 : client-reply 13:03:21 INFO rpc.host.0.1 : client: wait_load () {} 13:03:21 DEBUG rpc.host.0.1 : client-reply -------------------------------- live log call --------------------------------- 13:03:21 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'show\n') {} 13:03:21 DEBUG rpc.host.0.0 : client-reply 13:03:21 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Powered: yes') {} ... 13:03:23 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'pair 70:1a:b8:73:99:bb\n') {} 13:03:23 OUT host.0.0.bluetoothctl: pair 70:1a:b8:73:99:bb 13:03:23 DEBUG rpc.host.0.0 : client-reply 13:03:23 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Confirm passkey (\\d+).*:') {} 13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> pair 70:1a:b8:73:99:bb 13:03:23 OUT host.0.0.bluetoothctl: Attempting to pair with 70:1A:B8:73:99:BB 13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 device_flags_changed: 70:1A:B8:73:99:BB (BR/EDR) 13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> supp: 0x00000007 curr: 0x00000000 13:03:23 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 type 7 discovering off 13:03:25 OUT host.0.0.bluetoothctl: [bluetoothctl]> hci0 70:1A:B8:73:99:BB type BR/EDR connected eir_len 12 13:03:25 OUT host.0.0.bluetoothctl: [bluetoothctl]> [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB Connected: yes 13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> Request confirmation 13:03:25 DEBUG rpc.host.0.0 : client-reply 13:03:25 INFO rpc.host.0.1 : client: call_plugin ('bluetoothctl', 'expect', 'Confirm passkey 237345') {} 13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> hci0 84:5C:F3:77:31:19 type BR/EDR connected eir_len 12 13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> [NEW] Device 84:5C:F3:77:31:19 BlueZ 5.86 13:03:25 DEBUG rpc.host.0.1 : client-reply 13:03:25 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'send', 'yes\n') {} 13:03:25 OUT host.0.1.bluetoothctl: [bluetoothctl]> [BlueZ 5.86]> Request confirmation 13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [agent] Confirm passkey 237345 (yes/no): yes 13:03:25 DEBUG rpc.host.0.0 : client-reply 13:03:25 INFO rpc.host.0.1 : client: call_plugin ('bluetoothctl', 'send', 'yes\n') {} 13:03:25 OUT host.0.1.bluetoothctl: [BlueZ 5.86]> [agent] Confirm passkey 237345 (yes/no): yes 13:03:25 DEBUG rpc.host.0.1 : client-reply 13:03:25 INFO rpc.host.0.0 : client: call_plugin ('bluetoothctl', 'expect', 'Pairing successful') {} 13:03:25 OUT host.0.0.bluetoothctl: yes 13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> hci0 new_link_key 70:1A:B8:73:99:BB type 0x08 pin_len 0 store_hint 1 13:03:25 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB Bonded: yes 13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB AddressType: public 13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB UUIDs: 0000110c-0000-1000-8000-00805f9b34fb 13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:73:99:BB UUIDs: 0000110e-0000-1000-8000-00805f9b34fb 13:03:26 DEBUG rpc.host.0.0 : client-replyPASSED [100%]
------------------------------ live log teardown -------------------------------
13:03:26 OUT host.0.0.bluetoothctl: [BlueZ 5.86]> [CHG] Device 70:1A:B8:98:FF:qemu-system-x86_64: terminating on signal 15 from pid 149357 (python3)======================= 1 passed, 4 deselected in 13.22s =======================
$ test/test-functional -k test_btmgmt --kernel=../linux --trace ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 rootdir: /home/pauli/prj/external/bluez/unit configfile: pytest.ini plugins: cov-5.0.0, forked-1.6.0, rerunfailures-15.0, timeout-2.4.0, xdist-3.7.0, hypothesis-6.123.0, flaky-3.8.1, anyio-4.12.1 collected 5 items / 4 deselected / 1 selected
test/functional/test_btmgmt_vm.pyQuoted 2 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
PDB runcall (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(19)test_btmgmt_info()
-> (host,) = hosts
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(21)test_btmgmt_info()
-> result = host.call(
(Pdb) p host.bdaddr
'00:aa:01:00:00:42'
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(22)test_btmgmt_info()
-> run,
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(23)test_btmgmt_info()
-> [btmgmt, "--index", "0", "info"],
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(24)test_btmgmt_info()
-> stdout=subprocess.PIPE,
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(25)test_btmgmt_info()
-> stdin=subprocess.DEVNULL,
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(26)test_btmgmt_info()
-> encoding="utf-8",
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(21)test_btmgmt_info()
-> result = host.call(
(Pdb) nQuoted 1 line
/home/pauli/prj/external/bluez/test/functional/test_btmgmt_vm.py(28)test_btmgmt_info()
-> assert result.returncode == 0
(Pdb) p result
CompletedProcess(args=['/home/pauli/prj/external/bluez/build/tools/btmgmt', '--index', '0', 'info'], returncode=0, stdout='hci0:\tPrimary controller\n\taddr 00:AA:01:00:00:42 version 11 manufacturer 1521 class 0x000000\n\tsupported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver \n\tcurrent settings: br/edr \n\tname \n\tshort name \n') (Pdb) print(result.stdout)
hci0: Primary controller
addr 00:AA:01:00:00:42 version 11 manufacturer 1521 class0x000000
supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy static-addr phy-configuration cis-central cis-peripheral iso-broadcaster sync-receiver ll-privacy past-sender past-receiver
current settings: br/edr
name
short name
(Pdb) q!!!!!!!!!!!!!!!!!!! _pytest.outcomes.Exit: Quitting debugger !!!!!!!!!!!!!!!!!!! ======================= 4 deselected in 75.91s (0:01:15) =======================
Pauli Virtanen (16):
emulator: btvirt: check pkt lengths, don't get stuck on malformed
emulator: btvirt: allow specifying where server unix sockets are made
emulator: btvirt: support SCO data packets
emulator: btdev: clear more state on Reset
test-runner: enable path argument for --unix
test-runner: Add -o/--option option
test-runner: allow source tree root for -k
test-runner: use virtio-serial for implementing -u device forwarding
doc: enableCONFIG_VIRTIO_CONSOLEin tester config
doc: enable KVM paravirtualization & clock support in tester kernel
config
doc: add functional/integration testing documentation
test: add functional/integration testing framework
build: add functional testing target
test: functional: impose Python code formatting
test: functional: add some Agent1 interface tests
test: functional: add basic obex file transfer testsMakefile.am | 10 + configure.ac | 22 ++ doc/ci.config | 9 + doc/test-functional.rst | 299 ++++++++++++++++++++++++ doc/test-runner.rst | 17 ++ doc/tester.config | 9 + emulator/btdev.c | 117 ++++++---- emulator/main.c | 37 +-- emulator/server.c | 21 ++ test/functional/__init__.py | 2 + test/functional/conftest.py | 48 ++++ test/functional/requirements.txt | 2 + test/functional/test_agent.py | 46 ++++ test/functional/test_bluetoothctl_vm.py | 152 ++++++++++++ test/functional/test_btmgmt_vm.py | 30 +++ test/functional/test_obex.py | 285 ++++++++++++++++++++++ test/functional/test_tests.py | 23 ++ test/pytest.ini | 17 ++ test/test-functional | 21 ++ test/test-functional-attach | 7 + tools/test-runner.c | 89 ++++--- 21 files changed, 1177 insertions(+), 86 deletions(-) create mode 100644 doc/test-functional.rst create mode 100644 test/functional/__init__.py create mode 100644 test/functional/conftest.py create mode 100644 test/functional/requirements.txt create mode 100644 test/functional/test_agent.py create mode 100644 test/functional/test_bluetoothctl_vm.py create mode 100644 test/functional/test_btmgmt_vm.py create mode 100644 test/functional/test_obex.py create mode 100644 test/functional/test_tests.py create mode 100644 test/pytest.ini create mode 100755 test/test-functional create mode 100755 test/test-functional-attach
Quoted 2 lines
--
2.54.0
Do you mind resending the remaining changes? I'd like to see how it works; it seems you've already integrated with things like make check, right?
Signature · 1 line
Luiz Augusto von Dentz
Hi,
pe, 2026-06-12 kello 17:13 -0300, Luiz Augusto von Dentz kirjoitti:
Quoted 7 lines
Hi Pauli,
Quoted 4 lines · Pauli Virtanen
Add framework for writing tests simulating "real" environments where BlueZ and other parts of the stack run on different virtual machine hosts that communicate with each other.
[clip]
Quoted 15 lines
Quoted 15 lines
21 files changed, 1177 insertions(+), 86 deletions(-) create mode 100644 doc/test-functional.rst create mode 100644 test/functional/__init__.py create mode 100644 test/functional/conftest.py create mode 100644 test/functional/requirements.txt create mode 100644 test/functional/test_agent.py create mode 100644 test/functional/test_bluetoothctl_vm.py create mode 100644 test/functional/test_btmgmt_vm.py create mode 100644 test/functional/test_obex.py create mode 100644 test/functional/test_tests.py create mode 100644 test/pytest.ini create mode 100755 test/test-functional create mode 100755 test/test-functional-attach
Quoted 6 lines
Quoted 2 lines
--
2.54.0Do you mind resending the remaining changes? I'd like to see how it works; it seems you've already integrated with things like
make check, right?
Sent v6.
Note it's failing on current bluetooth-next kernel due to hci_uart bug introduced recently, needs something like this to fix it: