1#!/usr/bin/env python3.4 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 Telephony Test Functionality 18""" 19 20import os 21import time 22import inspect 23import traceback 24 25import acts.controllers.diag_logger 26 27from acts.base_test import BaseTestClass 28from acts.keys import Config 29from acts.signals import TestSignal 30from acts import utils 31 32from acts.test_utils.tel.tel_subscription_utils import \ 33 get_subid_from_slot_index 34from acts.test_utils.tel.tel_subscription_utils import \ 35 initial_set_up_for_subid_infomation 36from acts.test_utils.tel.tel_subscription_utils import set_subid_for_data 37from acts.test_utils.tel.tel_subscription_utils import \ 38 set_subid_for_message 39from acts.test_utils.tel.tel_subscription_utils import \ 40 set_subid_for_outgoing_call 41from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode 42from acts.test_utils.tel.tel_test_utils import ensure_phones_default_state 43from acts.test_utils.tel.tel_test_utils import \ 44 reset_preferred_network_type_to_allowable_range 45from acts.test_utils.tel.tel_test_utils import set_phone_screen_on 46from acts.test_utils.tel.tel_test_utils import set_phone_silent_mode 47from acts.test_utils.tel.tel_test_utils import setup_droid_properties 48from acts.test_utils.tel.tel_test_utils import refresh_droid_config 49from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND 50from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING 51from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND 52from acts.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_ENABLED 53from acts.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_DISABLED 54from acts.utils import force_airplane_mode 55 56 57class _TelephonyTraceLogger(): 58 def __init__(self, logger): 59 self._logger = logger 60 61 @staticmethod 62 def _get_trace_info(): 63 # we want the stack frame above this and above the error/warning/info 64 stack_frames = inspect.stack()[2] 65 info = inspect.getframeinfo(stack_frames[0]) 66 67 return "{}:{}:{}".format( 68 os.path.basename(info.filename), info.function, info.lineno) 69 70 def error(self, msg, *args, **kwargs): 71 trace_info = _TelephonyTraceLogger._get_trace_info() 72 self._logger.error("{} - {}".format(trace_info, msg), *args, **kwargs) 73 74 def warning(self, msg, *args, **kwargs): 75 trace_info = _TelephonyTraceLogger._get_trace_info() 76 self._logger.error("{} - {}".format(trace_info, msg), *args, **kwargs) 77 78 def __getattr__(self, name): 79 return getattr(self._logger, name) 80 81 82class TelephonyBaseTest(BaseTestClass): 83 def __init__(self, controllers): 84 85 BaseTestClass.__init__(self, controllers) 86 self.logger_sessions = [] 87 88 self.log = _TelephonyTraceLogger(self.log) 89 90 # Use for logging in the test cases to facilitate 91 # faster log lookup and reduce ambiguity in logging. 92 def tel_test_wrap(fn): 93 def _safe_wrap_test_case(self, *args, **kwargs): 94 test_id = "{}:{}:{}".format(self.__class__.__name__, fn.__name__, 95 time.time()) 96 log_string = "[Test ID] {}".format(test_id) 97 self.log.info(log_string) 98 try: 99 for ad in self.android_devices: 100 ad.droid.logI("Started " + log_string) 101 # TODO: b/19002120 start QXDM Logging 102 result = fn(self, *args, **kwargs) 103 if result is not True and "telephony_auto_rerun" in self.user_params: 104 self.teardown_test() 105 # re-run only once, if re-run pass, mark as pass 106 log_string = "[Rerun Test ID] {}. 1st run failed.".format( 107 test_id) 108 self.log.info(log_string) 109 self.setup_test() 110 for ad in self.android_devices: 111 ad.droid.logI("Rerun Started " + log_string) 112 result = fn(self, *args, **kwargs) 113 if result is True: 114 self.log.info("Rerun passed.") 115 elif result is False: 116 self.log.info("Rerun failed.") 117 else: 118 # In the event that we have a non-bool or null 119 # retval, we want to clearly distinguish this in the 120 # logs from an explicit failure, though the test will 121 # still be considered a failure for reporting purposes. 122 self.log.info("Rerun indeterminate.") 123 result = False 124 return result 125 except TestSignal: 126 raise 127 except Exception as e: 128 self.log.error(traceback.format_exc()) 129 self.log.error(str(e)) 130 return False 131 finally: 132 # TODO: b/19002120 stop QXDM Logging 133 for ad in self.android_devices: 134 try: 135 ad.adb.wait_for_device() 136 ad.droid.logI("Finished " + log_string) 137 except Exception as e: 138 self.log.error(str(e)) 139 140 return _safe_wrap_test_case 141 142 def setup_class(self): 143 144 if not "sim_conf_file" in self.user_params.keys(): 145 self.log.error("Missing mandatory user config \"sim_conf_file\"!") 146 return False 147 148 sim_conf_file = self.user_params["sim_conf_file"] 149 # If the sim_conf_file is not a full path, attempt to find it 150 # relative to the config file. 151 if not os.path.isfile(sim_conf_file): 152 sim_conf_file = os.path.join( 153 self.user_params[Config.key_config_path], sim_conf_file) 154 if not os.path.isfile(sim_conf_file): 155 self.log.error("Unable to load user config " + sim_conf_file + 156 "from test config file.") 157 return False 158 159 setattr(self, 160 "diag_logger", 161 self.register_controller(acts.controllers.diag_logger, 162 required=False)) 163 for ad in self.android_devices: 164 setup_droid_properties(self.log, ad, sim_conf_file) 165 166 # Ensure that a test class starts from a consistent state that 167 # improves chances of valid network selection and facilitates 168 # logging. 169 toggle_airplane_mode(self.log, ad, True) 170 if not set_phone_screen_on(self.log, ad): 171 self.log.error("Failed to set phone screen-on time.") 172 return False 173 if not set_phone_silent_mode(self.log, ad): 174 self.log.error("Failed to set phone silent mode.") 175 return False 176 177 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 178 PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND, True) 179 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 180 PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING, True) 181 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 182 PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND, True) 183 184 if "enable_wifi_verbose_logging" in self.user_params: 185 ad.droid.wifiEnableVerboseLogging(WIFI_VERBOSE_LOGGING_ENABLED) 186 187 # Reset preferred network type. 188 reset_preferred_network_type_to_allowable_range(self.log, ad) 189 190 # Sub ID setup 191 for ad in self.android_devices: 192 initial_set_up_for_subid_infomation(self.log, ad) 193 return True 194 195 def teardown_class(self): 196 try: 197 ensure_phones_default_state(self.log, self.android_devices) 198 199 for ad in self.android_devices: 200 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 201 PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND, False) 202 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 203 PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING, False) 204 ad.droid.telephonyAdjustPreciseCallStateListenLevel( 205 PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND, False) 206 if "enable_wifi_verbose_logging" in self.user_params: 207 ad.droid.wifiEnableVerboseLogging( 208 WIFI_VERBOSE_LOGGING_DISABLED) 209 finally: 210 for ad in self.android_devices: 211 try: 212 toggle_airplane_mode(self.log, ad, True) 213 except BrokenPipeError: 214 # Broken Pipe, can not call SL4A API to turn on Airplane Mode. 215 # Use adb command to turn on Airplane Mode. 216 if not force_airplane_mode(ad, True): 217 self.log.error( 218 "Can not turn on airplane mode on:{}".format( 219 ad.serial)) 220 return True 221 222 def setup_test(self): 223 for ad in self.android_devices: 224 refresh_droid_config(self.log, ad) 225 226 if getattr(self, "diag_logger", None): 227 for logger in self.diag_logger: 228 self.log.info("Starting a diagnostic session {}".format( 229 logger)) 230 self.logger_sessions.append((logger, logger.start())) 231 232 return ensure_phones_default_state(self.log, self.android_devices) 233 234 def teardown_test(self): 235 return True 236 237 def _cleanup_logger_sessions(self): 238 for (logger, session) in self.logger_sessions: 239 self.log.info("Resetting a diagnostic session {},{}".format( 240 logger, session)) 241 logger.reset() 242 self.logger_sessions = [] 243 244 def on_exception(self, test_name, begin_time): 245 self._pull_diag_logs(test_name, begin_time) 246 self._take_bug_report(test_name, begin_time) 247 self._cleanup_logger_sessions() 248 249 def on_fail(self, test_name, begin_time): 250 self._pull_diag_logs(test_name, begin_time) 251 self._take_bug_report(test_name, begin_time) 252 self._cleanup_logger_sessions() 253 254 def on_pass(self, test_name, begin_time): 255 self._cleanup_logger_sessions() 256 257 def _pull_diag_logs(self, test_name, begin_time): 258 for (logger, session) in self.logger_sessions: 259 self.log.info("Pulling diagnostic session {}".format(logger)) 260 logger.stop(session) 261 diag_path = os.path.join(self.log_path, begin_time) 262 utils.create_dir(diag_path) 263 logger.pull(session, diag_path) 264 265 def _take_bug_report(self, test_name, begin_time): 266 if "no_bug_report_on_fail" in self.user_params: 267 return 268 269 # magical sleep to ensure the runtime restart or reboot begins 270 time.sleep(1) 271 for ad in self.android_devices: 272 try: 273 ad.adb.wait_for_device() 274 ad.take_bug_report(test_name, begin_time) 275 tombstone_path = os.path.join( 276 ad.log_path, "BugReports", 277 "{},{}".format(begin_time, ad.serial).replace(' ', '_')) 278 utils.create_dir(tombstone_path) 279 ad.adb.pull('/data/tombstones/', tombstone_path) 280 except: 281 ad.log.error("Failed to take a bug report for {}, {}" 282 .format(ad.serial, test_name)) 283