• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2016 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of 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,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16"""
17    Base Class for Defining Common Bluetooth Test Functionality
18"""
19
20import threading
21import time
22import traceback
23import os
24from acts.base_test import BaseTestClass
25from acts.signals import TestSignal
26from acts.utils import dump_string_to_file
27
28from acts.libs.proto.proto_utils import parse_proto_to_ascii
29from acts_contrib.test_utils.bt.bt_metrics_utils import get_bluetooth_metrics
30from acts_contrib.test_utils.bt.bt_test_utils import get_device_selector_dictionary
31from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth
32from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
33from acts_contrib.test_utils.bt.bt_test_utils import take_btsnoop_logs
34from acts_contrib.test_utils.bt.ble_lib import BleLib
35from acts_contrib.test_utils.bt.bta_lib import BtaLib
36from acts_contrib.test_utils.bt.config_lib import ConfigLib
37from acts_contrib.test_utils.bt.gattc_lib import GattClientLib
38from acts_contrib.test_utils.bt.gatts_lib import GattServerLib
39from acts_contrib.test_utils.bt.rfcomm_lib import RfcommLib
40from acts_contrib.test_utils.bt.shell_commands_lib import ShellCommands
41
42
43class BluetoothBaseTest(BaseTestClass):
44    DEFAULT_TIMEOUT = 10
45    start_time = 0
46    timer_list = []
47
48    def collect_bluetooth_manager_metrics_logs(self, ads, test_name):
49        """
50        Collect Bluetooth metrics logs, save an ascii log to disk and return
51        both binary and ascii logs to caller
52        :param ads: list of active Android devices
53        :return: List of binary metrics logs,
54                List of ascii metrics logs
55        """
56        bluetooth_logs = []
57        bluetooth_logs_ascii = []
58        for ad in ads:
59            serial = ad.serial
60            out_name = "{}_{}_{}".format(serial, test_name,
61                                         "bluetooth_metrics.txt")
62            bluetooth_log = get_bluetooth_metrics(ad)
63            bluetooth_log_ascii = parse_proto_to_ascii(bluetooth_log)
64            dump_string_to_file(bluetooth_log_ascii,
65                                os.path.join(ad.metrics_path, out_name))
66            bluetooth_logs.append(bluetooth_log)
67            bluetooth_logs_ascii.append(bluetooth_log_ascii)
68        return bluetooth_logs, bluetooth_logs_ascii
69
70    # Use for logging in the test cases to facilitate
71    # faster log lookup and reduce ambiguity in logging.
72    @staticmethod
73    def bt_test_wrap(fn):
74        def _safe_wrap_test_case(self, *args, **kwargs):
75            test_id = "{}:{}:{}".format(self.__class__.__name__, fn.__name__,
76                                        time.time())
77            log_string = "[Test ID] {}".format(test_id)
78            self.log.info(log_string)
79            try:
80                for ad in self.android_devices:
81                    ad.droid.logI("Started " + log_string)
82                result = fn(self, *args, **kwargs)
83                for ad in self.android_devices:
84                    ad.droid.logI("Finished " + log_string)
85                if result is not True and "bt_auto_rerun" in self.user_params:
86                    self.teardown_test()
87                    log_string = "[Rerun Test ID] {}. 1st run failed.".format(
88                        test_id)
89                    self.log.info(log_string)
90                    self.setup_test()
91                    for ad in self.android_devices:
92                        ad.droid.logI("Rerun Started " + log_string)
93                    result = fn(self, *args, **kwargs)
94                    if result is True:
95                        self.log.info("Rerun passed.")
96                    elif result is False:
97                        self.log.info("Rerun failed.")
98                    else:
99                        # In the event that we have a non-bool or null
100                        # retval, we want to clearly distinguish this in the
101                        # logs from an explicit failure, though the test will
102                        # still be considered a failure for reporting purposes.
103                        self.log.info("Rerun indeterminate.")
104                        result = False
105                return result
106            except TestSignal:
107                raise
108            except Exception as e:
109                self.log.error(traceback.format_exc())
110                self.log.error(str(e))
111                raise
112            return fn(self, *args, **kwargs)
113
114        return _safe_wrap_test_case
115
116    def setup_class(self):
117        super().setup_class()
118        for ad in self.android_devices:
119            self._setup_bt_libs(ad)
120        if 'preferred_device_order' in self.user_params:
121            prefered_device_order = self.user_params['preferred_device_order']
122            for i, ad in enumerate(self.android_devices):
123                if ad.serial in prefered_device_order:
124                    index = prefered_device_order.index(ad.serial)
125                    self.android_devices[i], self.android_devices[index] = \
126                        self.android_devices[index], self.android_devices[i]
127
128        if "reboot_between_test_class" in self.user_params:
129            threads = []
130            for a in self.android_devices:
131                thread = threading.Thread(
132                    target=self._reboot_device, args=([a]))
133                threads.append(thread)
134                thread.start()
135            for t in threads:
136                t.join()
137        if not setup_multiple_devices_for_bt_test(self.android_devices):
138            return False
139        self.device_selector = get_device_selector_dictionary(
140            self.android_devices)
141        if "bluetooth_proto_path" in self.user_params:
142            for ad in self.android_devices:
143                ad.metrics_path = os.path.join(ad.log_path, "BluetoothMetrics")
144                os.makedirs(ad.metrics_path, exist_ok=True)
145                # Clear metrics.
146                get_bluetooth_metrics(ad)
147        return True
148
149    def teardown_class(self):
150        if "bluetooth_proto_path" in self.user_params:
151            # Collect metrics here bassed off class name
152            bluetooth_logs, bluetooth_logs_ascii = \
153                self.collect_bluetooth_manager_metrics_logs(
154                    self.android_devices, self.__class__.__name__)
155
156    def setup_test(self):
157        self.timer_list = []
158        for a in self.android_devices:
159            a.ed.clear_all_events()
160            a.droid.setScreenTimeout(500)
161            a.droid.wakeUpNow()
162        return True
163
164    def on_fail(self, test_name, begin_time):
165        self.log.debug(
166            "Test {} failed. Gathering bugreport and btsnoop logs".format(
167                test_name))
168        take_btsnoop_logs(self.android_devices, self, test_name)
169        self._take_bug_report(test_name, begin_time)
170        for _ in range(5):
171            if reset_bluetooth(self.android_devices):
172                break
173            else:
174                self.log.error("Failed to reset Bluetooth... retrying.")
175        return
176
177    def _get_time_in_milliseconds(self):
178        return int(round(time.time() * 1000))
179
180    def start_timer(self):
181        self.start_time = self._get_time_in_milliseconds()
182
183    def end_timer(self):
184        total_time = self._get_time_in_milliseconds() - self.start_time
185        self.timer_list.append(total_time)
186        self.start_time = 0
187        return total_time
188
189    def log_stats(self):
190        if self.timer_list:
191            self.log.info("Overall list {}".format(self.timer_list))
192            self.log.info("Average of list {}".format(
193                sum(self.timer_list) / float(len(self.timer_list))))
194            self.log.info("Maximum of list {}".format(max(self.timer_list)))
195            self.log.info("Minimum of list {}".format(min(self.timer_list)))
196            self.log.info("Total items in list {}".format(
197                len(self.timer_list)))
198        self.timer_list = []
199
200    def _setup_bt_libs(self, android_device):
201        # Bluetooth Low Energy library.
202        setattr(android_device, "ble", BleLib(
203            log=self.log, dut=android_device))
204        # Bluetooth Adapter library.
205        setattr(android_device, "bta", BtaLib(
206            log=self.log, dut=android_device))
207        # Bluetooth stack config library.
208        setattr(android_device, "config",
209                ConfigLib(log=self.log, dut=android_device))
210        # GATT Client library.
211        setattr(android_device, "gattc",
212                GattClientLib(log=self.log, dut=android_device))
213        # GATT Server library.
214        setattr(android_device, "gatts",
215                GattServerLib(log=self.log, dut=android_device))
216        # RFCOMM library.
217        setattr(android_device, "rfcomm",
218                RfcommLib(log=self.log, dut=android_device))
219        # Shell command library
220        setattr(android_device, "shell",
221                ShellCommands(log=self.log, dut=android_device))
222        # Setup Android Device feature list
223        setattr(android_device, "features",
224                android_device.adb.shell("pm list features").split("\n"))
225