1# Lint as: python2, python3
2# Copyright 2021 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""A Batch of of Bluetooth enterprise policy health tests"""
7
8from __future__ import absolute_import
9from __future__ import division
10from __future__ import print_function
11
12import time
13
14from six.moves import zip
15
16from autotest_lib.client.common_lib import error
17from autotest_lib.client.cros.bluetooth.bluetooth_audio_test_data import A2DP
18from autotest_lib.server.cros.bluetooth.bluetooth_adapter_quick_tests import (
19        BluetoothAdapterQuickTests)
20from autotest_lib.server.cros.bluetooth.bluetooth_adapter_audio_tests import (
21        BluetoothAdapterAudioTests)
22from autotest_lib.server.cros.bluetooth.bluetooth_adapter_hidreports_tests \
23        import BluetoothAdapterHIDReportTests
24
25from autotest_lib.server.cros.bluetooth.bluetooth_test_utils import (
26        BluetoothPolicy)
27
28
29class bluetooth_AdapterEPHealth(BluetoothAdapterQuickTests,
30                                BluetoothAdapterAudioTests,
31                                BluetoothAdapterHIDReportTests):
32    """A Batch of Bluetooth enterprise policy health tests."""
33
34    # A delay for disconnection to finish.
35    DISCONNECT_SLEEP_SECS = 2
36
37    # With raspberry pi peer, it takes a moment before the device is
38    # registered as an input device. Without delay, the input recorder
39    # doesn't find the device
40    CONNECT_SLEEP_SECS = 1
41
42    test_wrapper = BluetoothAdapterQuickTests.quick_test_test_decorator
43    batch_wrapper = BluetoothAdapterQuickTests.quick_test_batch_decorator
44
45
46    def get_device_verifier(self, device, expected_pass):
47        """Helper function to get a proper test method for verifying device
48           avalibility depending on its type
49
50        @param device: a peer device
51        @param expected_pass: True if the test is expected to pass
52        @returns: a test method if the device type can be recongnized,
53                  None otherwise.
54        """
55        if device.device_type == 'KEYBOARD':
56            return self.run_keyboard_tests
57        elif device.device_type == 'MOUSE':
58            return self.test_mouse_left_click
59        elif device.device_type == 'BLUETOOTH_AUDIO':
60            # If the test is expected to pass, verify the whole audio procedure
61            # Otherwise only make sure A2DP is not connected on peer device.
62            if expected_pass:
63                return lambda device: self.test_a2dp_sinewaves(device, A2DP, 0)
64            else:
65                return lambda device: self.test_device_a2dp_connected(device)
66        else:
67            raise error.TestError('Failed to find verifier for device type %s' %
68                                  device.device_type)
69
70
71    def ep_outgoing_connection(self, device, expected_pass):
72        """Run outoging connection tests
73
74        @param device: the peer device
75        @param expected_pass: True if the test is expected to pass
76        """
77        self.test_discover_device(device.address)
78        time.sleep(self.TEST_SLEEP_SECS)
79
80        self.test_pairing(device.address, device.pin, trusted=True)
81        time.sleep(self.CONNECT_SLEEP_SECS)
82
83
84    def ep_incoming_connection(self, device, expected_pass):
85        """Run incoming connection tests
86
87        @param device: the peer device
88        @param expected_pass: True if the test is expected to pass
89        """
90        self.test_discover_device(device.address)
91        time.sleep(self.TEST_SLEEP_SECS)
92
93        self.test_pairing(device.address, device.pin, trusted=True)
94        time.sleep(self.CONNECT_SLEEP_SECS)
95
96        self.test_disconnection_by_device(device)
97        time.sleep(self.DISCONNECT_SLEEP_SECS)
98
99        if expected_pass:
100            self.test_connection_by_device(device)
101        else:
102            # ignore the result of connection by device since bluez could
103            # disconnect the device connection if there is no service
104            # available
105            adapter_address = self.bluetooth_facade.address
106            device.ConnectToRemoteAddress(adapter_address)
107        time.sleep(self.CONNECT_SLEEP_SECS)
108
109
110    def ep_auto_reconnection(self, device, expected_pass):
111        """Run auto reconnection tests
112
113        @param device: the peer device
114        @param expected_pass: True if the test is expected to pass
115        """
116        self.test_discover_device(device.address)
117        time.sleep(self.TEST_SLEEP_SECS)
118
119        self.test_pairing(device.address, device.pin, trusted=True)
120        time.sleep(self.CONNECT_SLEEP_SECS)
121
122        device.AdapterPowerOff()
123        time.sleep(self.TEST_SLEEP_SECS)
124        # device should be connected after power on
125        device.AdapterPowerOn()
126
127
128    def reset_allowlist_and_raise_fail(self, err_msg):
129        """Reset the allowlist and raise TestFail.
130
131        @param err_msg: the error message
132        """
133        self.test_reset_allowlist()
134        raise error.TestFail(err_msg)
135
136
137    def post_test_method(self, device):
138        """Run tests to make sure the device is not connected and not paired to
139        host
140
141        @param device: the peer device
142        """
143
144        self.test_disconnection_by_adapter(device.address)
145        self.test_remove_pairing(device.address)
146
147    def run_test_method(self, pre_test_method, devices, uuids='',
148                        expected_passes=True):
149        """Run specified pre_test_method and verify devices can be used.
150
151        @param pre_test_method: the test method to run before verification
152        @param devices: a peer device or a list of peer devices
153        @param uuids: the uuids in the allowlist to set.
154                If uuids is None, it means not to set Allowlist.
155                The default value is '' which means to allow all UUIDs.
156        @param expected_passes: a boolean value or a list of boolean value,
157                each element is True if the ep_test_method is expected to pass.
158                The default value is a single value of True.
159        """
160        has_audio_device = False
161
162        if uuids is not None:
163            self.test_check_set_allowlist(uuids, True)
164
165        if type(devices) is not list:
166            devices = [devices]
167
168        if type(expected_passes) is not list:
169            expected_passes = [expected_passes]
170
171        for device, expected_pass in zip(devices, expected_passes):
172            if device.device_type == 'BLUETOOTH_AUDIO':
173                self.initialize_bluetooth_audio(device, A2DP)
174                has_audio_device = True
175            pre_test_method(device, expected_pass)
176
177        # TODO(b:219398837) Remove this once b/219398837 is fixed.
178        # There is an issue on chameleon when a DUT connects to multiple peers
179        # with at least one emulated as an audio device, the other connections
180        # might be dropped for a few seconds then reconnect.
181        # Ensures only one device is connected at a time as a workaround.
182        # The details of the issue is described in b/210379084#comment3
183        # and b/172381798
184        multi_conn_workaround = len(devices) >= 2 and has_audio_device
185        if multi_conn_workaround:
186            for device, expected_pass in zip(devices, expected_passes):
187                # Only disconnect expected_pass devices, since the expected_fail
188                # devices could be disconnected as they don't have connectable
189                # profiles.
190                if expected_pass:
191                    self.test_disconnection_by_adapter(device.address)
192
193        for device, expected_pass in zip(devices, expected_passes):
194            self.check_if_affected_by_policy(device, not expected_pass)
195            verifier = self.get_device_verifier(device, expected_pass)
196
197            if multi_conn_workaround:
198                self.test_connection_by_adapter(device.address)
199
200            # Make sure hid device was created before using it
201            if device.device_type in ['KEYBOARD', 'MOUSE']:
202                self.expect_test(expected_pass, self.test_hid_device_created,
203                                 device.address)
204
205            # Whether the test should pass or fail depends on expected_pass.
206            self.expect_test(expected_pass, verifier, device)
207
208            if multi_conn_workaround:
209                self.test_disconnection_by_adapter(device.address)
210
211        for device in devices:
212            self.post_test_method(device)
213            if device.device_type == 'BLUETOOTH_AUDIO':
214                self.cleanup_bluetooth_audio(device, A2DP)
215
216
217    @test_wrapper('Set Allowlist with Different UUIDs')
218    def ep_check_set_allowlist(self):
219        """The Enterprise Policy set valid and invalid allowlists test."""
220        # Duplicate valid UUIDs
221        self.test_check_set_allowlist('abcd,0xabcd', True)
222
223        # Mix of valid UUID16, UUID32, and UUID128
224        self.test_check_set_allowlist(
225                '0xabcd,abcd1234,'
226                'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', True)
227
228        # Mix of valid UUID16, UUID32, and UUID128 with duplicate UUIUDs
229        self.test_check_set_allowlist(
230                'abcd,0xabcd,abcd1234,0xabcd1234,'
231                'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', True)
232
233        # Single valid classic HID UUID
234        self.test_check_set_allowlist(BluetoothPolicy.UUID_HID, True)
235
236        # Empty allowlist
237        self.test_check_set_allowlist('', True)
238
239        # Invalid UUID should fail.
240        self.test_check_set_allowlist(
241                'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee-ffff', False)
242
243        # Invalid UUID should fail.
244        self.test_check_set_allowlist('aaaaaaaa-bbbb-cccc-dddd', False)
245
246
247    @test_wrapper('Outgoing: HID: Service in Allowlist', devices={'KEYBOARD':1})
248    def ep_outgoing_hid_service_in_allowlist(self):
249        """The test with service in allowlist for outgoing connection."""
250        device = self.devices['KEYBOARD'][0]
251        self.run_test_method(self.ep_outgoing_connection, device,
252                             uuids=BluetoothPolicy.UUID_HID, expected_passes=True)
253
254
255    @test_wrapper('Outgoing: Audio: Service in Allowlist',
256                  devices={'BLUETOOTH_AUDIO':1})
257    def ep_outgoing_audio_services_in_allowlist(self):
258        """The test with service in allowlist for outgoing connection."""
259        device = self.devices['BLUETOOTH_AUDIO'][0]
260        self.run_test_method(self.ep_outgoing_connection, device,
261                             uuids=BluetoothPolicy.ALLOWLIST_AUDIO,
262                             expected_passes=True)
263
264
265    @test_wrapper('Outgoing: HID: Service not in Allowlist',
266                  devices={'KEYBOARD':1})
267    def ep_outgoing_hid_service_not_in_allowlist(self):
268        """The test with service not in allowlist for outgoing connection."""
269        device = self.devices['KEYBOARD'][0]
270        self.run_test_method(self.ep_outgoing_connection, device,
271                             uuids='0xaabb', expected_passes=False)
272
273
274    @test_wrapper('Outgoing: Audio: Service not in Allowlist',
275                  devices={'BLUETOOTH_AUDIO':1})
276    def ep_outgoing_audio_services_not_in_allowlist(self):
277        """The test with service not in allowlist for outgoing connection."""
278        device = self.devices['BLUETOOTH_AUDIO'][0]
279        self.run_test_method(self.ep_outgoing_connection,
280                             device,
281                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID,
282                             expected_passes=False)
283
284
285    @test_wrapper('Outgoing: HID: Empty Allowlist',
286                  devices={'KEYBOARD':1})
287    def ep_outgoing_hid_empty_allowlist(self):
288        """The test with an empty allowlist for outgoing connection."""
289        device = self.devices['KEYBOARD'][0]
290        self.run_test_method(self.ep_outgoing_connection, device,
291                             uuids='', expected_passes=True)
292
293
294    @test_wrapper('Outgoing: Audio: Empty Allowlist',
295                  devices={'BLUETOOTH_AUDIO':1})
296    def ep_outgoing_audio_empty_allowlist(self):
297        """The test with an empty allowlist for outgoing connection."""
298        device = self.devices['BLUETOOTH_AUDIO'][0]
299        self.run_test_method(self.ep_outgoing_connection, device,
300                             uuids='', expected_passes=True)
301
302
303    @test_wrapper('Incoming: HID: Service in Allowlist',
304                  devices={'KEYBOARD':1})
305    def ep_incoming_hid_service_in_allowlist(self):
306        """Service in allowlist for incoming reconnection from device."""
307        device = self.devices['KEYBOARD'][0]
308        self.run_test_method(self.ep_incoming_connection, device,
309                             uuids=BluetoothPolicy.UUID_HID, expected_passes=True)
310
311
312    @test_wrapper('Incoming: Audio: Service in Allowlist',
313                  devices={'BLUETOOTH_AUDIO':1})
314    def ep_incoming_audio_service_in_allowlist(self):
315        """Service in allowlist for incoming reconnection from device."""
316        device = self.devices['BLUETOOTH_AUDIO'][0]
317        self.run_test_method(self.ep_incoming_connection, device,
318                             uuids=BluetoothPolicy.ALLOWLIST_AUDIO,
319                             expected_passes=True)
320
321
322    @test_wrapper('Incoming: HID: Service not in Allowlist',
323                  devices={'KEYBOARD':1})
324    def ep_incoming_hid_service_not_in_allowlist(self):
325        """Service not in allowlist for incoming reconnection from device."""
326        device = self.devices['KEYBOARD'][0]
327        self.run_test_method(self.ep_incoming_connection, device,
328                             uuids='0xaabb', expected_passes=False)
329
330
331    @test_wrapper('Incoming: Audio: Service not in Allowlist',
332                  devices={'BLUETOOTH_AUDIO':1})
333    def ep_incoming_audio_service_not_in_allowlist(self):
334        """Service not in allowlist for incoming reconnection from device."""
335        device = self.devices['BLUETOOTH_AUDIO'][0]
336        self.run_test_method(self.ep_incoming_connection,
337                             device,
338                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID,
339                             expected_passes=False)
340
341
342    @test_wrapper('Incoming: HID: Service empty Allowlist',
343                  devices={'KEYBOARD':1})
344    def ep_incoming_hid_service_empty_allowlist(self):
345        """The test with an empty allowlist for incoming connection."""
346        device = self.devices['KEYBOARD'][0]
347        self.run_test_method(self.ep_incoming_connection, device,
348                             uuids='',
349                             expected_passes=True)
350
351
352    @test_wrapper('Incoming: Audio: Service empty Allowlist',
353                  devices={'BLUETOOTH_AUDIO':1})
354    def ep_incoming_audio_service_empty_allowlist(self):
355        """The test with an empty allowlist for incoming connection."""
356        device = self.devices['BLUETOOTH_AUDIO'][0]
357        self.run_test_method(self.ep_incoming_connection, device,
358                             uuids='',
359                             expected_passes=True)
360
361
362    @test_wrapper('Outgoing: BLE Keyboard: Services in Allowlist',
363                  devices={'BLE_KEYBOARD':1})
364    def ep_outgoing_ble_hid_services_in_allowlist(self):
365        """The test for BLE gatt services in allowlist."""
366        device = self.devices['BLE_KEYBOARD'][0]
367        self.run_test_method(self.ep_outgoing_connection, device,
368                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID,
369                             expected_passes=True)
370
371
372    @test_wrapper('Outgoing: BLE Keyboard: Services not in Allowlist',
373                  devices={'BLE_KEYBOARD':1})
374    def ep_outgoing_ble_hid_services_not_in_allowlist(self):
375        """The test for BLE gatt services not in allowlist."""
376        device = self.devices['BLE_KEYBOARD'][0]
377        self.run_test_method(self.ep_outgoing_connection,
378                             device,
379                             uuids=BluetoothPolicy.ALLOWLIST_AUDIO,
380                             expected_passes=False)
381
382
383    @test_wrapper('Outgoing: BLE Keyboard: Empty Allowlist',
384                  devices={'BLE_KEYBOARD':1})
385    def ep_outgoing_ble_hid_empty_allowlist(self):
386        """The test for BLE gatt services and an empty allowlist."""
387        device = self.devices['BLE_KEYBOARD'][0]
388        self.run_test_method(self.ep_outgoing_connection, device,
389                             uuids='', expected_passes=True)
390
391
392    @test_wrapper('Reconnection: BLE Keyboard: Service in Allowlist',
393                  devices={'BLE_KEYBOARD':1})
394    def ep_reconnection_ble_hid_service_in_allowlist(self):
395        """Service in allowlist for auto reconnection from device."""
396        device = self.devices['BLE_KEYBOARD'][0]
397        self.run_test_method(self.ep_auto_reconnection, device,
398                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID,
399                             expected_passes=True)
400
401
402    @test_wrapper('Reconnection: BLE Keyboard: Service not in Allowlist',
403                  devices={'BLE_KEYBOARD':1})
404    def ep_reconnection_ble_hid_service_not_in_allowlist(self):
405        """Service in allowlist for auto reconnection from device."""
406        device = self.devices['BLE_KEYBOARD'][0]
407        self.run_test_method(self.ep_auto_reconnection,
408                             device,
409                             uuids=BluetoothPolicy.ALLOWLIST_AUDIO,
410                             expected_passes=False)
411
412
413    @test_wrapper('Combo: Set Allowlist and Disconnect', devices={'KEYBOARD':1})
414    def ep_combo_set_allowlist_and_disconnect(self):
415        """Set a new allowlist and current connection should be terminated."""
416        device = self.devices['KEYBOARD'][0]
417        self.run_test_method(self.ep_outgoing_connection, device,
418                             uuids=BluetoothPolicy.UUID_HID, expected_passes=True)
419
420        # Setting a non-HID UUID should disconnect the device.
421        self.test_check_set_allowlist('abcd', True)
422        time.sleep(self.DISCONNECT_SLEEP_SECS)
423        self.test_device_is_not_connected(device.address)
424
425
426    @test_wrapper('Combo: Successive Allowlist', devices={'KEYBOARD':1})
427    def ep_combo_successive_allowlists(self):
428        """A new allowlist overwrites previoius one and allows connection."""
429        device = self.devices['KEYBOARD'][0]
430
431        # Setting a non-HID UUID initially.
432        self.test_check_set_allowlist('abcd', True)
433
434        # A subsequent HID UUID should supersede the previous setting.
435        self.run_test_method(self.ep_outgoing_connection, device,
436                             uuids=BluetoothPolicy.UUID_HID, expected_passes=True)
437
438
439    @test_wrapper('Combo: HID Allowlist Persists Adapter Reset',
440                  devices={'KEYBOARD':1})
441    def ep_combo_hid_persists_adapter_reset(self):
442        """The Allowlist with HID UUID should persist adapter reset."""
443        device = self.devices['KEYBOARD'][0]
444        self.test_check_set_allowlist(BluetoothPolicy.UUID_HID, True)
445        self.test_reset_on_adapter()
446        self.run_test_method(self.ep_outgoing_connection, device,
447                             uuids=None, expected_passes=True)
448
449
450    @test_wrapper('Combo: Non-HID Allowlist Persists Adapter Reset',
451                  devices={'KEYBOARD':1})
452    def ep_combo_non_hid_persists_adapter_reset(self):
453        """The Allowlist with non-HID UUID should persist adapter reset."""
454        device = self.devices['KEYBOARD'][0]
455        self.test_check_set_allowlist('abcd', True)
456        self.test_reset_on_adapter()
457        self.run_test_method(self.ep_outgoing_connection, device,
458                             uuids=None, expected_passes=False)
459
460
461    @test_wrapper('Combo: HID Allowlist Persists bluetoothd restart',
462                  devices={'KEYBOARD':1})
463    def ep_combo_hid_persists_bluetoothd_restart(self):
464        """The Allowlist with HID UUID should persist bluetoothd restart."""
465        device = self.devices['KEYBOARD'][0]
466        self.test_check_set_allowlist(BluetoothPolicy.UUID_HID, True)
467        self.test_stop_bluetoothd()
468        self.test_start_bluetoothd()
469        # Powering on adapter could take a few milliseconds, make sure the power
470        # is on before proceeding.
471        self.test_adapter_work_state()
472        self.run_test_method(self.ep_outgoing_connection, device,
473                             uuids=None, expected_passes=True)
474
475
476    @test_wrapper('Combo: Non-HID Allowlist Persists bluetoothd restart',
477                  devices={'KEYBOARD':1})
478    def ep_combo_non_hid_persists_bluetoothd_restart(self):
479        """The Allowlist with non-HID UUID should persist bluetoothd restart."""
480        device = self.devices['KEYBOARD'][0]
481        self.test_check_set_allowlist('abcd', True)
482        self.test_stop_bluetoothd()
483        self.test_start_bluetoothd()
484        # Powering on adapter could take a few milliseconds, make sure the power
485        # is on before proceeding.
486        self.test_adapter_work_state()
487        self.run_test_method(self.ep_outgoing_connection, device,
488                             uuids=None, expected_passes=False)
489
490
491    @test_wrapper('Combo: HID Allowlist Persists reboot',
492                  devices={'KEYBOARD':1})
493    def ep_combo_hid_persists_reboot(self):
494        """The Allowlist with HID UUID should persist reboot."""
495        device = self.devices['KEYBOARD'][0]
496        self.test_check_set_allowlist(BluetoothPolicy.UUID_HID, True)
497        self.reboot()
498        # Make sure adapter power is on before proceeding.
499        self.test_adapter_work_state()
500        self.run_test_method(self.ep_outgoing_connection, device,
501                             uuids=None, expected_passes=True)
502
503
504    @test_wrapper('Combo: Non-HID Allowlist Persists reboot',
505                  devices={'KEYBOARD':1})
506    def ep_combo_non_hid_persists_reboot(self):
507        """The Allowlist with non-HID UUID should persist reboot."""
508        device = self.devices['KEYBOARD'][0]
509        self.test_check_set_allowlist('aaaa', True)
510        self.reboot()
511        # Make sure adapter power is on before proceeding.
512        self.test_adapter_work_state()
513        self.run_test_method(self.ep_outgoing_connection, device,
514                             uuids=None, expected_passes=False)
515
516
517    @test_wrapper('MD: BLE HID and Audio: Services in Allowlist',
518                  devices={'BLE_MOUSE':1, 'BLUETOOTH_AUDIO':1})
519    def ep_md_ble_hid_and_audio_in_allowlist(self):
520        """The multi-device test for BLE HID and audio services in allowlist."""
521        hid_device = self.devices['BLE_MOUSE'][0]
522        audio_device = self.devices['BLUETOOTH_AUDIO'][0]
523
524        self.run_test_method(self.ep_outgoing_connection,
525                             [hid_device, audio_device],
526                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID_AUDIO,
527                             expected_passes=[True, True])
528
529
530    @test_wrapper('MD: BLE HID and Audio: Only Audio in Allowlist',
531                  devices={'BLE_MOUSE':1, 'BLUETOOTH_AUDIO':1})
532    def ep_md_audio_in_allowlist(self):
533        """The multi-device test for audio services in allowlist."""
534        hid_device = self.devices['BLE_MOUSE'][0]
535        audio_device = self.devices['BLUETOOTH_AUDIO'][0]
536
537        self.run_test_method(self.ep_outgoing_connection,
538                             [hid_device, audio_device],
539                             uuids=BluetoothPolicy.ALLOWLIST_AUDIO,
540                             expected_passes=[False, True])
541
542
543    @test_wrapper('MD: BLE HID and Audio: Only BLE HID in Allowlist',
544                  devices={'BLE_KEYBOARD':1, 'BLUETOOTH_AUDIO':1})
545    def ep_md_ble_hid_in_allowlist(self):
546        """The multi-device test for audio services in allowlist."""
547        hid_device = self.devices['BLE_KEYBOARD'][0]
548        audio_device = self.devices['BLUETOOTH_AUDIO'][0]
549
550        self.run_test_method(self.ep_outgoing_connection,
551                             [hid_device, audio_device],
552                             uuids=BluetoothPolicy.ALLOWLIST_BLE_HID,
553                             expected_passes=[True, False])
554
555
556    @test_wrapper('MD: Classic and BLE HID: Services in Allowlist',
557                  devices={'BLE_KEYBOARD':1, 'MOUSE':1})
558    def ep_md_hid_and_ble_hid_in_allowlist(self):
559        """The multi-device test for Classic and BLE HID in the allowlist."""
560        keyboard_device = self.devices['BLE_KEYBOARD'][0]
561        mouse_device = self.devices['MOUSE'][0]
562
563        self.run_test_method(self.ep_outgoing_connection,
564                             [keyboard_device, mouse_device],
565                             uuids=BluetoothPolicy.ALLOWLIST_CLASSIC_BLE_HID,
566                             expected_passes=[True, True])
567
568
569    @test_wrapper('MD: BLE HID and Audio: Empty Allowlist',
570                  devices={'BLE_KEYBOARD':1, 'BLUETOOTH_AUDIO':1})
571    def ep_md_ble_hid_and_audio_empty_allowlist(self):
572        """The multi-device test for BLE HID and Audio with empty allowlist."""
573        hid_device = self.devices['BLE_KEYBOARD'][0]
574        audio_device = self.devices['BLUETOOTH_AUDIO'][0]
575
576        self.run_test_method(self.ep_outgoing_connection,
577                             [hid_device, audio_device],
578                             uuids='',
579                             expected_passes=[True, True])
580
581
582    @batch_wrapper('EP Health')
583    def ep_health_batch_run(self, num_iterations=1, test_name=None):
584        """Run the EP health test batch or a specific given test.
585
586        @param num_iterations: how many iterations to run
587        @param test_name: specific test to run otherwise None to run the
588                whole batch
589        """
590
591        self.ep_check_set_allowlist()
592
593        self.ep_outgoing_hid_service_in_allowlist()
594        self.ep_outgoing_hid_service_not_in_allowlist()
595        self.ep_outgoing_hid_empty_allowlist()
596
597        self.ep_outgoing_ble_hid_services_in_allowlist()
598        self.ep_outgoing_ble_hid_services_not_in_allowlist()
599        self.ep_outgoing_ble_hid_empty_allowlist()
600
601        self.ep_incoming_hid_service_in_allowlist()
602        self.ep_incoming_hid_service_not_in_allowlist()
603        self.ep_incoming_hid_service_empty_allowlist()
604
605        self.ep_outgoing_audio_services_in_allowlist()
606        self.ep_outgoing_audio_services_not_in_allowlist()
607        self.ep_outgoing_audio_empty_allowlist()
608
609        self.ep_incoming_audio_service_in_allowlist()
610        self.ep_incoming_audio_service_not_in_allowlist()
611        self.ep_incoming_audio_service_empty_allowlist()
612
613        self.ep_reconnection_ble_hid_service_in_allowlist()
614        self.ep_reconnection_ble_hid_service_not_in_allowlist()
615
616        self.ep_combo_set_allowlist_and_disconnect()
617        self.ep_combo_successive_allowlists()
618        self.ep_combo_hid_persists_adapter_reset()
619        self.ep_combo_non_hid_persists_adapter_reset()
620        self.ep_combo_hid_persists_bluetoothd_restart()
621        self.ep_combo_non_hid_persists_bluetoothd_restart()
622        self.ep_combo_hid_persists_reboot()
623        self.ep_combo_non_hid_persists_reboot()
624
625        self.ep_md_ble_hid_and_audio_in_allowlist()
626        self.ep_md_audio_in_allowlist()
627        self.ep_md_ble_hid_in_allowlist()
628        self.ep_md_hid_and_ble_hid_in_allowlist()
629        self.ep_md_ble_hid_and_audio_empty_allowlist()
630
631    def run_once(self,
632                 host,
633                 num_iterations=1,
634                 peer_required=True,
635                 args_dict=None,
636                 test_name=None,
637                 flag='Quick Health'):
638        """Run the batch of Bluetooth enterprise policy health tests
639
640        @param host: the DUT, usually a chromebook
641        @param num_iterations: the number of rounds to execute the test
642        @param test_name: the test to run, or None for all tests
643        """
644
645        # Initialize and run the test batch or the requested specific test
646        self.quick_test_init(host,
647                             use_btpeer=peer_required,
648                             flag=flag,
649                             args_dict=args_dict)
650        self.ep_health_batch_run(num_iterations, test_name)
651        self.quick_test_cleanup()
652