• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#/usr/bin/env python3.4
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17Basic LE Stress tests.
18"""
19
20import concurrent
21import pprint
22import time
23
24from queue import Empty
25from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
26from acts.test_utils.bt.bt_test_utils import BtTestUtilsError
27from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
28from acts.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
29from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects
30from acts.test_utils.bt.bt_test_utils import get_advanced_droid_list
31from acts.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement
32from acts.test_utils.bt.bt_test_utils import reset_bluetooth
33from acts.test_utils.bt.bt_test_utils import scan_result
34
35class BleStressTest(BluetoothBaseTest):
36    default_timeout = 10
37    PAIRING_TIMEOUT = 20
38
39    def __init__(self, controllers):
40        BluetoothBaseTest.__init__(self, controllers)
41        self.droid_list = get_advanced_droid_list(self.android_devices)
42        self.scn_ad = self.android_devices[0]
43        self.adv_ad = self.android_devices[1]
44
45    def teardown_test(self):
46        super(BluetoothBaseTest, self).teardown_test()
47        self.log_stats()
48
49    def bleadvertise_verify_onsuccess_handler(self, event):
50        test_result = True
51        self.log.debug("Verifying onSuccess event")
52        self.log.debug(pprint.pformat(event))
53        return test_result
54
55    def _verify_successful_bond(self, target_address):
56        end_time = time.time() + self.PAIRING_TIMEOUT
57        self.log.info("Verifying devices are bonded")
58        while time.time() < end_time:
59            bonded_devices = self.scn_ad.droid.bluetoothGetBondedDevices()
60            if target_address in {d['address'] for d in bonded_devices}:
61                self.log.info("Successfully bonded to device")
62                return True
63        return False
64
65    @BluetoothBaseTest.bt_test_wrap
66    def test_loop_scanning_1000(self):
67        """Stress start/stop scan instances.
68
69        This test will start and stop scan instances as fast as possible. This
70        will guarantee that the scan instances are properly being cleaned up
71        when the scan is stopped.
72
73        Steps:
74        1. Start a scan instance.
75        2. Stop the scan instance.
76        3. Repeat steps 1-2 1000 times.
77
78        Expected Result:
79        Neither starting or stopping scan instances causes any failures.
80
81        Returns:
82          Pass if True
83          Fail if False
84
85        TAGS: LE, Scanning, Stress
86        Priority: 1
87        """
88        test_result = True
89        for _ in range(1000):
90            filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
91                self.scn_ad.droid)
92            self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
93                                              scan_callback)
94            self.scn_ad.droid.bleStopBleScan(scan_callback)
95        return test_result
96
97    @BluetoothBaseTest.bt_test_wrap
98    def test_loop_scanning_100_verify_no_hci_timeout(self):
99        """Stress start/stop scan instances variant.
100
101        This test will start and stop scan instances with a one second timeout
102        in between each iteration. This testcase was added because the specific
103        timing combination caused hci timeouts.
104
105        Steps:
106        1. Start a scan instance.
107        2. Stop the scan instance.
108        3. Sleep for 1 second.
109        4. Repeat steps 1-3 100 times.
110
111        Expected Result:
112        Neither starting or stopping scan instances causes any failures.
113
114        Returns:
115          Pass if True
116          Fail if False
117
118        TAGS: LE, Scanning, Stress
119        Priority: 1
120        """
121        for _ in range(self.droid_list[1]['max_advertisements']):
122            adv_callback, adv_data, adv_settings = generate_ble_advertise_objects(
123                self.adv_ad.droid)
124            self.adv_ad.droid.bleStartBleAdvertising(adv_callback, adv_data,
125                                                     adv_settings)
126        for _ in range(100):
127            filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
128                self.scn_ad.droid)
129            self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
130                                              scan_callback)
131            self.log.info(self.scn_ad.ed.pop_event(scan_result.format(
132                scan_callback)))
133            self.scn_ad.droid.bleStopBleScan(scan_callback)
134            time.sleep(1)
135        return True
136
137    @BluetoothBaseTest.bt_test_wrap
138    def test_loop_advertising_100(self):
139        """Stress start/stop advertising instances.
140
141        This test will start and stop advertising instances as fast as possible.
142
143        Steps:
144        1. Start a advertising instance.
145        2. Find that an onSuccess callback is triggered.
146        3. Stop the advertising instance.
147        4. Repeat steps 1-3 100 times.
148
149        Expected Result:
150        Neither starting or stopping advertising instances causes any failures.
151
152        Returns:
153          Pass if True
154          Fail if False
155
156        TAGS: LE, Advertising, Stress
157        Priority: 1
158        """
159        test_result = True
160        for _ in range(100):
161            advertise_callback, advertise_data, advertise_settings = generate_ble_advertise_objects(
162                self.adv_ad.droid)
163            self.adv_ad.droid.bleStartBleAdvertising(
164                advertise_callback, advertise_data, advertise_settings)
165            expected_advertise_event_name = "".join(["BleAdvertise", str(
166                advertise_callback), "onSuccess"])
167            worker = self.adv_ad.ed.handle_event(
168                self.bleadvertise_verify_onsuccess_handler,
169                expected_advertise_event_name, ([]), self.default_timeout)
170            try:
171                self.log.debug(worker.result(self.default_timeout))
172            except Empty as error:
173                self.log.debug(" ".join(["Test failed with Empty error:", str(
174                    error)]))
175                test_result = False
176            except concurrent.futures._base.TimeoutError as error:
177                self.log.debug(" ".join([
178                    "Test failed, filtering callback onSuccess never occurred:",
179                    str(error)
180                ]))
181                test_result = False
182            self.adv_ad.droid.bleStopBleAdvertising(advertise_callback)
183        return test_result
184
185    @BluetoothBaseTest.bt_test_wrap
186    def test_restart_advertise_callback_after_bt_toggle(self):
187        """Test to reuse an advertise callback.
188
189        This will verify if advertising objects can be reused after a bluetooth
190        toggle.
191
192        Steps:
193        1. Start a advertising instance.
194        2. Find that an onSuccess callback is triggered.
195        3. Stop the advertising instance.
196        4. Toggle bluetooth off and on.
197        5. Start an advertising instance on the same objects used in step 1.
198        6. Find that an onSuccess callback is triggered.
199
200        Expected Result:
201        Advertisement should start successfully.
202
203        Returns:
204          Pass if True
205          Fail if False
206
207        TAGS: LE, Advertising, Stress
208        Priority: 1
209        """
210        test_result = True
211        advertise_callback, advertise_data, advertise_settings = generate_ble_advertise_objects(
212            self.adv_ad.droid)
213        self.adv_ad.droid.bleStartBleAdvertising(
214            advertise_callback, advertise_data, advertise_settings)
215        expected_advertise_event_name = "".join(["BleAdvertise", str(
216            advertise_callback), "onSuccess"])
217        worker = self.adv_ad.ed.handle_event(
218            self.bleadvertise_verify_onsuccess_handler,
219            expected_advertise_event_name, ([]), self.default_timeout)
220        try:
221            self.log.debug(worker.result(self.default_timeout))
222        except Empty as error:
223            self.log.debug(" ".join(["Test failed with Empty error:", str(
224                error)]))
225            test_result = False
226        except concurrent.futures._base.TimeoutError as error:
227            self.log.debug(" ".join(
228                ["Test failed, filtering callback onSuccess never occurred:",
229                 str(error)]))
230        test_result = reset_bluetooth([self.scn_ad])
231        if not test_result:
232            return test_result
233        time.sleep(5)
234        self.adv_ad.droid.bleStartBleAdvertising(
235            advertise_callback, advertise_data, advertise_settings)
236        worker = self.adv_ad.ed.handle_event(
237            self.bleadvertise_verify_onsuccess_handler,
238            expected_advertise_event_name, ([]), self.default_timeout)
239        try:
240            self.log.debug(worker.result(self.default_timeout))
241        except Empty as error:
242            self.log.debug(" ".join(["Test failed with Empty error:", str(
243                error)]))
244            test_result = False
245        except concurrent.futures._base.TimeoutError as error:
246            self.log.debug(" ".join(
247                ["Test failed, filtering callback onSuccess never occurred:",
248                 str(error)]))
249        return test_result
250
251    @BluetoothBaseTest.bt_test_wrap
252    def test_restart_scan_callback_after_bt_toggle(self):
253        """Test to reuse an scan callback.
254
255        This will verify if scan objects can be reused after a bluetooth
256        toggle.
257
258        Steps:
259        1. Start a scanning instance.
260        3. Stop the scanning instance.
261        4. Toggle bluetooth off and on.
262        5. Start an scanning instance on the same objects used in step 1.
263
264        Expected Result:
265        Scanner should start successfully.
266
267        Returns:
268          Pass if True
269          Fail if False
270
271        TAGS: LE, Scanning, Stress
272        Priority: 1
273        """
274        test_result = True
275        filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
276            self.scn_ad.droid)
277        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
278                                          scan_callback)
279        reset_bluetooth([self.scn_ad])
280        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
281                                          scan_callback)
282        return test_result
283
284    @BluetoothBaseTest.bt_test_wrap
285    def test_le_pairing(self):
286        """Test LE pairing transport stress
287
288        This will test LE pairing between two android devices.
289
290        Steps:
291        1. Start an LE advertisement on secondary device.
292        2. Find address from primary device.
293        3. Discover and bond to LE address.
294        4. Stop LE advertisement on secondary device.
295        5. Repeat steps 1-4 100 times
296
297        Expected Result:
298        LE pairing should pass 100 times.
299
300        Returns:
301          Pass if True
302          Fail if False
303
304        TAGS: LE, Scanning, Stress, Pairing
305        Priority: 1
306        """
307        iterations = 100
308        for i in range(iterations):
309            try:
310                target_address, adv_callback = get_mac_address_of_generic_advertisement(
311                    self.scn_ad, self.adv_ad)
312            except BtTestUtilsError as err:
313                self.log.error(err)
314                return False
315            self.log.info("Begin interation {}/{}".format(i + 1, iterations))
316            self.scn_ad.droid.bluetoothStartPairingHelper()
317            self.adv_ad.droid.bluetoothStartPairingHelper()
318            start_time = self.start_timer()
319            self.scn_ad.droid.bluetoothDiscoverAndBond(target_address)
320            if not self._verify_successful_bond(target_address):
321                self.log.error("Failed to bond devices.")
322                return False
323            self.log.info("Total time (ms): {}".format(self.end_timer()))
324            if not clear_bonded_devices(self.scn_ad):
325                self.log.error("Failed to unbond device from scanner.")
326                return False
327            if not clear_bonded_devices(self.adv_ad):
328                self.log.error("Failed to unbond device from advertiser.")
329                return False
330            self.adv_ad.droid.bleStopBleAdvertising(adv_callback)
331            # Magic sleep to let unbonding finish
332            time.sleep(2)
333        return True
334