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"""A Batch of Bluetooth LE LLT health tests""" 6 7from autotest_lib.server.cros.bluetooth import advertisements_data 8 9DEFAULT_MIN_ADV_INTERVAL = 200 10DEFAULT_MAX_ADV_INTERVAL = 500 11 12from autotest_lib.server.cros.bluetooth.\ 13 bluetooth_adapter_controller_role_tests \ 14 import bluetooth_AdapterControllerRoleTests 15from autotest_lib.server.cros.bluetooth.bluetooth_adapter_quick_tests \ 16 import BluetoothAdapterQuickTests 17from autotest_lib.server.cros.bluetooth.bluetooth_adapter_hidreports_tests \ 18 import BluetoothAdapterHIDReportTests 19from autotest_lib.server.cros.bluetooth.bluetooth_adapter_better_together \ 20 import BluetoothAdapterBetterTogether 21 22 23class bluetooth_AdapterLLTHealth(BluetoothAdapterHIDReportTests, 24 bluetooth_AdapterControllerRoleTests, 25 BluetoothAdapterBetterTogether): 26 """A Batch of Bluetooth LE LLT health tests. This test is written 27 as a batch of tests in order to reduce test time, since auto-test 28 ramp up time is costly. The batch is using BluetoothAdapterQuickTests 29 wrapper methods to start and end a test and a batch of tests. 30 31 This class can be called to run the entire test batch or to run a 32 specific test only 33 """ 34 35 test_wrapper = BluetoothAdapterQuickTests.quick_test_test_decorator 36 batch_wrapper = BluetoothAdapterQuickTests.quick_test_batch_decorator 37 38 39 def discover_and_pair(self, device): 40 """Discovers and pairs given device. Automatically connects too. 41 42 @param device: meta object for bt peer device 43 """ 44 self.test_discover_device(device.address) 45 self.test_pairing(device.address, device.pin, trusted=True) 46 self.test_connection_by_adapter(device.address) 47 48 49 def start_connectable_advertisement(self): 50 """ Initiate connectable advertising from DUT """ 51 # Register and start advertising instance 52 # We ignore failure because the test isn't able to verify 53 # the min/max advertising intervals, but this is ok. 54 self.test_reset_advertising() 55 self.test_set_advertising_intervals(DEFAULT_MIN_ADV_INTERVAL, 56 DEFAULT_MAX_ADV_INTERVAL) 57 self.test_register_advertisement(advertisements_data.ADVERTISEMENTS[0], 58 1) 59 60 61 def pair_and_test_central(self, peripheral): 62 """Connects DUT as central to a peripheral device. 63 64 @param peripheral: meta object for bt peer device 65 """ 66 # Pair the central device first - 67 # necessary for later connection to peripheral 68 self.pair_adapter_to_device(peripheral) 69 self.test_device_set_discoverable(peripheral, False) 70 71 self.start_connectable_advertisement() 72 # Discover DUT from peer 73 self.test_discover_by_device(peripheral) 74 # Connect to DUT from peer, putting DUT in peripheral role 75 self.test_connection_by_device(peripheral) 76 self.test_reset_advertising() 77 78 79 @test_wrapper('LLT: 1 Central 1 Peripheral. Order of connection CP', 80 devices={ 81 'BLE_KEYBOARD': 1, 82 'BLE_MOUSE': 1 83 }) 84 def llt_1c1p_connect_cp(self): 85 """Tests llt with two peer devices. 86 Connects DUT as central to first device 87 and as peripheral to second device, 88 sends small amount of data over the connection 89 """ 90 91 self.verify_controller_capability( 92 required_roles=['central-peripheral']) 93 94 central = self.devices['BLE_MOUSE'][0] 95 peripheral = self.devices['BLE_KEYBOARD'][0] 96 # Establish connection from DUT as LE Central 97 self.discover_and_pair(central) 98 99 self.test_hid_device_created(central.address) 100 # Verify data transfer over the DUT LE central Connection 101 self.test_mouse_left_click(central) 102 103 # Now establish second connection with DUT as LE Peripheral 104 self.bluetooth_le_facade = self.bluetooth_facade 105 self.pair_and_test_central(peripheral) 106 self.run_keyboard_tests(peripheral) 107 108 # Verify data over LE Central connection again 109 self.test_mouse_left_click(central) 110 111 # Disconnect connections from DUT 112 self.test_disconnection_by_adapter(central.address) 113 self.test_disconnection_by_device(peripheral) 114 115 116 @test_wrapper('LLT: 1 Central 1 Peripheral. Order of connection PC', 117 devices={ 118 'BLE_KEYBOARD': 1, 119 'BLE_MOUSE': 1 120 }) 121 def llt_1c1p_connect_pc(self): 122 """Tests llt with two peer devices, 123 Connects DUT as peripheral to first device 124 and as central to second device, 125 sends small amount of data over the connection 126 """ 127 128 self.verify_controller_capability( 129 required_roles=['central-peripheral']) 130 131 central = self.devices['BLE_MOUSE'][0] 132 peripheral = self.devices['BLE_KEYBOARD'][0] 133 # Establish the first connection with DUT as LE Peripheral 134 self.bluetooth_le_facade = self.bluetooth_facade 135 136 # Connect to DUT from peer, putting DUT in peripheral role 137 # Try transferring data over connection 138 self.pair_and_test_central(peripheral) 139 self.run_keyboard_tests(peripheral) 140 141 # Establish second connection from DUT as LE Central 142 self.discover_and_pair(central) 143 self.test_hid_device_created(central.address) 144 # Verify data transfer over the DUT LE Central Connection 145 self.test_mouse_left_click(central) 146 # Verfiy LE peripheral connection again 147 self.run_keyboard_tests(peripheral) 148 149 # Disconnect connections from DUT 150 self.test_disconnection_by_adapter(central.address) 151 self.test_disconnection_by_device(peripheral) 152 153 154 @test_wrapper('LLT: 1 Central 1 Peripheral while DUT advertising.' 155 'Order of connection PC', 156 devices={ 157 'BLE_KEYBOARD': 1, 158 'BLE_MOUSE': 1 159 }) 160 def llt_1c1p_connect_pc_while_adv(self): 161 """Tests llt with two peer devices, while DUT advertising. 162 Connects DUT while advertising 163 as peripheral to first device 164 and as central to second device, 165 sends small amount of data over the connection 166 """ 167 168 self.verify_controller_capability( 169 required_roles=['central-peripheral']) 170 171 central = self.devices['BLE_MOUSE'][0] 172 peripheral = self.devices['BLE_KEYBOARD'][0] 173 # Establish the first connection with DUT as LE Peripheral 174 self.bluetooth_le_facade = self.bluetooth_facade 175 176 # Connect to DUT from peer, putting DUT in peripheral role 177 # Try transferring data over connection 178 self.pair_and_test_central(peripheral) 179 self.run_keyboard_tests(peripheral) 180 181 # Establish second connection from DUT as LE Central 182 # while advertising in progress 183 self.start_connectable_advertisement() 184 self.discover_and_pair(central) 185 self.test_hid_device_created(central.address) 186 187 # Verify data transfer over the DUT LE Central Connection 188 self.test_mouse_left_click(central) 189 # Verfiy LE Peripheral connection again 190 self.run_keyboard_tests(peripheral) 191 192 # Disconnect connections from DUT 193 self.test_disconnection_by_adapter(central.address) 194 self.test_disconnection_by_device(peripheral) 195 self.test_reset_advertising() 196 197 198 @test_wrapper('LLT: 2 Central 1 Peripheral. Order of connection CCP', 199 devices={ 200 'BLE_KEYBOARD': 1, 201 'BLE_MOUSE': 1, 202 'BLE_PHONE': 1 203 }) 204 def llt_2c1p_connect_ccp(self): 205 """Tests llt with three peer devices. 206 Connects DUT as central to first and second devices, 207 connects DUT as peripheral to third device, 208 sends small amount of data over the connection 209 """ 210 211 self.verify_controller_capability( 212 required_roles=['central-peripheral']) 213 214 central_1 = self.devices['BLE_PHONE'][0] 215 central_2 = self.devices['BLE_MOUSE'][0] 216 peripheral = self.devices['BLE_KEYBOARD'][0] 217 # Establish two connections from DUT as LE Central 218 self.discover_and_pair(central_2) 219 self.test_hid_device_created(central_2.address) 220 221 # Verify data transfer over two DUT LE Central Connections 222 self.test_mouse_left_click(central_2) 223 224 central_1.RemoveDevice(self.bluetooth_facade.address) 225 self.test_smart_unlock_llt(address=central_1.address) 226 227 # Establish third connection with DUT as LE Peripheral 228 self.bluetooth_le_facade = self.bluetooth_facade 229 self.pair_and_test_central(peripheral) 230 self.run_keyboard_tests(peripheral) 231 232 # Verify data transfer over two DUT LE Central Connections 233 self.test_mouse_left_click(central_2) 234 235 # Disconnect connections from DUT 236 self.test_disconnection_by_adapter(central_1.address) 237 self.test_disconnection_by_adapter(central_2.address) 238 self.test_disconnection_by_device(peripheral) 239 240 241 @test_wrapper('LLT: 2 Central 1 Peripheral. Order of connection PCC', 242 devices={ 243 'BLE_KEYBOARD': 1, 244 'BLE_MOUSE': 1, 245 'BLE_PHONE': 1 246 }) 247 def llt_2c1p_connect_pcc(self): 248 """Tests llt with three peer devices. 249 Connects DUT as peripheral to first device 250 and as central to second and third device, 251 sends small amount of data over the connection 252 """ 253 254 self.verify_controller_capability( 255 required_roles=['central-peripheral']) 256 257 central_1 = self.devices['BLE_PHONE'][0] 258 central_2 = self.devices['BLE_MOUSE'][0] 259 peripheral = self.devices['BLE_KEYBOARD'][0] 260 261 # Establish the first connection with DUT as LE Peripheral 262 self.bluetooth_le_facade = self.bluetooth_facade 263 264 # Connect to DUT from peer, putting DUT in peripheral role 265 # Try transferring data over connection 266 self.pair_and_test_central(peripheral) 267 self.run_keyboard_tests(peripheral) 268 269 # Establish connections from DUT as LE Central 270 self.discover_and_pair(central_2) 271 self.test_hid_device_created(central_2.address) 272 273 # Verify data transfer over two DUT LE Central Connections 274 self.test_mouse_left_click(central_2) 275 276 # Establish third connection 277 central_1.RemoveDevice(self.bluetooth_facade.address) 278 self.test_smart_unlock_llt(address=central_1.address) 279 280 # Verify once again data transfer over DUT LE Peripheral connection 281 self.run_keyboard_tests(peripheral) 282 283 # Disconnect connections from DUT 284 self.test_disconnection_by_adapter(central_1.address) 285 self.test_disconnection_by_adapter(central_2.address) 286 self.test_disconnection_by_device(peripheral) 287 288 289 @test_wrapper('LLT: 2 Central 1 Peripheral. Order of connection CPC', 290 devices={ 291 'BLE_KEYBOARD': 1, 292 'BLE_MOUSE': 1, 293 'BLE_PHONE': 1 294 }) 295 def llt_2c1p_connect_cpc(self): 296 """Tests llt with three peer devices. 297 Connects DUT as central to first device, 298 as peripheral to second and as central to third device, 299 sends small amount of data over the connection 300 """ 301 302 self.verify_controller_capability( 303 required_roles=['central-peripheral']) 304 305 central_1 = self.devices['BLE_PHONE'][0] 306 central_2 = self.devices['BLE_MOUSE'][0] 307 peripheral = self.devices['BLE_KEYBOARD'][0] 308 309 # Establish the first connection with DUT as LE Central 310 central_1.RemoveDevice(self.bluetooth_facade.address) 311 self.test_smart_unlock_llt(address=central_1.address) 312 313 # Establish the second connection with DUT as LE Peripheral 314 self.bluetooth_le_facade = self.bluetooth_facade 315 316 # Connect to DUT from peer, putting DUT in peripheral role 317 # Try transferring data over connection 318 self.pair_and_test_central(peripheral) 319 self.run_keyboard_tests(peripheral) 320 321 # Establish third connections from DUT as LE Central 322 self.discover_and_pair(central_2) 323 self.test_hid_device_created(central_2.address) 324 325 # Verify data transfer over second LE Central Connections 326 self.test_mouse_left_click(central_2) 327 # Verify once again data transfer over DUT LE Peripheral connection 328 self.run_keyboard_tests(peripheral) 329 330 # Disconnect connections from DUT 331 self.test_disconnection_by_adapter(central_1.address) 332 self.test_disconnection_by_adapter(central_2.address) 333 self.test_disconnection_by_device(peripheral) 334 335 336 @test_wrapper('LLT: 2 Central 1 Peripheral while DUT advertising.' 337 'Order of connection PCC', 338 devices={ 339 'BLE_KEYBOARD': 1, 340 'BLE_MOUSE': 1, 341 'BLE_PHONE': 1 342 }) 343 def llt_2c1p_connect_pcc_while_adv(self): 344 """Tests llt with three peer devices. 345 Connects DUT as peripheral to first device 346 and as central to second and third device while advertising, 347 sends small amount of data over the connection 348 """ 349 350 self.verify_controller_capability( 351 required_roles=['central-peripheral']) 352 353 central_1 = self.devices['BLE_MOUSE'][0] 354 central_2 = self.devices['BLE_PHONE'][0] 355 peripheral = self.devices['BLE_KEYBOARD'][0] 356 357 # Establish the first connection with DUT as LE Peripheral 358 self.bluetooth_le_facade = self.bluetooth_facade 359 360 # Connect to DUT from peer, putting DUT in peripheral role 361 # Try transferring data over connection 362 self.pair_and_test_central(peripheral) 363 self.run_keyboard_tests(peripheral) 364 365 # Connect as first LE Central while DUT is advertising 366 self.start_connectable_advertisement() 367 self.discover_and_pair(central_1) 368 self.test_hid_device_created(central_1.address) 369 370 # Establish second LE connection from DUT as LE Central 371 central_2.RemoveDevice(self.bluetooth_facade.address) 372 self.test_smart_unlock_llt(address=central_2.address) 373 374 # Verify data transfer over first LE Central Connections 375 self.test_mouse_left_click(central_1) 376 # Verify once again data transfer over DUT LE Peripheral connection 377 self.run_keyboard_tests(peripheral) 378 379 # Disconnect connections from DUT 380 self.test_disconnection_by_adapter(central_1.address) 381 self.test_disconnection_by_adapter(central_2.address) 382 self.test_disconnection_by_device(peripheral) 383 self.test_reset_advertising() 384 385 386 @test_wrapper('LLT: 2 Central 1 Peripheral while DUT Advertising.' 387 'Order of connection CPC', 388 devices={ 389 'BLE_KEYBOARD': 1, 390 'BLE_MOUSE': 1, 391 'BLE_PHONE': 1 392 }) 393 def llt_2c1p_connect_cpc_while_adv(self): 394 """Tests llt with three peer devices. 395 Connects DUT while advertising as central to first device, 396 as peripheral to second and as central to third device, 397 sends small amount of data over the connection 398 """ 399 400 self.verify_controller_capability( 401 required_roles=['central-peripheral']) 402 403 central_1 = self.devices['BLE_PHONE'][0] 404 central_2 = self.devices['BLE_MOUSE'][0] 405 peripheral = self.devices['BLE_KEYBOARD'][0] 406 407 self.bluetooth_le_facade = self.bluetooth_facade 408 # Establish the first connection with DUT as LE Central 409 # while advertising in progress 410 self.start_connectable_advertisement() 411 central_1.RemoveDevice(self.bluetooth_facade.address) 412 self.test_smart_unlock_llt(address=central_1.address) 413 414 # Establish the second connection with DUT as LE Peripheral 415 # Try transferring data over connection 416 self.pair_and_test_central(peripheral) 417 self.run_keyboard_tests(peripheral) 418 419 # Establish third connections from DUT as LE Central 420 self.discover_and_pair(central_2) 421 self.test_hid_device_created(central_2.address) 422 423 # Verify data transfer over second LE Central Connections 424 self.test_mouse_left_click(central_2) 425 # Verify once again data transfer over DUT LE Peripheral connection 426 self.run_keyboard_tests(peripheral) 427 428 # Disconnect connections from DUT 429 self.test_disconnection_by_adapter(central_1.address) 430 self.test_disconnection_by_adapter(central_2.address) 431 self.test_disconnection_by_device(peripheral) 432 self.test_reset_advertising() 433 434 435 @test_wrapper('LLT: 1 Central 2 Peripheral. Order of connection CPP', 436 devices={ 437 'BLE_KEYBOARD': 1, 438 'BLE_MOUSE': 1, 439 'BLE_PHONE': 1 440 }) 441 def llt_2p1c_connect_cpp(self): 442 """Tests llt with three peer devices. 443 Connects DUT as central to first device 444 and as peripheral to second and third devices, 445 sends small amount of data over the connection 446 """ 447 448 self.verify_controller_capability( 449 required_roles=['central-peripheral']) 450 451 peripheral_1 = self.devices['BLE_KEYBOARD'][0] 452 central_peer = self.devices['BLE_PHONE'][0] 453 peripheral_2 = self.devices['BLE_MOUSE'][0] 454 455 # Establish connection from DUT as LE Central 456 central_peer.RemoveDevice(self.bluetooth_facade.address) 457 self.test_smart_unlock_llt(address=central_peer.address) 458 459 self.bluetooth_le_facade = self.bluetooth_facade 460 461 # Connect to DUT from peer, putting DUT in peripheral role 462 # Try transferring data over connection 463 self.pair_and_test_central(peripheral_1) 464 self.run_keyboard_tests(peripheral_1) 465 466 # Establish and Verify second LE peripheral connection 467 self.pair_and_test_central(peripheral_2) 468 469 # Try transferring data over connection 470 self.test_mouse_left_click(peripheral_2) 471 # Verify traffic from LE Peripheral connections again 472 self.run_keyboard_tests(peripheral_1) 473 self.test_mouse_left_click(peripheral_2) 474 475 # Disconnect connections from DUT 476 self.test_disconnection_by_adapter(central_peer.address) 477 self.test_disconnection_by_device(peripheral_1) 478 self.test_disconnection_by_device(peripheral_2) 479 480 481 @test_wrapper('LLT: 1 Central 2 Peripheral. Order of connection PCP', 482 devices={ 483 'BLE_KEYBOARD': 1, 484 'BLE_MOUSE': 1, 485 'BLE_PHONE': 1 486 }) 487 def llt_2p1c_connect_pcp(self): 488 """Tests llt with three peer devices. 489 Connects DUT as peripheral to first device, 490 as central to second and as peripheral to third devices, 491 sends small amount of data over the connection 492 """ 493 494 self.verify_controller_capability( 495 required_roles=['central-peripheral']) 496 497 peripheral_1 = self.devices['BLE_KEYBOARD'][0] 498 central_peer = self.devices['BLE_PHONE'][0] 499 peripheral_2 = self.devices['BLE_MOUSE'][0] 500 501 self.bluetooth_le_facade = self.bluetooth_facade 502 503 # Connect to DUT from peer, putting DUT in peripheral role 504 # Try transferring data over connection 505 self.pair_and_test_central(peripheral_1) 506 self.run_keyboard_tests(peripheral_1) 507 508 # Establish connection from DUT as LE Central 509 central_peer.RemoveDevice(self.bluetooth_facade.address) 510 self.test_smart_unlock_llt(address=central_peer.address) 511 512 # Establish and Verify second LE peripheral connection 513 self.pair_and_test_central(peripheral_2) 514 515 # Try transferring data over connection 516 self.test_mouse_left_click(peripheral_2) 517 # Verify traffic from LE Peripheral connections again 518 self.run_keyboard_tests(peripheral_1) 519 self.test_mouse_left_click(peripheral_2) 520 521 # Disconnect connections from DUT 522 self.test_disconnection_by_adapter(central_peer.address) 523 self.test_disconnection_by_device(peripheral_1) 524 self.test_disconnection_by_device(peripheral_2) 525 526 527 @test_wrapper('LLT: 1 Central 2 Peripheral. Order of connection PPC', 528 devices={ 529 'BLE_KEYBOARD': 1, 530 'BLE_MOUSE': 1, 531 'BLE_PHONE': 1 532 }) 533 def llt_2p1c_connect_ppc(self): 534 """Tests llt with three peer devices. 535 Connects DUT as peripheral to first and second devices 536 and as central to third device, 537 sends small amount of data over the connection 538 """ 539 540 self.verify_controller_capability( 541 required_roles=['central-peripheral']) 542 543 peripheral_1 = self.devices['BLE_KEYBOARD'][0] 544 central_peer = self.devices['BLE_PHONE'][0] 545 peripheral_2 = self.devices['BLE_MOUSE'][0] 546 547 self.bluetooth_le_facade = self.bluetooth_facade 548 549 # Connect to DUT from peer, putting DUT in peripheral role 550 # Try transferring data over connection 551 self.pair_and_test_central(peripheral_1) 552 self.run_keyboard_tests(peripheral_1) 553 554 # Establish and Verify second LE peripheral connection 555 self.pair_and_test_central(peripheral_2) 556 557 # Try transferring data over connection 558 self.test_mouse_left_click(peripheral_2) 559 560 # Verify data transfer over two DUT LE Central Connections 561 central_peer.RemoveDevice(self.bluetooth_facade.address) 562 self.test_smart_unlock_llt(address=central_peer.address) 563 # Verify traffic from LE Peripheral connections again 564 self.run_keyboard_tests(peripheral_1) 565 self.test_mouse_left_click(peripheral_2) 566 567 # Disconnect connections from DUT 568 self.test_disconnection_by_adapter(central_peer.address) 569 self.test_disconnection_by_device(peripheral_1) 570 self.test_disconnection_by_device(peripheral_2) 571 572 573 @batch_wrapper('LLT Health') 574 def llt_health_batch_run(self, num_iterations=1, test_name=None): 575 """Run the LE LLT health test batch or a specific given test. 576 The wrapper of this method is implemented in batch_decorator. 577 Using the decorator a test batch method can implement the only its 578 core tests invocations and let the decorator handle the wrapper, 579 which is taking care for whether to run a specific test or the 580 batch as a whole, and running the batch in iterations 581 582 @param num_iterations: how many iterations to run 583 @param test_name: specific test to run otherwise None to run the 584 whole batch 585 """ 586 self.llt_1c1p_connect_cp() 587 self.llt_1c1p_connect_pc() 588 self.llt_1c1p_connect_pc_while_adv() 589 self.llt_2c1p_connect_ccp() 590 self.llt_2c1p_connect_pcc() 591 self.llt_2c1p_connect_cpc() 592 self.llt_2c1p_connect_pcc_while_adv() 593 self.llt_2c1p_connect_cpc_while_adv() 594 self.llt_2p1c_connect_cpp() 595 self.llt_2p1c_connect_pcp() 596 self.llt_2p1c_connect_ppc() 597 598 599 def run_once(self, 600 host, 601 num_iterations=1, 602 args_dict=None, 603 test_name=None, 604 flag='Quick Health'): 605 """Run the batch of Bluetooth LE LLT health tests 606 607 @param host: the DUT, usually a chromebook 608 @param num_iterations: the number of rounds to execute the test 609 @test_name: the test to run, or None for all tests 610 """ 611 612 # Initialize and run the test batch or the requested specific test 613 self.quick_test_init(host, 614 use_btpeer=True, 615 flag=flag, 616 args_dict=args_dict) 617 self.llt_health_batch_run(num_iterations, test_name) 618 self.quick_test_cleanup() 619