blob: e3495aa1d2c1475ce2f91920a40dcc4d8e74121a [file] [log] [blame]
#!/usr/bin/env python3.4
#
# Copyright 2018 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import time
import acts.test_utils.power.PowerBaseTest as PBT
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.test_utils.power.tel_simulations.GsmSimulation import GsmSimulation
from acts.test_utils.power.tel_simulations.LteSimulation import LteSimulation
from acts.test_utils.power.tel_simulations.UmtsSimulation import UmtsSimulation
from acts.test_utils.power.tel_simulations.LteCaSimulation import LteCaSimulation
class PowerCellularLabBaseTest(PBT.PowerBaseTest):
""" Base class for Cellular power related tests.
Inherits from PowerBaseTest so it has methods to collect power measurements.
Provides methods to setup and control the Anritsu simulation.
"""
# List of test name keywords that indicate the RAT to be used
PARAM_SIM_TYPE_LTE = "lte"
PARAM_SIM_TYPE_LTE_CA = "lteca"
PARAM_SIM_TYPE_UMTS = "umts"
PARAM_SIM_TYPE_GSM = "gsm"
# User param keywords
KEY_CALIBRATION_TABLE = "calibration_table"
def __init__(self, controllers):
""" Class initialization.
Sets class attributes to None.
"""
super().__init__(controllers)
self.simulation = None
self.anritsu = None
self.calibration_table = {}
# If callbox version was not specified in the config files,
# set a default value
if not hasattr(self, "md8475_version"):
self.md8475_version = "A"
def setup_class(self):
""" Executed before any test case is started.
Sets the device to rockbottom and connects to the anritsu callbox.
Returns:
False if connecting to the callbox fails.
"""
super().setup_class()
# Gets the name of the interface from which packets are sent
if hasattr(self, 'packet_senders'):
self.pkt_sender = self.packet_senders[0]
# Load calibration tables
# Load calibration tables
if self.KEY_CALIBRATION_TABLE in self.user_params:
self.calibration_table = self.unpack_custom_file(
self.user_params[self.KEY_CALIBRATION_TABLE], False)
# Store the value of the key to access the test config in the
# user_params dictionary.
self.PARAMS_KEY = self.TAG + "_params"
# Set DUT to rockbottom
self.dut_rockbottom()
# Establish connection to Anritsu Callbox
return self.connect_to_anritsu()
def connect_to_anritsu(self):
""" Connects to Anritsu Callbox and gets handle object.
Returns:
False if a connection with the callbox could not be started
"""
try:
self.anritsu = MD8475A(
self.md8475a_ip_address,
self.log,
self.wlan_option,
md8475_version=self.md8475_version)
return True
except AnritsuError:
self.log.error('Error in connecting to Anritsu Callbox')
return False
def setup_test(self):
""" Executed before every test case.
Parses parameters from the test name and sets a simulation up according
to those values. Also takes care of attaching the phone to the base
station. Because starting new simulations and recalibrating takes some
time, the same simulation object is kept between tests and is only
destroyed and re instantiated in case the RAT is different from the
previous tests.
Children classes need to call the parent method first. This method will
create the list self.parameters with the keywords separated by
underscores in the test name and will remove the ones that were consumed
for the simulation config. The setup_test methods in the children
classes can then consume the remaining values.
"""
# Get list of parameters from the test name
self.parameters = self.current_test_name.split('_')
# Remove the 'test' keyword
self.parameters.remove('test')
# Decide what type of simulation and instantiate it if needed
if self.consume_parameter(self.PARAM_SIM_TYPE_LTE):
self.init_simulation(self.PARAM_SIM_TYPE_LTE)
elif self.consume_parameter(self.PARAM_SIM_TYPE_LTE_CA):
self.init_simulation(self.PARAM_SIM_TYPE_LTE_CA)
elif self.consume_parameter(self.PARAM_SIM_TYPE_UMTS):
self.init_simulation(self.PARAM_SIM_TYPE_UMTS)
elif self.consume_parameter(self.PARAM_SIM_TYPE_GSM):
self.init_simulation(self.PARAM_SIM_TYPE_GSM)
else:
self.log.error(
"Simulation type needs to be indicated in the test name.")
return False
# Changing cell parameters requires the phone to be detached
self.simulation.detach()
# Parse simulation parameters.
# This may throw a ValueError exception if incorrect values are passed
# or if required arguments are omitted.
try:
self.simulation.parse_parameters(self.parameters)
except ValueError as error:
self.log.error(str(error))
return False
# Wait for new params to settle
time.sleep(5)
# Attach the phone to the basestation
if not self.simulation.attach():
return False
self.simulation.start_test_case()
# Make the device go to sleep
self.dut.droid.goToSleepNow()
return True
def consume_parameter(self, parameter_name, num_values=0):
""" Parses a parameter from the test name.
Allows the test to get parameters from its name. Deletes parameters from
the list after consuming them to ensure that they are not used twice.
Args:
parameter_name: keyword to look up in the test name
num_values: number of arguments following the parameter name in the
test name
Returns:
A list containing the parameter name and the following num_values
arguments.
"""
try:
i = self.parameters.index(parameter_name)
except ValueError:
# parameter_name is not set
return []
return_list = []
try:
for j in range(num_values + 1):
return_list.append(self.parameters.pop(i))
except IndexError:
self.log.error(
"Parameter {} has to be followed by {} values.".format(
parameter_name, num_values))
raise ValueError()
return return_list
def teardown_class(self):
"""Clean up the test class after tests finish running.
Stop the simulation and then disconnect from the Anritsu Callbox.
"""
super().teardown_class()
if self.anritsu:
self.anritsu.stop_simulation()
self.anritsu.disconnect()
def init_simulation(self, sim_type):
""" Starts a new simulation only if needed.
Only starts a new simulation if type is different from the one running
before.
Args:
type: defines the type of simulation to be started.
"""
simulation_dictionary = {
self.PARAM_SIM_TYPE_LTE: LteSimulation,
self.PARAM_SIM_TYPE_UMTS: UmtsSimulation,
self.PARAM_SIM_TYPE_GSM: GsmSimulation,
self.PARAM_SIM_TYPE_LTE_CA: LteCaSimulation
}
if not sim_type in simulation_dictionary:
raise ValueError("The provided simulation type is invalid.")
simulation_class = simulation_dictionary[sim_type]
if isinstance(self.simulation, simulation_class):
# The simulation object we already have is enough.
return
if self.simulation:
# Make sure the simulation is stopped before loading a new one
self.simulation.stop()
# If the calibration table doesn't have an entry for this simulation
# type add an empty one
if sim_type not in self.calibration_table:
self.calibration_table[sim_type] = {}
# Instantiate a new simulation
self.simulation = simulation_class(self.anritsu, self.log, self.dut,
self.user_params[self.PARAMS_KEY],
self.calibration_table[sim_type])
# Start the simulation
self.simulation.start()