mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-05-24 21:38:05 -04:00
test: add VM-based full-stack bluetooth tests
Add tests that check PipeWire <-> PipeWire bluetooth audio streaming for A2DP, BAP, HFP. The tests use Qemu VMs and don't require Bluetooth support from HW / kernel. Full VM images are not required; similarly to BlueZ kernel tester these use (read-only) mount of host filesystem. A monolithic kernel image with suitable config is required. The bluetoothd binary installed on host is used if found; otherwise tests are skipped. These test depend on https://github.com/pv/pytest-bluezenv which manages the VM setup. To launch: python3 -m pip install pytest-bluezenv meson devenv -C builddir -w . python3 -m pytest test --kernel-build -v which also builds a kernel image with required options.
This commit is contained in:
parent
708cb6e2e8
commit
d12367e10e
4 changed files with 680 additions and 0 deletions
95
test/bluezenv/conftest.py
Normal file
95
test/bluezenv/conftest.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# -*- coding: utf-8; mode: python; eval: (blacken-mode); -*-
|
||||
# SPDX-FileCopyrightText: Copyright © 2026 Pauli Virtanen
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import pytest
|
||||
import warnings
|
||||
|
||||
from pytest_bluezenv import Bluetoothd
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def paired_hosts(hosts, host_setup):
|
||||
"""
|
||||
Provide two hosts, paired with each other, and the first one Central
|
||||
"""
|
||||
|
||||
le = any(
|
||||
"ControllerMode = le" in (p.conf or "")
|
||||
for plugins in host_setup["setup"]
|
||||
for p in plugins
|
||||
if isinstance(p, Bluetoothd)
|
||||
)
|
||||
|
||||
if le:
|
||||
yield from _pair_le(hosts)
|
||||
else:
|
||||
yield from _pair_bredr(hosts)
|
||||
|
||||
|
||||
def _pair_bredr(hosts):
|
||||
host0, host1 = hosts
|
||||
|
||||
host0.bluetoothctl.send("scan on\n")
|
||||
host0.bluetoothctl.expect(f"Controller {host0.bdaddr.upper()} Discovering: yes")
|
||||
|
||||
host1.bluetoothctl.send("pairable on\n")
|
||||
host1.bluetoothctl.expect("Changing pairable on succeeded")
|
||||
host1.bluetoothctl.send("discoverable on\n")
|
||||
host1.bluetoothctl.expect(f"Controller {host1.bdaddr.upper()} Discoverable: yes")
|
||||
|
||||
host0.bluetoothctl.expect(f"Device {host1.bdaddr.upper()}")
|
||||
host0.bluetoothctl.send(f"pair {host1.bdaddr}\n")
|
||||
|
||||
idx, m = host0.bluetoothctl.expect(r"Confirm passkey (\d+).*:")
|
||||
key = m[0].decode("utf-8")
|
||||
|
||||
host1.bluetoothctl.expect(f"Confirm passkey {key}")
|
||||
|
||||
host0.bluetoothctl.send("yes\n")
|
||||
host1.bluetoothctl.send("yes\n")
|
||||
|
||||
host0.bluetoothctl.expect("Pairing successful")
|
||||
|
||||
yield hosts
|
||||
|
||||
|
||||
def _pair_le(hosts):
|
||||
host0, host1 = hosts
|
||||
|
||||
host0.bluetoothctl.send("scan on\n")
|
||||
host0.bluetoothctl.expect(f"Controller {host0.bdaddr.upper()} Discovering: yes")
|
||||
|
||||
host1.bluetoothctl.send("advertise on\n")
|
||||
host1.bluetoothctl.expect("Advertising object registered")
|
||||
|
||||
host0.bluetoothctl.expect(f"Device {host1.bdaddr.upper()}")
|
||||
host0.bluetoothctl.send(f"pair {host1.bdaddr.upper()}\n")
|
||||
|
||||
# BUG!: if controller is power cycled off/on at boot (before bluetoothd)
|
||||
# BUG!: which is what the tester here does,
|
||||
# BUG!: bluetoothd MGMT command to enable Secure Connections Host Support
|
||||
# BUG!: fails and we are left with legacy passkey. It seems we get randomly
|
||||
# BUG!: one of these depending on what state controller/kernel were before
|
||||
# BUG!: btmgmt power off/on
|
||||
|
||||
idx, m = host0.bluetoothctl.expect(
|
||||
[r"\[agent\].*Passkey:.*m(\d+)", r"Confirm passkey (\d+).*:"]
|
||||
)
|
||||
key = m[0].decode("utf-8")
|
||||
|
||||
if idx == 0:
|
||||
warnings.warn(
|
||||
"BUG: we got passkey authentication, bluetoothd/kernel should be fixed"
|
||||
)
|
||||
host1.bluetoothctl.expect(r"\[agent\] Enter passkey \(number in 0-999999\):")
|
||||
host1.bluetoothctl.send(f"{key}\n")
|
||||
else:
|
||||
host1.bluetoothctl.expect(f"Confirm passkey {key}")
|
||||
|
||||
host0.bluetoothctl.send("yes\n")
|
||||
host1.bluetoothctl.send("yes\n")
|
||||
|
||||
host0.bluetoothctl.expect("Pairing successful")
|
||||
|
||||
yield hosts
|
||||
Loading…
Add table
Add a link
Reference in a new issue