1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - The Android Open Source Project 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. 16import time 17 18import acts.test_utils.power.PowerBaseTest as PBT 19from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError 20from acts.controllers.anritsu_lib.md8475a import MD8475A 21from acts.test_utils.power.tel_simulations.GsmSimulation import GsmSimulation 22from acts.test_utils.power.tel_simulations.LteSimulation import LteSimulation 23from acts.test_utils.power.tel_simulations.UmtsSimulation import UmtsSimulation 24from acts.test_utils.power.tel_simulations.LteCaSimulation import LteCaSimulation 25 26 27class PowerCellularLabBaseTest(PBT.PowerBaseTest): 28 """ Base class for Cellular power related tests. 29 30 Inherits from PowerBaseTest so it has methods to collect power measurements. 31 Provides methods to setup and control the Anritsu simulation. 32 33 """ 34 35 # List of test name keywords that indicate the RAT to be used 36 37 PARAM_SIM_TYPE_LTE = "lte" 38 PARAM_SIM_TYPE_LTE_CA = "lteca" 39 PARAM_SIM_TYPE_UMTS = "umts" 40 PARAM_SIM_TYPE_GSM = "gsm" 41 42 # User param keywords 43 KEY_CALIBRATION_TABLE = "calibration_table" 44 45 def __init__(self, controllers): 46 """ Class initialization. 47 48 Sets class attributes to None. 49 """ 50 51 super().__init__(controllers) 52 53 self.simulation = None 54 self.anritsu = None 55 self.calibration_table = {} 56 57 # If callbox version was not specified in the config files, 58 # set a default value 59 if not hasattr(self, "md8475_version"): 60 self.md8475_version = "A" 61 62 def setup_class(self): 63 """ Executed before any test case is started. 64 65 Sets the device to rockbottom and connects to the anritsu callbox. 66 67 Returns: 68 False if connecting to the callbox fails. 69 """ 70 71 super().setup_class() 72 73 # Gets the name of the interface from which packets are sent 74 if hasattr(self, 'packet_senders'): 75 self.pkt_sender = self.packet_senders[0] 76 77 # Load calibration tables 78 # Load calibration tables 79 if self.KEY_CALIBRATION_TABLE in self.user_params: 80 self.calibration_table = self.unpack_custom_file( 81 self.user_params[self.KEY_CALIBRATION_TABLE], False) 82 83 # Store the value of the key to access the test config in the 84 # user_params dictionary. 85 self.PARAMS_KEY = self.TAG + "_params" 86 87 # Set DUT to rockbottom 88 self.dut_rockbottom() 89 90 # Establish connection to Anritsu Callbox 91 return self.connect_to_anritsu() 92 93 def connect_to_anritsu(self): 94 """ Connects to Anritsu Callbox and gets handle object. 95 96 Returns: 97 False if a connection with the callbox could not be started 98 """ 99 100 try: 101 102 self.anritsu = MD8475A( 103 self.md8475a_ip_address, 104 self.log, 105 self.wlan_option, 106 md8475_version=self.md8475_version) 107 return True 108 except AnritsuError: 109 self.log.error('Error in connecting to Anritsu Callbox') 110 return False 111 112 def setup_test(self): 113 """ Executed before every test case. 114 115 Parses parameters from the test name and sets a simulation up according 116 to those values. Also takes care of attaching the phone to the base 117 station. Because starting new simulations and recalibrating takes some 118 time, the same simulation object is kept between tests and is only 119 destroyed and re instantiated in case the RAT is different from the 120 previous tests. 121 122 Children classes need to call the parent method first. This method will 123 create the list self.parameters with the keywords separated by 124 underscores in the test name and will remove the ones that were consumed 125 for the simulation config. The setup_test methods in the children 126 classes can then consume the remaining values. 127 """ 128 129 # Get list of parameters from the test name 130 self.parameters = self.current_test_name.split('_') 131 132 # Remove the 'test' keyword 133 self.parameters.remove('test') 134 135 # Decide what type of simulation and instantiate it if needed 136 if self.consume_parameter(self.PARAM_SIM_TYPE_LTE): 137 self.init_simulation(self.PARAM_SIM_TYPE_LTE) 138 elif self.consume_parameter(self.PARAM_SIM_TYPE_LTE_CA): 139 self.init_simulation(self.PARAM_SIM_TYPE_LTE_CA) 140 elif self.consume_parameter(self.PARAM_SIM_TYPE_UMTS): 141 self.init_simulation(self.PARAM_SIM_TYPE_UMTS) 142 elif self.consume_parameter(self.PARAM_SIM_TYPE_GSM): 143 self.init_simulation(self.PARAM_SIM_TYPE_GSM) 144 else: 145 self.log.error( 146 "Simulation type needs to be indicated in the test name.") 147 return False 148 149 # Changing cell parameters requires the phone to be detached 150 self.simulation.detach() 151 152 # Parse simulation parameters. 153 # This may throw a ValueError exception if incorrect values are passed 154 # or if required arguments are omitted. 155 try: 156 self.simulation.parse_parameters(self.parameters) 157 except ValueError as error: 158 self.log.error(str(error)) 159 return False 160 161 # Wait for new params to settle 162 time.sleep(5) 163 164 # Attach the phone to the basestation 165 if not self.simulation.attach(): 166 return False 167 168 self.simulation.start_test_case() 169 170 # Make the device go to sleep 171 self.dut.droid.goToSleepNow() 172 173 return True 174 175 def consume_parameter(self, parameter_name, num_values=0): 176 """ Parses a parameter from the test name. 177 178 Allows the test to get parameters from its name. Deletes parameters from 179 the list after consuming them to ensure that they are not used twice. 180 181 Args: 182 parameter_name: keyword to look up in the test name 183 num_values: number of arguments following the parameter name in the 184 test name 185 Returns: 186 A list containing the parameter name and the following num_values 187 arguments. 188 """ 189 190 try: 191 i = self.parameters.index(parameter_name) 192 except ValueError: 193 # parameter_name is not set 194 return [] 195 196 return_list = [] 197 198 try: 199 for j in range(num_values + 1): 200 return_list.append(self.parameters.pop(i)) 201 except IndexError: 202 self.log.error( 203 "Parameter {} has to be followed by {} values.".format( 204 parameter_name, num_values)) 205 raise ValueError() 206 207 return return_list 208 209 def teardown_class(self): 210 """Clean up the test class after tests finish running. 211 212 Stop the simulation and then disconnect from the Anritsu Callbox. 213 214 """ 215 super().teardown_class() 216 217 if self.anritsu: 218 self.anritsu.stop_simulation() 219 self.anritsu.disconnect() 220 221 def init_simulation(self, sim_type): 222 """ Starts a new simulation only if needed. 223 224 Only starts a new simulation if type is different from the one running 225 before. 226 227 Args: 228 type: defines the type of simulation to be started. 229 """ 230 231 simulation_dictionary = { 232 self.PARAM_SIM_TYPE_LTE: LteSimulation, 233 self.PARAM_SIM_TYPE_UMTS: UmtsSimulation, 234 self.PARAM_SIM_TYPE_GSM: GsmSimulation, 235 self.PARAM_SIM_TYPE_LTE_CA: LteCaSimulation 236 } 237 238 if not sim_type in simulation_dictionary: 239 raise ValueError("The provided simulation type is invalid.") 240 241 simulation_class = simulation_dictionary[sim_type] 242 243 if isinstance(self.simulation, simulation_class): 244 # The simulation object we already have is enough. 245 return 246 247 if self.simulation: 248 # Make sure the simulation is stopped before loading a new one 249 self.simulation.stop() 250 251 # If the calibration table doesn't have an entry for this simulation 252 # type add an empty one 253 if sim_type not in self.calibration_table: 254 self.calibration_table[sim_type] = {} 255 256 # Instantiate a new simulation 257 self.simulation = simulation_class(self.anritsu, self.log, self.dut, 258 self.user_params[self.PARAMS_KEY], 259 self.calibration_table[sim_type]) 260 261 # Start the simulation 262 self.simulation.start() 263