Merge "Add a common controller for Headsets."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 053c580..b76b797 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,32 +1,7 @@
[Hook Scripts]
-acts_adb_test = ./acts/framework/tests/acts_adb_test.py
-acts_android_device_test = ./acts/framework/tests/acts_android_device_test.py
-acts_asserts_test = ./acts/framework/tests/acts_asserts_test.py
-acts_base_class_test = ./acts/framework/tests/acts_base_class_test.py
-acts_config_test = ./acts/framework/tests/config/unittest_bundle.py
-acts_context_test = ./acts/framework/tests/acts_context_test.py
-acts_error_test = ./acts/framework/tests/acts_error_test.py
-acts_host_utils_test = ./acts/framework/tests/acts_host_utils_test.py
-acts_import_test_utils_test = ./acts/framework/tests/acts_import_test_utils_test.py
-acts_import_unit_test = ./acts/framework/tests/acts_import_unit_test.py
-acts_job_test = ./acts/framework/tests/acts_job_test.py
-acts_libs_ota_tests = ./acts/framework/tests/libs/ota/unittest_bundle.py
-acts_logger_test = ./acts/framework/tests/acts_logger_test.py
-acts_metrics_test = ./acts/framework/tests/libs/metrics/unittest_bundle.py
-acts_records_test = ./acts/framework/tests/acts_records_test.py
-acts_relay_controller_test = ./acts/framework/tests/acts_relay_controller_test.py
-acts_test_runner_test = ./acts/framework/tests/acts_test_runner_test.py
-acts_unittest_suite = ./acts/framework/tests/acts_unittest_suite.py
-acts_utils_test = ./acts/framework/tests/acts_utils_test.py
-android_lib_unittest_bundle = ./acts/framework/tests/controllers/android_lib/android_lib_unittest_bundle.py
-event_unittest_bundle = ./acts/framework/tests/event/event_unittest_bundle.py
-instrumentation_unit_test_suite = ./acts/framework/tests/test_utils/instrumentation/unit_test_suite.py
-logging_unittest_bundle = ./acts/framework/tests/libs/logging/logging_unittest_bundle.py
-metrics_tests = ./acts/framework/tests/metrics/unittest_bundle.py
-proc_unittest_bundle = ./acts/framework/tests/libs/proc/proc_unittest_bundle.py
-sl4a_lib_suite = ./acts/framework/tests/controllers/sl4a_lib/test_suite.py
-test_runner_test = ./acts/framework/tests/test_runner_test.py
-version_selector_tests = ./acts/framework/tests/libs/version_selector_test.py
+create_virtualenv = ./tools/create_virtualenv.sh
+acts_unittests = /tmp/acts_preupload_virtualenv/bin/python3 ./acts/tests/meta/ActsUnitTest.py
+destroy_virtualenv = rm -rf /tmp/acts_preupload_virtualenv/
lab_test = ./tools/lab/lab_upload_hooks.py
proto_check = ./tools/proto_check.py
diff --git a/acts/framework/acts/base_test.py b/acts/framework/acts/base_test.py
index 0e250f4..4e3c4de 100755
--- a/acts/framework/acts/base_test.py
+++ b/acts/framework/acts/base_test.py
@@ -198,16 +198,6 @@
class_name=self.__class__.__name__,
controller_configs=self.testbed_configs)
- # Import and register the built-in controller modules specified
- # in testbed config.
- for module in self._import_builtin_controllers():
- self.register_controller(module, builtin=True)
- if hasattr(self, 'android_devices'):
- for ad in self.android_devices:
- if ad.droid:
- utils.set_location_service(ad, False)
- utils.sync_device_time(ad)
-
def _import_builtin_controllers(self):
"""Import built-in controller modules.
@@ -386,6 +376,10 @@
is called.
"""
event_bus.post(TestClassBeginEvent(self))
+ # Import and register the built-in controller modules specified
+ # in testbed config.
+ for module in self._import_builtin_controllers():
+ self.register_controller(module, builtin=True)
return self.setup_class()
def _teardown_class(self):
@@ -899,6 +893,7 @@
self._block_all_test_cases(tests)
setup_fail = True
except signals.TestAbortClass:
+ self.log.exception('Test class %s aborted' % self.TAG)
setup_fail = True
except Exception as e:
self.log.exception("Failed to setup %s.", self.TAG)
@@ -917,6 +912,7 @@
self.exec_one_testcase(test_name, test_func, self.cli_args)
return self.results
except signals.TestAbortClass:
+ self.log.exception('Test class %s aborted' % self.TAG)
return self.results
except signals.TestAbortAll as e:
# Piggy-back test results on this exception object so we don't lose
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index 52404fa..9f03c93 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -100,6 +100,10 @@
" but is not attached.") % ad.serial,
serial=ad.serial)
_start_services_on_ads(ads)
+ for ad in ads:
+ if ad.droid:
+ utils.set_location_service(ad, False)
+ utils.sync_device_time(ad)
return ads
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
index 892a786..23fee41 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
@@ -14,7 +14,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import ntpath
+import time
import acts.controllers.cellular_simulator as cc
+from acts.test_utils.power.tel_simulations import LteSimulation
from acts.controllers.anritsu_lib import md8475a
from acts.controllers.anritsu_lib import _anritsu_utils as anritsu
@@ -23,20 +26,501 @@
MD8475_VERSION = 'A'
+ # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
+ LTE_SUPPORTS_DL_256QAM = False
+
+ # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
+ LTE_SUPPORTS_UL_64QAM = False
+
+ # Indicates if 4x4 MIMO is supported for LTE
+ LTE_SUPPORTS_4X4_MIMO = False
+
+ # The maximum number of carriers that this simulator can support for LTE
+ LTE_MAX_CARRIERS = 2
+
+ # The maximum power that the equipment is able to transmit
+ MAX_DL_POWER = -10
+
+ # Simulation config files in the callbox computer.
+ # These should be replaced in the future by setting up
+ # the same configuration manually.
+ LTE_BASIC_SIM_FILE = 'SIM_default_LTE.wnssp'
+ LTE_BASIC_CELL_FILE = 'CELL_LTE_config.wnscp'
+ LTE_CA_BASIC_SIM_FILE = 'SIM_LTE_CA.wnssp'
+ LTE_CA_BASIC_CELL_FILE = 'CELL_LTE_CA_config.wnscp'
+
+ # Filepath to the config files stored in the Anritsu callbox. Needs to be
+ # formatted to replace {} with either A or B depending on the model.
+ CALLBOX_CONFIG_PATH = 'C:\\Users\\MD8475A\\Documents\\DAN_configs\\'
+
def __init__(self, ip_address):
+ """ Initializes the cellular simulator.
+
+ Args:
+ ip_address: the ip address of the MD8475 instrument
+ """
+ super().__init__()
+
try:
self.anritsu = md8475a.MD8475A(ip_address,
md8475_version=self.MD8475_VERSION)
except anritsu.AnristuError:
raise cc.CellularSimulatorError('Could not connect to MD8475.')
+ self.bts = None
+
def destroy(self):
""" Sends finalization commands to the cellular equipment and closes
the connection. """
self.anritsu.stop_simulation()
self.anritsu.disconnect()
+ def setup_lte_scenario(self):
+ """ Configures the equipment for an LTE simulation. """
+ cell_file_name = self.LTE_BASIC_CELL_FILE
+ sim_file_name = self.LTE_BASIC_SIM_FILE
+
+ cell_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, cell_file_name)
+ sim_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, sim_file_name)
+
+ self.anritsu.load_simulation_paramfile(sim_file_path)
+ self.anritsu.load_cell_paramfile(cell_file_path)
+ self.anritsu.start_simulation()
+
+ self.bts = [self.anritsu.get_BTS(md8475a.BtsNumber.BTS1)]
+
+ def setup_lte_ca_scenario(self):
+ """ Configures the equipment for an LTE with CA simulation. """
+ cell_file_name = self.LTE_CA_BASIC_CELL_FILE
+ sim_file_name = self.LTE_CA_BASIC_SIM_FILE
+
+ cell_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, cell_file_name)
+ sim_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, sim_file_name)
+
+ self.anritsu.load_simulation_paramfile(sim_file_path)
+ self.anritsu.load_cell_paramfile(cell_file_path)
+ self.anritsu.start_simulation()
+
+ self.bts = [
+ self.anritsu.get_BTS(md8475a.BtsNumber.BTS1),
+ self.anritsu.get_BTS(md8475a.BtsNumber.BTS2)
+ ]
+
+ def set_input_power(self, bts_index, input_power):
+ """ Sets the input power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ input_power: the new input power
+ """
+ self.bts[bts_index].input_level = input_power
+
+ def set_output_power(self, bts_index, output_power):
+ """ Sets the output power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ output_power: the new output power
+ """
+ self.bts[bts_index].output_level = output_power
+
+ def set_downlink_channel_number(self, bts_index, channel_number):
+ """ Sets the downlink channel number for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ channel_number: the new channel number
+ """
+ # Temporarily adding this line to workaround a bug in the
+ # Anritsu callbox in which the channel number needs to be set
+ # to a different value before setting it to the final one.
+ self.bts[bts_index].dl_channel = str(channel_number + 1)
+ time.sleep(8)
+ self.bts[bts_index].dl_channel = str(channel_number)
+
+ def set_enabled_for_ca(self, bts_index, enabled):
+ """ Enables or disables the base station during carrier aggregation.
+
+ Args:
+ bts_index: the base station number
+ enabled: whether the base station should be enabled for ca.
+ """
+ self.bts[bts_index].dl_cc_enabled = enabled
+
+ def set_dl_modulation(self, bts_index, modulation):
+ """ Sets the DL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new DL modulation
+ """
+ self.bts[bts_index].lte_dl_modulation_order = modulation
+
+ def set_ul_modulation(self, bts_index, modulation):
+ """ Sets the UL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new UL modulation
+ """
+ self.bts[bts_index].lte_ul_modulation_order = modulation
+
+ def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
+ """ Enables or disables TBS pattern in the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ tbs_pattern_on: the new TBS pattern setting
+ """
+ if tbs_pattern_on:
+ self.bts[bts_index].tbs_pattern = 'FULLALLOCATION'
+ else:
+ self.bts[bts_index].tbs_pattern = 'OFF'
+
+ def set_band(self, bts_index, band):
+ """ Sets the right duplex mode before switching to a new band.
+
+ Args:
+ bts_index: the base station number
+ band: desired band
+ """
+ bts = self.bts[bts_index]
+
+ # The callbox won't restore the band-dependent default values if the
+ # request is to switch to the same band as the one the base station is
+ # currently using. To ensure that default values are restored, go to a
+ # different band before switching.
+ if int(bts.band) == band:
+ # Using bands 1 and 2 but it could be any others
+ bts.band = '1' if band != 1 else '2'
+ # Switching to config.band will be handled by the parent class
+ # implementation of this method.
+
+ bts.duplex_mode = self.get_duplex_mode(band).value
+ bts.band = band
+ time.sleep(5) # It takes some time to propagate the new band
+
+ def get_duplex_mode(self, band):
+ """ Determines if the band uses FDD or TDD duplex mode
+
+ Args:
+ band: a band number
+ Returns:
+ an variable of class DuplexMode indicating if band is FDD or TDD
+ """
+
+ if 33 <= int(band) <= 46:
+ return LteSimulation.DuplexMode.TDD
+ else:
+ return LteSimulation.DuplexMode.FDD
+
+ def set_tdd_config(self, bts_index, config):
+ """ Sets the frame structure for TDD bands.
+
+ Args:
+ bts_index: the base station number
+ config: the desired frame structure. An int between 0 and 6.
+ """
+
+ if not 0 <= config <= 6:
+ raise ValueError("The frame structure configuration has to be a "
+ "number between 0 and 6")
+
+ self.bts[bts_index].uldl_configuration = config
+
+ # Wait for the setting to propagate
+ time.sleep(5)
+
+ def set_bandwidth(self, bts_index, bandwidth):
+ """ Sets the LTE channel bandwidth (MHz)
+
+ Args:
+ bts_index: the base station number
+ bandwidth: desired bandwidth (MHz)
+ """
+ bts = self.bts[bts_index]
+
+ if bandwidth == 20:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_20MHz
+ elif bandwidth == 15:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_15MHz
+ elif bandwidth == 10:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_10MHz
+ elif bandwidth == 5:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_5MHz
+ elif bandwidth == 3:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_3MHz
+ elif bandwidth == 1.4:
+ bts.bandwidth = md8475a.BtsBandwidth.LTE_BANDWIDTH_1dot4MHz
+ else:
+ msg = "Bandwidth = {} MHz is not valid for LTE".format(bandwidth)
+ self.log.error(msg)
+ raise ValueError(msg)
+ time.sleep(5) # It takes some time to propagate the new settings
+
+ def set_mimo_mode(self, bts_index, mimo):
+ """ Sets the number of DL antennas for the desired MIMO mode.
+
+ Args:
+ bts_index: the base station number
+ mimo: object of class MimoMode
+ """
+
+ bts = self.bts[bts_index]
+
+ # If the requested mimo mode is not compatible with the current TM,
+ # warn the user before changing the value.
+
+ if mimo == LteSimulation.MimoMode.MIMO_1x1:
+ if bts.transmode not in [
+ LteSimulation.TransmissionMode.TM1,
+ LteSimulation.TransmissionMode.TM7
+ ]:
+ self.log.warning(
+ "Using only 1 DL antennas is not allowed with "
+ "the current transmission mode. Changing the "
+ "number of DL antennas will override this "
+ "setting.")
+ bts.dl_antenna = 1
+ elif mimo == LteSimulation.MimoMode.MIMO_2x2:
+ if bts.transmode not in [
+ LteSimulation.TransmissionMode.TM2,
+ LteSimulation.TransmissionMode.TM3,
+ LteSimulation.TransmissionMode.TM4,
+ LteSimulation.TransmissionMode.TM8,
+ LteSimulation.TransmissionMode.TM9
+ ]:
+ self.log.warning("Using two DL antennas is not allowed with "
+ "the current transmission mode. Changing the "
+ "number of DL antennas will override this "
+ "setting.")
+ bts.dl_antenna = 2
+ elif mimo == LteSimulation.MimoMode.MIMO_4x4:
+ if bts.transmode not in [
+ LteSimulation.TransmissionMode.TM2,
+ LteSimulation.TransmissionMode.TM3,
+ LteSimulation.TransmissionMode.TM4,
+ LteSimulation.TransmissionMode.TM9
+ ]:
+ self.log.warning("Using four DL antennas is not allowed with "
+ "the current transmission mode. Changing the "
+ "number of DL antennas will override this "
+ "setting.")
+
+ bts.dl_antenna = 4
+ else:
+ RuntimeError("The requested MIMO mode is not supported.")
+
+ def set_scheduling_mode(self, bts_index, scheduling, mcs_dl, mcs_ul,
+ nrb_dl, nrb_ul):
+ """ Sets the scheduling mode for LTE
+
+ Args:
+ bts_index: the base station number
+ scheduling: DYNAMIC or STATIC scheduling (Enum list)
+ mcs_dl: Downlink MCS (only for STATIC scheduling)
+ mcs_ul: Uplink MCS (only for STATIC scheduling)
+ nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
+ nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
+ """
+
+ bts = self.bts[bts_index]
+ bts.lte_scheduling_mode = scheduling.value
+
+ if scheduling == LteSimulation.SchedulingMode.STATIC:
+
+ if not all([nrb_dl, nrb_ul, mcs_dl, mcs_ul]):
+ raise ValueError('When the scheduling mode is set to manual, '
+ 'the RB and MCS parameters are required.')
+
+ bts.packet_rate = md8475a.BtsPacketRate.LTE_MANUAL
+ bts.lte_mcs_dl = mcs_dl
+ bts.lte_mcs_ul = mcs_ul
+ bts.nrb_dl = nrb_dl
+ bts.nrb_ul = nrb_ul
+
+ time.sleep(5) # It takes some time to propagate the new settings
+
+ def lte_attach_secondary_carriers(self):
+ """ Activates the secondary carriers for CA. Requires the DUT to be
+ attached to the primary carrier first. """
+
+ testcase = self.anritsu.get_AnritsuTestCases()
+ # Setting the procedure to selection is needed because of a bug in the
+ # instrument's software (b/139547391).
+ testcase.procedure = md8475a.TestProcedure.PROCEDURE_SELECTION
+ testcase.procedure = md8475a.TestProcedure.PROCEDURE_MULTICELL
+ testcase.power_control = md8475a.TestPowerControl.POWER_CONTROL_DISABLE
+ testcase.measurement_LTE = md8475a.TestMeasurement.MEASUREMENT_DISABLE
+
+ self.anritsu.start_testcase()
+
+ retry_counter = 0
+ self.log.info("Waiting for the test case to start...")
+ time.sleep(5)
+
+ while self.anritsu.get_testcase_status() == "0":
+ retry_counter += 1
+ if retry_counter == 3:
+ raise RuntimeError(
+ "The test case failed to start after {} "
+ "retries. The connection between the phone "
+ "and the base station might be unstable.".format(
+ retry_counter))
+ time.sleep(10)
+
+ def set_transmission_mode(self, bts_index, tmode):
+ """ Sets the transmission mode for the LTE basetation
+
+ Args:
+ bts_index: the base station number
+ tmode: Enum list from class 'TransmissionModeLTE'
+ """
+
+ bts = self.bts[bts_index]
+
+ # If the selected transmission mode does not support the number of DL
+ # antennas, throw an exception.
+ if (tmode in [
+ LteSimulation.TransmissionMode.TM1,
+ LteSimulation.TransmissionMode.TM7
+ ] and bts.dl_antenna != '1'):
+ # TM1 and TM7 only support 1 DL antenna
+ raise ValueError("{} allows only one DL antenna. Change the "
+ "number of DL antennas before setting the "
+ "transmission mode.".format(tmode.value))
+ elif (tmode == LteSimulation.TransmissionMode.TM8
+ and bts.dl_antenna != '2'):
+ # TM8 requires 2 DL antennas
+ raise ValueError("TM2 requires two DL antennas. Change the "
+ "number of DL antennas before setting the "
+ "transmission mode.")
+ elif (tmode in [
+ LteSimulation.TransmissionMode.TM2,
+ LteSimulation.TransmissionMode.TM3,
+ LteSimulation.TransmissionMode.TM4,
+ LteSimulation.TransmissionMode.TM9
+ ] and bts.dl_antenna == '1'):
+ # TM2, TM3, TM4 and TM9 require 2 or 4 DL antennas
+ raise ValueError("{} requires at least two DL atennas. Change the "
+ "number of DL antennas before setting the "
+ "transmission mode.".format(tmode.value))
+
+ # The TM mode is allowed for the current number of DL antennas, so it
+ # is safe to change this setting now
+ bts.transmode = tmode.value
+
+ time.sleep(5) # It takes some time to propagate the new settings
+
+ def wait_until_attached(self, timeout=120):
+ """ Waits until the DUT is attached to the primary carrier.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ try:
+ self.anritsu.wait_for_registration_state(time_to_wait=timeout)
+ except anritsu.AnritsuError:
+ raise cc.CellularSimulatorError('The phone did not attach before '
+ 'the timeout period ended.')
+
+ def wait_until_communication_state(self, timeout=120):
+ """ Waits until the DUT is in Communication state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ try:
+ self.anritsu.wait_for_communication_state(time_to_wait=timeout)
+ except anritsu.AnritsuError:
+ raise cc.CellularSimulatorError('The phone was not in '
+ 'Communication state before '
+ 'the timeout period ended.')
+
+ def wait_until_idle_state(self, timeout=120):
+ """ Waits until the DUT is in Idle state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ try:
+ self.anritsu.wait_for_idle_state(time_to_wait=timeout)
+ except anritsu.AnritsuError:
+ raise cc.CellularSimulatorError('The phone was not in Idle state '
+ 'before the time the timeout '
+ 'period ended.')
+
+ def detach(self):
+ """ Turns off all the base stations so the DUT loose connection."""
+ self.anritsu.set_simulation_state_to_poweroff()
+
+ def stop(self):
+ """ Stops current simulation. After calling this method, the simulator
+ will need to be set up again. """
+ self.simulator.stop()
+
+ def start_data_traffic(self):
+ """ Starts transmitting data from the instrument to the DUT. """
+ try:
+ self.anritsu.start_ip_traffic()
+ except md8475a.AnritsuError as inst:
+ # This typically happens when traffic is already running.
+ # TODO (b/141962691): continue only if traffic is running
+ self.log.warning(str(inst))
+ time.sleep(4)
+
+ def stop_data_traffic(self):
+ """ Stops transmitting data from the instrument to the DUT. """
+ try:
+ self.anritsu.stop_ip_traffic()
+ except md8475a.AnritsuError as inst:
+ # This typically happens when traffic has already been stopped
+ # TODO (b/141962691): continue only if traffic is stopped
+ self.log.warning(str(inst))
+ time.sleep(2)
+
class MD8475BCellularSimulator(MD8475CellularSimulator):
MD8475_VERSION = 'B'
+
+ # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
+ LTE_SUPPORTS_DL_256QAM = True
+
+ # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
+ LTE_SUPPORTS_UL_64QAM = True
+
+ # Indicates if 4x4 MIMO is supported for LTE
+ LTE_SUPPORTS_4X4_MIMO = True
+
+ # The maximum number of carriers that this simulator can support for LTE
+ LTE_MAX_CARRIERS = 4
+
+ # The maximum power that the equipment is able to transmit
+ MAX_DL_POWER = -30
+
+ # Simulation config files in the callbox computer.
+ # These should be replaced in the future by setting up
+ # the same configuration manually.
+ LTE_BASIC_SIM_FILE = 'SIM_default_LTE.wnssp2'
+ LTE_BASIC_CELL_FILE = 'CELL_LTE_config.wnscp2'
+ LTE_CA_BASIC_SIM_FILE = 'SIM_LTE_CA.wnssp2'
+ LTE_CA_BASIC_CELL_FILE = 'CELL_LTE_CA_config.wnscp2'
+
+ # Filepath to the config files stored in the Anritsu callbox. Needs to be
+ # formatted to replace {} with either A or B depending on the model.
+ CALLBOX_CONFIG_PATH = 'C:\\Users\\MD8475B\\Documents\\DAN_configs\\'
+
+ def setup_lte_ca_scenario(self):
+ """ The B model can support up to five carriers. """
+
+ super().setup_lte_ca_scenario()
+
+ self.bts.extend([
+ self.anritsu.get_BTS(md8475a.BtsNumber.BTS3),
+ self.anritsu.get_BTS(md8475a.BtsNumber.BTS4),
+ self.anritsu.get_BTS(md8475a.BtsNumber.BTS5)
+ ])
diff --git a/acts/framework/acts/controllers/cellular_simulator.py b/acts/framework/acts/controllers/cellular_simulator.py
index 8c82792..a140c0f 100644
--- a/acts/framework/acts/controllers/cellular_simulator.py
+++ b/acts/framework/acts/controllers/cellular_simulator.py
@@ -13,6 +13,8 @@
# 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.
+from acts import logger
+from acts.test_utils.power import tel_simulations as sims
class AbstractCellularSimulator:
@@ -22,11 +24,286 @@
This class defines the interface that every cellular simulator controller
needs to implement and shouldn't be instantiated by itself. """
+
+ # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
+ LTE_SUPPORTS_DL_256QAM = None
+
+ # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
+ LTE_SUPPORTS_UL_64QAM = None
+
+ # Indicates if 4x4 MIMO is supported for LTE
+ LTE_SUPPORTS_4X4_MIMO = None
+
+ # The maximum number of carriers that this simulator can support for LTE
+ LTE_MAX_CARRIERS = None
+
+ # The maximum power that the equipment is able to transmit
+ MAX_DL_POWER = None
+
+ def __init__(self):
+ """ Initializes the cellular simulator. """
+ self.log = logger.create_tagged_trace_logger('CellularSimulator')
+
def destroy(self):
""" Sends finalization commands to the cellular equipment and closes
the connection. """
raise NotImplementedError()
+ def setup_lte_scenario(self):
+ """ Configures the equipment for an LTE simulation. """
+ raise NotImplementedError()
+
+ def setup_lte_ca_scenario(self):
+ """ Configures the equipment for an LTE with CA simulation. """
+ raise NotImplementedError()
+
+ def configure_bts(self, config, bts_index=0):
+ """ Commands the equipment to setup a base station with the required
+ configuration. This method applies configurations that are common to all
+ RATs.
+
+ Args:
+ config: a BaseSimulation.BtsConfig object.
+ bts_index: the base station number.
+ """
+
+ if config.output_power:
+ self.set_output_power(bts_index, config.output_power)
+
+ if config.input_power:
+ self.set_input_power(bts_index, config.input_power)
+
+ if isinstance(config, sims.LteSimulation.LteSimulation.BtsConfig):
+ self.configure_lte_bts(config, bts_index)
+
+ def configure_lte_bts(self, config, bts_index=0):
+ """ Commands the equipment to setup an LTE base station with the
+ required configuration.
+
+ Args:
+ config: an LteSimulation.BtsConfig object.
+ bts_index: the base station number.
+ """
+ if config.band:
+ self.set_band(bts_index, config.band)
+
+ if config.dlul_config:
+ self.set_tdd_config(bts_index, config.dlul_config)
+
+ if config.bandwidth:
+ self.set_bandwidth(bts_index, config.bandwidth)
+
+ if config.dl_channel:
+ self.set_downlink_channel_number(bts_index, config.dl_channel)
+
+ if config.mimo_mode:
+ self.set_mimo_mode(bts_index, config.mimo_mode)
+
+ if config.transmission_mode:
+ self.set_transmission_mode(bts_index, config.transmission_mode)
+
+ if config.scheduling_mode:
+
+ if (config.scheduling_mode ==
+ sims.LteSimulation.SchedulingMode.STATIC
+ and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
+ and config.ul_mcs)):
+ raise ValueError('When the scheduling mode is set to manual, '
+ 'the RB and MCS parameters are required.')
+
+ # If scheduling mode is set to Dynamic, the RB and MCS parameters
+ # will be ignored by set_scheduling_mode.
+ self.set_scheduling_mode(bts_index, config.scheduling_mode,
+ config.dl_mcs, config.ul_mcs,
+ config.dl_rbs, config.ul_rbs)
+
+ # This variable stores a boolean value so the following is needed to
+ # differentiate False from None
+ if config.dl_cc_enabled is not None:
+ self.set_enabled_for_ca(bts_index, config.dl_cc_enabled)
+
+ if config.dl_modulation_order:
+ self.set_dl_modulation(bts_index, config.dl_modulation_order)
+
+ if config.ul_modulation_order:
+ self.set_ul_modulation(bts_index, config.ul_modulation_order)
+
+ # This variable stores a boolean value so the following is needed to
+ # differentiate False from None
+ if config.tbs_pattern_on is not None:
+ self.set_tbs_pattern_on(bts_index, config.tbs_pattern_on)
+
+ def set_band(self, bts_index, band):
+ """ Sets the band for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ band: the new band
+ """
+ raise NotImplementedError()
+
+ def set_input_power(self, bts_index, input_power):
+ """ Sets the input power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ input_power: the new input power
+ """
+ raise NotImplementedError()
+
+ def set_output_power(self, bts_index, output_power):
+ """ Sets the output power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ output_power: the new output power
+ """
+ raise NotImplementedError()
+
+ def set_tdd_config(self, bts_index, tdd_config):
+ """ Sets the tdd configuration number for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ tdd_config: the new tdd configuration number
+ """
+ raise NotImplementedError()
+
+ def set_bandwidth(self, bts_index, bandwidth):
+ """ Sets the bandwidth for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ bandwidth: the new bandwidth
+ """
+ raise NotImplementedError()
+
+ def set_downlink_channel_number(self, bts_index, channel_number):
+ """ Sets the downlink channel number for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ channel_number: the new channel number
+ """
+ raise NotImplementedError()
+
+ def set_mimo_mode(self, bts_index, mimo_mode):
+ """ Sets the mimo mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ mimo_mode: the new mimo mode
+ """
+ raise NotImplementedError()
+
+ def set_transmission_mode(self, bts_index, transmission_mode):
+ """ Sets the transmission mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ transmission_mode: the new transmission mode
+ """
+ raise NotImplementedError()
+
+ def set_scheduling_mode(self, bts_index, scheduling_mode, mcs_dl, mcs_ul,
+ nrb_dl, nrb_ul):
+ """ Sets the scheduling mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ scheduling_mode: the new scheduling mode
+ mcs_dl: Downlink MCS (only for STATIC scheduling)
+ mcs_ul: Uplink MCS (only for STATIC scheduling)
+ nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
+ nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
+ """
+ raise NotImplementedError()
+
+ def set_enabled_for_ca(self, bts_index, enabled):
+ """ Enables or disables the base station during carrier aggregation.
+
+ Args:
+ bts_index: the base station number
+ enabled: whether the base station should be enabled for ca.
+ """
+ raise NotImplementedError()
+
+ def set_dl_modulation(self, bts_index, modulation):
+ """ Sets the DL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new DL modulation
+ """
+ raise NotImplementedError()
+
+ def set_ul_modulation(self, bts_index, modulation):
+ """ Sets the UL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new UL modulation
+ """
+ raise NotImplementedError()
+
+ def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
+ """ Enables or disables TBS pattern in the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ tbs_pattern_on: the new TBS pattern setting
+ """
+ raise NotImplementedError()
+
+ def lte_attach_secondary_carriers(self):
+ """ Activates the secondary carriers for CA. Requires the DUT to be
+ attached to the primary carrier first. """
+ raise NotImplementedError()
+
+ def wait_until_attached(self, timeout=120):
+ """ Waits until the DUT is attached to the primary carrier.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def wait_until_communication_state(self, timeout=120):
+ """ Waits until the DUT is in Communication state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def wait_until_idle_state(self, timeout=120):
+ """ Waits until the DUT is in Idle state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def detach(self):
+ """ Turns off all the base stations so the DUT loose connection."""
+ raise NotImplementedError()
+
+ def stop(self):
+ """ Stops current simulation. After calling this method, the simulator
+ will need to be set up again. """
+ raise NotImplementedError()
+
+ def start_data_traffic(self):
+ """ Starts transmitting data from the instrument to the DUT. """
+ raise NotImplementedError()
+
+ def stop_data_traffic(self):
+ """ Stops transmitting data from the instrument to the DUT. """
+ raise NotImplementedError()
+
class CellularSimulatorError(Exception):
""" Exceptions thrown when the cellular equipment is unreachable or it
diff --git a/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/packet.py b/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/packet.py
index f62975d..2233370 100644
--- a/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/packet.py
+++ b/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/packet.py
@@ -53,8 +53,8 @@
1 │ 2 │ uint16 │ Main │ Fine │ Calibration/Measurement value
2 │ 4 │ uint16 │ USB │ Coarse │ Calibration/Measurement value
3 │ 6 │ uint16 │ USB │ Fine │ Calibration/Measurement value
- 4 │ 8 │ int16 │ Aux │ Coarse │ Calibration/Measurement value
- 5 │ 10 │ int16 │ Aux │ Fine │ Calibration/Measurement value
+ 4 │ 8 │ uint16 │ Aux │ Coarse │ Calibration/Measurement value
+ 5 │ 10 │ uint16 │ Aux │ Fine │ Calibration/Measurement value
6 │ 12 │ uint16 │ Main │ Voltage │ Main V measurement, or Aux V
│ │ │ │ │ if setVoltageChannel == 1
7 │ 14 │ uint16 │ USB │ Voltage │ USB Voltage
@@ -76,7 +76,7 @@
SIZE = 18
def __init__(self, raw_data, sample_time):
- self.values = struct.unpack('>4H2h2H2B', raw_data)
+ self.values = struct.unpack('>8H2B', raw_data)
self._sample_time = sample_time
def __getitem__(self, channel_and_reading_granularity):
diff --git a/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/transformers.py b/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/transformers.py
index e91a89b..5ddc23c 100644
--- a/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/transformers.py
+++ b/acts/framework/acts/controllers/monsoon_lib/sampling/hvpm/transformers.py
@@ -438,10 +438,10 @@
zero_offset += cal_zero
if cal_ref - zero_offset != 0:
slope = scale / (cal_ref - zero_offset)
- if granularity == Granularity.FINE:
- slope /= 1000
else:
slope = 0
+ if granularity == Granularity.FINE:
+ slope /= 1000
index = HvpmMeasurement.get_index(channel, granularity)
calibrated_value[:, granularity] = slope * (
@@ -452,7 +452,7 @@
readings[:, channel] = np.where(
measurements[:, fine_data_position] < self.fine_threshold,
calibrated_value[:, Granularity.FINE],
- calibrated_value[:, Granularity.COARSE])
+ calibrated_value[:, Granularity.COARSE]) / 1000.0 # to mA
main_voltage_index = HvpmMeasurement.get_index(Channel.MAIN,
Reading.VOLTAGE)
diff --git a/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/packet.py b/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/packet.py
index 80c8274..b0f8839 100644
--- a/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/packet.py
+++ b/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/packet.py
@@ -54,9 +54,9 @@
Val │ Byte │ Type │ Monsoon │ Reading │
Pos │ Offset │ Format │ Channel │ Type │ Description
────┼────────┼────────┼─────────┼─────────┼──────────────────────────────
- 0 │ 0 │ uint16 │ Main │ Current │ Calibration value.
- 1 │ 2 │ uint16 │ USB │ Current │ Calibration value.
- 2 │ 4 │ uint16 │ Aux │ Current │ Calibration value.
+ 0 │ 0 │ int16 │ Main │ Current │ Calibration value.
+ 1 │ 2 │ int16 │ USB │ Current │ Calibration value.
+ 2 │ 4 │ int16 │ Aux │ Current │ Calibration value.
3 │ 6 │ uint16 │ Main │ Voltage │ Calibration value.
If the measurement is a power reading:
@@ -64,11 +64,11 @@
Val │ Byte │ Type │ Monsoon │ Reading │
Pos │ Offset │ Format │ Channel │ Type │ Description
────┼────────┼────────┼─────────┼─────────┼──────────────────────────────
- 0 │ 0 │ uint16 │ Main │ Current │ b0: if 1, Coarse, else Fine
+ 0 │ 0 │ int16 │ Main │ Current │ b0: if 1, Coarse, else Fine
│ │ │ │ │ b1-7: Measurement value.
- 1 │ 2 │ uint16 │ USB │ Current │ b0: if 1, Coarse, else Fine
+ 1 │ 2 │ int16 │ USB │ Current │ b0: if 1, Coarse, else Fine
│ │ │ │ │ b1-7: Measurement value.
- 2 │ 4 │ uint16 │ Aux │ Current │ b0: if 1, Coarse, else Fine
+ 2 │ 4 │ int16 │ Aux │ Current │ b0: if 1, Coarse, else Fine
│ │ │ │ │ b1-7: Measurement value.
3 │ 6 │ uint16 │ Main │ Voltage │ Measurement value.
@@ -86,7 +86,7 @@
sample_type: The type of sample that was recorded.
entry_index: The index of the measurement within the packet.
"""
- self.values = struct.unpack('>4H', raw_data)
+ self.values = struct.unpack('>3hH', raw_data)
self._sample_time = sample_time
self._sample_type = sample_type
diff --git a/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/stock_transformers.py b/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/stock_transformers.py
index eaf60b0..becc4ee 100644
--- a/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/stock_transformers.py
+++ b/acts/framework/acts/controllers/monsoon_lib/sampling/lvpm_stock/stock_transformers.py
@@ -340,32 +340,6 @@
return False
return True
- @staticmethod
- def _get_currents(sample, calibration_data):
- """Returns the list of current values for each channel.
-
- Args:
- sample: The Sample object to determine the current values of.
- calibration_data: The CalibrationCollection used to calibrate the
- sample.
-
- Returns:
-
- """
- currents = [0] * 3
- for channel in Channel.values:
- current = sample[channel]
- granularity = Granularity.FINE
- if current & 1:
- current &= ~1
- granularity = Granularity.COARSE
-
- zero = calibration_data.get(channel, Origin.ZERO, granularity)
- scale = calibration_data.get(channel, Origin.SCALE, granularity)
- currents[channel] = (current - zero) * scale
-
- return currents
-
def _transform_buffer(self, buffer):
calibration_data = buffer.calibration_data
@@ -393,7 +367,7 @@
# Monsoon.py algorithm.
readings[:, channel] = np.where(
measurements[:, channel] & 1,
- (measurements[:, channel] - 1 - coarse_zero) * coarse_scale,
+ ((measurements[:, channel] & ~1) - coarse_zero) * coarse_scale,
(measurements[:, channel] - fine_zero) * fine_scale)
for i in range(len(buffer.samples)):
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py
new file mode 100644
index 0000000..6c76e62
--- /dev/null
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py
@@ -0,0 +1,230 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+from acts.controllers.rohdeschwarz_lib import cmw500
+from acts.controllers import cellular_simulator as cc
+
+
+class CMW500CellularSimulator:
+ """ A cellular simulator for telephony simulations based on the CMW 500
+ controller. """
+
+ # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
+ LTE_SUPPORTS_DL_256QAM = None
+
+ # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
+ LTE_SUPPORTS_UL_64QAM = None
+
+ # Indicates if 4x4 MIMO is supported for LTE
+ LTE_SUPPORTS_4X4_MIMO = None
+
+ # The maximum number of carriers that this simulator can support for LTE
+ LTE_MAX_CARRIERS = None
+
+ def __init__(self, ip_address, port):
+ """ Initializes the cellular simulator.
+
+ Args:
+ ip_address: the ip address of the CMW500
+ port: the port number for the CMW500 controller
+ """
+ try:
+ self.cmw = cmw500.Cmw500(ip_address, port)
+ except cmw500.CmwError:
+ raise cc.CellularSimulatorError('Could not connect to CMW500.')
+
+ def destroy(self):
+ """ Sends finalization commands to the cellular equipment and closes
+ the connection. """
+ raise NotImplementedError()
+
+ def setup_lte_scenario(self):
+ """ Configures the equipment for an LTE simulation. """
+ raise NotImplementedError()
+
+ def setup_lte_ca_scenario(self):
+ """ Configures the equipment for an LTE with CA simulation. """
+ raise NotImplementedError()
+
+ def set_band(self, bts_index, band):
+ """ Sets the band for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ band: the new band
+ """
+ raise NotImplementedError()
+
+ def set_input_power(self, bts_index, input_power):
+ """ Sets the input power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ input_power: the new input power
+ """
+ raise NotImplementedError()
+
+ def set_output_power(self, bts_index, output_power):
+ """ Sets the output power for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ output_power: the new output power
+ """
+ raise NotImplementedError()
+
+ def set_tdd_config(self, bts_index, tdd_config):
+ """ Sets the tdd configuration number for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ tdd_config: the new tdd configuration number
+ """
+ raise NotImplementedError()
+
+ def set_bandwidth(self, bts_index, bandwidth):
+ """ Sets the bandwidth for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ bandwidth: the new bandwidth
+ """
+ raise NotImplementedError()
+
+ def set_downlink_channel_number(self, bts_index, channel_number):
+ """ Sets the downlink channel number for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ channel_number: the new channel number
+ """
+ raise NotImplementedError()
+
+ def set_mimo_mode(self, bts_index, mimo_mode):
+ """ Sets the mimo mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ mimo_mode: the new mimo mode
+ """
+ raise NotImplementedError()
+
+ def set_transmission_mode(self, bts_index, transmission_mode):
+ """ Sets the transmission mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ transmission_mode: the new transmission mode
+ """
+ raise NotImplementedError()
+
+ def set_scheduling_mode(self, bts_index, scheduling_mode, mcs_dl, mcs_ul,
+ nrb_dl, nrb_ul):
+ """ Sets the scheduling mode for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ scheduling_mode: the new scheduling mode
+ mcs_dl: Downlink MCS (only for STATIC scheduling)
+ mcs_ul: Uplink MCS (only for STATIC scheduling)
+ nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
+ nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
+ """
+ raise NotImplementedError()
+
+ def set_enabled_for_ca(self, bts_index, enabled):
+ """ Enables or disables the base station during carrier aggregation.
+
+ Args:
+ bts_index: the base station number
+ enabled: whether the base station should be enabled for ca.
+ """
+ raise NotImplementedError()
+
+ def set_dl_modulation(self, bts_index, modulation):
+ """ Sets the DL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new DL modulation
+ """
+ raise NotImplementedError()
+
+ def set_ul_modulation(self, bts_index, modulation):
+ """ Sets the UL modulation for the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ modulation: the new UL modulation
+ """
+ raise NotImplementedError()
+
+ def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
+ """ Enables or disables TBS pattern in the indicated base station.
+
+ Args:
+ bts_index: the base station number
+ tbs_pattern_on: the new TBS pattern setting
+ """
+ raise NotImplementedError()
+
+ def lte_attach_secondary_carriers(self):
+ """ Activates the secondary carriers for CA. Requires the DUT to be
+ attached to the primary carrier first. """
+ raise NotImplementedError()
+
+ def wait_until_attached(self, timeout=120):
+ """ Waits until the DUT is attached to the primary carrier.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def wait_until_communication_state(self, timeout=120):
+ """ Waits until the DUT is in Communication state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def wait_until_idle_state(self, timeout=120):
+ """ Waits until the DUT is in Idle state.
+
+ Args:
+ timeout: after this amount of time the method will raise a
+ CellularSimulatorError exception. Default is 120 seconds.
+ """
+ raise NotImplementedError()
+
+ def detach(self):
+ """ Turns off all the base stations so the DUT loose connection."""
+ raise NotImplementedError()
+
+ def stop(self):
+ """ Stops current simulation. After calling this method, the simulator
+ will need to be set up again. """
+ raise NotImplementedError()
+
+ def start_data_traffic(self):
+ """ Starts transmitting data from the instrument to the DUT. """
+ raise NotImplementedError()
+
+ def stop_data_traffic(self):
+ """ Stops transmitting data from the instrument to the DUT. """
+ raise NotImplementedError()
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py b/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
index 7d6c790..f34a62b 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
@@ -47,7 +47,7 @@
MAXIMUM_OUTPUT_READ_RETRIES = 25
# Root directory for the FTP server in the remote computer
- FTP_ROOT = 'D:\\Contest\\Reports\\reports\\'
+ FTP_ROOT = 'D:\\Logs\\'
def __init__(self, logger, remote_ip, remote_port, automation_listen_ip,
automation_port, dut_on_func, dut_off_func, ftp_usr, ftp_pwd):
@@ -212,6 +212,9 @@
a JSON object containing the test results
"""
+ if not testplan_directory:
+ raise ValueError('Invalid testplan directory.')
+
# Download test reports from the remote host
job.run('wget -r --user={} --password={} -P {} ftp://{}/{}'.format(
self.ftp_user, self.ftp_pass, logging.log_path,
@@ -387,14 +390,17 @@
"DUT to off state.")
self.dut_off_func()
self.send_ok()
+ elif command.startswith(self.NOTIFICATION_TESTPLAN_START):
+ self.log.info('Test plan is starting.')
+ self.send_ok()
elif command.startswith(self.NOTIFICATION_TESTCASE_START):
self.log.info('Test case is starting.')
self.send_ok()
- elif command in [
- self.NOTIFICATION_TESTPLAN_START,
- self.NOTIFICATION_TESCASE_END,
- self.NOTIFICATION_TESTPLAN_END
- ]:
+ elif command.startswith(self.NOTIFICATION_TESCASE_END):
+ self.log.info('Test case finished.')
+ self.send_ok()
+ elif command.startswith(self.NOTIFICATION_TESTPLAN_END):
+ self.log.info('Test plan finished.')
self.send_ok()
else:
self.log.error('Unhandled automation command: ' + command)
diff --git a/acts/framework/acts/metrics/loggers/blackbox.py b/acts/framework/acts/metrics/loggers/blackbox.py
index 0e33164..8d7aeca 100644
--- a/acts/framework/acts/metrics/loggers/blackbox.py
+++ b/acts/framework/acts/metrics/loggers/blackbox.py
@@ -14,12 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import shutil
+
from acts.metrics.core import ProtoMetric
from acts.metrics.logger import MetricLogger
-class BlackboxMetricLogger(MetricLogger):
- """A MetricLogger for logging and publishing Blackbox metrics.
+class BlackboxMappedMetricLogger(MetricLogger):
+ """A MetricLogger for logging and publishing Blackbox metrics from a dict.
+ The dict maps the metric name to the metric value.
The logger will publish an ActsBlackboxMetricResult message, containing
data intended to be uploaded to Blackbox. The message itself contains only
@@ -32,47 +35,68 @@
Attributes:
proto_module: The proto module for ActsBlackboxMetricResult.
- metric_name: The name of the metric, used to determine output filename.
metric_key: The metric key to use. If unset, the logger will use the
context's identifier.
- metric_value: The metric value.
+ _metric_map: the map of metric_name -> metric_value to publish
+ to blackbox. If the metric value is set to None, the
+ metric will not be reported.
"""
PROTO_FILE = 'protos/acts_blackbox.proto'
- def __init__(self, metric_name, metric_key=None, event=None):
+ def __init__(self, metric_key=None, event=None, compiler_out=None):
"""Initializes a logger for Blackbox metrics.
Args:
- metric_name: The name of the metric.
metric_key: The metric key to use. If unset, the logger will use
the context's identifier.
event: The event triggering the creation of this logger.
+ compiler_out: The directory to store the compiled proto module.
"""
super().__init__(event=event)
- self.proto_module = self._compile_proto(self.PROTO_FILE)
- if not metric_name:
- raise ValueError("metric_name must be supplied.")
- self.metric_name = metric_name
+ self.proto_module = self._compile_proto(self.PROTO_FILE,
+ compiler_out=compiler_out)
self.metric_key = metric_key
- self.metric_value = None
+ self._metric_map = {}
- def _get_metric_key(self):
+ def _get_metric_key(self, metric_name):
"""Gets the metric key to use.
If the metric_key is explicitly set, returns that value. Otherwise,
extracts an identifier from the context.
+
+ Args:
+ metric_name: The name of the metric to report.
"""
if self.metric_key:
key = self.metric_key
else:
key = self._get_blackbox_identifier()
- key = '%s.%s' % (key, self.metric_name)
+ key = '%s.%s' % (key, metric_name)
return key
- def _get_file_name(self):
- """Gets the base file name to publish to."""
- return 'blackbox_%s' % self.metric_name
+ def set_metric_data(self, metric_map):
+ """Sets the map of metrics to be uploaded to Blackbox. Note that
+ this will overwrite all existing added by this function or add_metric.
+
+ Args:
+ metric_map: the map of metric_name -> metric_value to publish
+ to blackbox. If the metric value is set to None, the
+ metric will not be reported.
+ """
+ self._metric_map = metric_map
+
+ def add_metric(self, metric_name, metric_value):
+ """Adds a metric value to be published later.
+
+ Note that if the metric name has already been added, the metric value
+ will be overwritten.
+
+ Args:
+ metric_name: the name of the metric.
+ metric_value: the value of the metric.
+ """
+ self._metric_map[metric_name] = metric_value
def _get_blackbox_identifier(self):
"""Returns the testcase identifier, as expected by Blackbox."""
@@ -82,20 +106,63 @@
parts = identifier.rsplit('.', 1)
return '#'.join(parts)
- def end(self, event):
+ def end(self, _):
"""Creates and publishes a ProtoMetric with blackbox data.
- Builds an ActsBlackboxMetricResult message based on the result
- generated, and passes it off to the publisher.
+ Builds a list of ActsBlackboxMetricResult messages from the set
+ metric data, and sends them to the publisher.
+ """
+ metrics = []
+ for metric_name, metric_value in self._metric_map.items():
+ if metric_value is None:
+ continue
+ result = self.proto_module.ActsBlackboxMetricResult()
+ result.test_identifier = self._get_blackbox_identifier()
+ result.metric_key = self._get_metric_key(metric_name)
+ result.metric_value = metric_value
+
+ metrics.append(
+ ProtoMetric(name='blackbox_%s' % metric_name, data=result))
+
+ return self.publisher.publish(metrics)
+
+
+class BlackboxMetricLogger(BlackboxMappedMetricLogger):
+ """A MetricLogger for logging and publishing individual Blackbox metrics.
+
+ For additional information on reporting to Blackbox, see
+ BlackboxMappedMetricLogger.
+
+ Attributes:
+ proto_module: The proto module for ActsBlackboxMetricResult.
+ metric_name: The name of the metric, used to determine output filename.
+ metric_key: The metric key to use. If unset, the logger will use the
+ context's identifier.
+ metric_value: The metric value.
+ """
+
+ def __init__(self, metric_name, metric_key=None, event=None,
+ compiler_out=None):
+ """Initializes a logger for Blackbox metrics.
Args:
- event: The triggering event.
+ metric_name: The name of the metric.
+ metric_key: The metric key to use. If unset, the logger will use
+ the context's identifier.
+ event: The event triggering the creation of this logger.
+ compiler_out: The directory to store the compiled proto module
"""
- result = self.proto_module.ActsBlackboxMetricResult()
- result.test_identifier = self._get_blackbox_identifier()
- result.metric_key = self._get_metric_key()
- if self.metric_value is not None:
- result.metric_value = self.metric_value
+ super().__init__(metric_key=metric_key, event=event,
+ compiler_out=compiler_out)
+ if not metric_name:
+ raise ValueError("metric_name must be supplied.")
+ self.metric_name = metric_name
+ self.metric_value = None
- metric = ProtoMetric(name=self._get_file_name(), data=result)
- return self.publisher.publish(metric)
+ @property
+ def metric_value(self):
+ return self._metric_map[self.metric_name]
+
+ @metric_value.setter
+ def metric_value(self, value):
+ self.add_metric(self.metric_name, value)
diff --git a/acts/framework/acts/test_utils/bt/BluetoothBaseTest.py b/acts/framework/acts/test_utils/bt/BluetoothBaseTest.py
index ec34b04..d6bcd05 100644
--- a/acts/framework/acts/test_utils/bt/BluetoothBaseTest.py
+++ b/acts/framework/acts/test_utils/bt/BluetoothBaseTest.py
@@ -49,18 +49,6 @@
start_time = 0
timer_list = []
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
- for ad in self.android_devices:
- self._setup_bt_libs(ad)
- if 'preferred_device_order' in self.user_params:
- prefered_device_order = self.user_params['preferred_device_order']
- for i, ad in enumerate(self.android_devices):
- if ad.serial in prefered_device_order:
- index = prefered_device_order.index(ad.serial)
- self.android_devices[i], self.android_devices[index] = \
- self.android_devices[index], self.android_devices[i]
-
def collect_bluetooth_manager_metrics_logs(self, ads, test_name):
"""
Collect Bluetooth metrics logs, save an ascii log to disk and return
@@ -131,6 +119,17 @@
return _safe_wrap_test_case
def setup_class(self):
+ super().setup_class()
+ for ad in self.android_devices:
+ self._setup_bt_libs(ad)
+ if 'preferred_device_order' in self.user_params:
+ prefered_device_order = self.user_params['preferred_device_order']
+ for i, ad in enumerate(self.android_devices):
+ if ad.serial in prefered_device_order:
+ index = prefered_device_order.index(ad.serial)
+ self.android_devices[i], self.android_devices[index] = \
+ self.android_devices[index], self.android_devices[i]
+
if "reboot_between_test_class" in self.user_params:
threads = []
for a in self.android_devices:
diff --git a/acts/framework/acts/test_utils/bt/pts/pts_base_class.py b/acts/framework/acts/test_utils/bt/pts/pts_base_class.py
index 32f8b1b..33fa81b 100644
--- a/acts/framework/acts/test_utils/bt/pts/pts_base_class.py
+++ b/acts/framework/acts/test_utils/bt/pts/pts_base_class.py
@@ -46,8 +46,8 @@
scan_timeout_seconds = 10
peer_identifier = None
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
if 'dut' in self.user_params:
if self.user_params['dut'] == 'fuchsia_devices':
self.dut = create_bluetooth_device(self.fuchsia_devices[0])
@@ -122,7 +122,6 @@
}
}
- def setup_class(self):
self.pts.setup_pts()
self.pts.bind_to(self.process_next_action)
diff --git a/acts/framework/acts/test_utils/coex/audio_capture.py b/acts/framework/acts/test_utils/coex/audio_capture.py
index 7e011f1..bb29dcc 100644
--- a/acts/framework/acts/test_utils/coex/audio_capture.py
+++ b/acts/framework/acts/test_utils/coex/audio_capture.py
@@ -27,6 +27,9 @@
class DeviceNotFound(Exception):
"""Raises exception if audio capture device is not found."""
+# TODO: (@sairamganesh) This class will be deprecated for
+# ../acts/test_utils/coex/audio_capture_device.py
+
class AudioCapture:
diff --git a/acts/framework/acts/test_utils/coex/audio_capture_device.py b/acts/framework/acts/test_utils/coex/audio_capture_device.py
new file mode 100644
index 0000000..7f32030
--- /dev/null
+++ b/acts/framework/acts/test_utils/coex/audio_capture_device.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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 logging
+import os
+import pyaudio
+import wave
+
+from acts import context
+from acts import utils
+
+
+WAVE_FILE_TEMPLATE = 'recorded_audio_%s.wav'
+ADB_PATH = 'sdcard/Music/'
+ADB_FILE = 'rec.pcm'
+
+
+class AudioCaptureBase(object):
+ """Base class for Audio capture."""
+
+ def __init__(self):
+
+ self.wave_file = os.path.join(self.log_path, WAVE_FILE_TEMPLATE)
+ self.file_dir = self.log_path
+
+ @property
+ def log_path(self):
+ """Returns current log path."""
+ current_context = context.get_current_context()
+ full_out_dir = os.path.join(current_context.get_full_output_path(),
+ 'AudioCapture')
+
+ utils.create_dir(full_out_dir)
+ return full_out_dir
+
+ @property
+ def next_fileno(self):
+ counter = 0
+ while os.path.exists(self.wave_file % counter):
+ counter += 1
+ return counter
+
+ @property
+ def last_fileno(self):
+ return self.next_fileno - 1
+
+ def write_record_file(self, audio_params, frames):
+ """Writes the recorded audio into the file.
+
+ Args:
+ audio_params: A dict with audio configuration.
+ frames: Recorded audio frames.
+
+ Returns:
+ file_name: wave file name.
+ """
+ file_name = self.wave_file % self.next_fileno
+ logging.debug('writing to %s' % file_name)
+ wf = wave.open(file_name, 'wb')
+ wf.setnchannels(audio_params['channel'])
+ wf.setsampwidth(audio_params['sample_width'])
+ wf.setframerate(audio_params['sample_rate'])
+ wf.writeframes(frames)
+ wf.close()
+ return file_name
+
+
+class CaptureAudioOverAdb(AudioCaptureBase):
+ """Class to capture audio over android device which acts as the
+ a2dp sink or hfp client. This captures the digital audio and converts
+ to analog audio for post processing.
+ """
+
+ def __init__(self, ad, audio_params):
+ """Initializes CaptureAudioOverAdb.
+
+ Args:
+ ad: An android device object.
+ audio_params: Dict containing audio record settings.
+ """
+ super().__init__()
+ self._ad = ad
+ self.audio_params = audio_params
+ self.adb_path = None
+
+ def start(self):
+ """Start the audio capture over adb."""
+ self.adb_path = os.path.join(ADB_PATH, ADB_FILE)
+ cmd = 'ap2f --usage 1 --start --duration {} --target {}'.format(
+ self.audio_params['duration'], self.adb_path,
+ )
+ self._ad.adb.shell(cmd)
+
+ def stop(self):
+ """Stops the audio capture and stores it in wave file.
+
+ Returns:
+ File name of the recorded file.
+ """
+ cmd = '{} {}'.format(self.adb_path, self.file_dir)
+ self._ad.adb.pull(cmd)
+ self._ad.adb.shell('rm {}'.format(self.adb_path))
+ return self._convert_pcm_to_wav()
+
+ def _convert_pcm_to_wav(self):
+ """Converts raw pcm data into wave file.
+
+ Returns:
+ file_path: Returns the file path of the converted file
+ (digital to analog).
+ """
+ file_to_read = os.path.join(self.file_dir, ADB_FILE)
+ with open(file_to_read, 'rb') as pcm_file:
+ frames = pcm_file.read()
+ file_path = self.write_record_file(self.audio_params, frames)
+ return file_path
+
+
+class CaptureAudioOverLocal(AudioCaptureBase):
+ """Class to capture audio on local server using the audio input devices
+ such as iMic/AudioBox. This class mandates input deivce to be connected to
+ the machine.
+ """
+ def __init__(self, audio_params):
+ """Initializes CaptureAudioOverLocal.
+
+ Args:
+ audio_params: Dict containing audio record settings.
+ """
+ super().__init__()
+ self.audio_params = audio_params
+ self.channels = self.audio_params['channel']
+ self.chunk = self.audio_params['chunk']
+ self.sample_rate = self.audio_params['sample_rate']
+ self.__input_device = None
+ self.audio = None
+ self.frames = []
+
+ @property
+ def name(self):
+ return self.__input_device["name"]
+
+ def __get_input_device(self):
+ """Checks for the audio capture device."""
+ if self.__input_device is None:
+ for i in range(self.audio.get_device_count()):
+ device_info = self.audio.get_device_info_by_index(i)
+ logging.debug('Device Information: {}'.format(device_info))
+ if self.audio_params['input_device'] in device_info['name']:
+ self.__input_device = device_info
+ break
+ else:
+ raise DeviceNotFound(
+ 'Audio Capture device {} not found.'.format(
+ self.audio_params['input_device']))
+ return self.__input_device
+
+ def start(self, trim_beginning=0, trim_end=0):
+ """Starts audio recording on host machine.
+
+ Args:
+ trim_beginning: how many seconds to trim from the beginning
+ trim_end: how many seconds to trim from the end
+ """
+ self.audio = pyaudio.PyAudio()
+ self.__input_device = self.__get_input_device()
+ stream = self.audio.open(
+ format=pyaudio.paInt16,
+ channels=self.channels,
+ rate=self.sample_rate,
+ input=True,
+ frames_per_buffer=self.chunk,
+ input_device_index=self.__input_device['index'])
+ b_chunks = trim_beginning * (self.sample_rate // self.chunk)
+ e_chunks = trim_end * (self.sample_rate // self.chunk)
+ total_chunks = self.sample_rate // self.chunk * self.audio_params[
+ 'duration']
+ for i in range(total_chunks):
+ try:
+ data = stream.read(self.chunk, exception_on_overflow=False)
+ except IOError as ex:
+ logging.error('Cannot record audio: {}'.format(ex))
+ return False
+ if b_chunks <= i < total_chunks - e_chunks:
+ self.frames.append(data)
+
+ stream.stop_stream()
+ stream.close()
+
+ def stop(self):
+ """Terminates the pulse audio instance.
+
+ Returns:
+ File name of the recorded audio file.
+ """
+ self.audio.terminate()
+ frames = b''.join(self.frames)
+ return self.write_record_file(self.audio_params, frames)
+
+
+class DeviceNotFound(Exception):
+ """Raises exception if audio capture device is not found."""
diff --git a/acts/framework/acts/test_utils/coex/audio_test_utils.py b/acts/framework/acts/test_utils/coex/audio_test_utils.py
index efee428..0fca41a 100644
--- a/acts/framework/acts/test_utils/coex/audio_test_utils.py
+++ b/acts/framework/acts/test_utils/coex/audio_test_utils.py
@@ -18,6 +18,8 @@
import os
import wave
+from acts.test_utils.coex.audio_capture_device import CaptureAudioOverAdb
+from acts.test_utils.coex.audio_capture_device import CaptureAudioOverLocal
from acts.controllers.utils_lib.ssh import connection
from acts.controllers.utils_lib.ssh import settings
from acts.test_utils.audio_analysis_lib import audio_analysis
@@ -32,9 +34,47 @@
bits_per_sample = 32
+def get_audio_capture_device(test_class_instance):
+ """Gets the device object of the audio capture device connected to server.
+
+ The audio capture device returned is specified by the audio_params
+ within user_params. audio_params must specify a "type" field, that
+ is either "AndroidDevice" or "Local"
+
+ Args:
+ test_class_instance: object self of test class.
+
+ Returns:
+ Object of the audio capture device.
+
+ Raises:
+ ValueError if audio_params['type'] is not "AndroidDevice" or
+ "Local".
+ ValueError if "AndroidDevice" is specified, but there is only one
+ AndroidDevice within the testbed.
+ """
+ audio_params = test_class_instance.user_params.get('audio_params')
+
+ if audio_params['type'] == 'AndroidDevice':
+ if len(test_class_instance.android_devices) > 1:
+ return CaptureAudioOverAdb(
+ test_class_instance.android_devices[-1], audio_params)
+ else:
+ raise ValueError('At least 2 or more AndroidDevice should be '
+ 'specified to use as audio capture endpoint.')
+ elif audio_params['type'] == 'Local':
+ return CaptureAudioOverLocal(audio_params)
+ else:
+ raise ValueError('Unrecognized audio capture device '
+ '%s' % audio_params['type'])
+
+
class FileNotFound(Exception):
"""Raises Exception if file is not present"""
+# TODO @sairamganesh Rename this class to AudioCaptureResult and
+# remove duplicates which are in ../test_utils/coex/audio_capture_device.py.
+
class SshAudioCapture(AudioCapture):
diff --git a/acts/framework/acts/test_utils/gnss/gnss_test_utils.py b/acts/framework/acts/test_utils/gnss/gnss_test_utils.py
index 16285c2..2b4e6f3 100644
--- a/acts/framework/acts/test_utils/gnss/gnss_test_utils.py
+++ b/acts/framework/acts/test_utils/gnss/gnss_test_utils.py
@@ -42,6 +42,15 @@
"TTFF_REPORT", "ttff_loop ttff_sec ttff_pe ttff_cn")
TRACK_REPORT = collections.namedtuple(
"TRACK_REPORT", "track_l5flag track_pe track_top4cn track_cn")
+LOCAL_PROP_FILE_CONTENTS = """\
+log.tag.LocationManagerService=VERBOSE
+log.tag.GnssLocationProvider=VERBOSE
+log.tag.GnssMeasurementsProvider=VERBOSE
+log.tag.GpsNetInitiatedHandler=VERBOSE
+log.tag.GnssNetworkConnectivityHandler=VERBOSE
+log.tag.ConnectivityService=VERBOSE
+log.tag.ConnectivityManager=VERBOSE
+log.tag.GnssVisibilityControl=VERBOSE"""
class GnssTestUtilsError(Exception):
@@ -88,11 +97,7 @@
remount_device(ad)
ad.log.info("Enable GNSS VERBOSE Logging and persistent logcat.")
ad.adb.shell("echo DEBUG_LEVEL = 5 >> /vendor/etc/gps.conf")
- ad.adb.shell("echo log.tag.LocationManagerService=VERBOSE >> /data/local.prop")
- ad.adb.shell("echo log.tag.GnssLocationProvider=VERBOSE >> /data/local.prop")
- ad.adb.shell("echo log.tag.GnssMeasurementsProvider=VERBOSE >> /data/local.prop")
- ad.adb.shell("echo log.tag.GpsNetInitiatedHandler=VERBOSE >> /data/local.prop")
- ad.adb.shell("echo log.tag.GnssNetworkConnectivityHandler=VERBOSE >> /data/local.prop")
+ ad.adb.shell("echo %r >> /data/local.prop" % LOCAL_PROP_FILE_CONTENTS)
ad.adb.shell("chmod 644 /data/local.prop")
ad.adb.shell("setprop persist.logd.size 16777216")
ad.adb.shell("setprop persist.vendor.radio.adb_log_on 1")
@@ -284,7 +289,8 @@
shutil.make_archive(gnss_log_path, "zip", gnss_log_path)
shutil.rmtree(gnss_log_path)
output_path = os.path.join(DEFAULT_QXDM_LOG_PATH, "logs/.")
- file_count = ad.adb.shell("find %s -type f -iname *.qmdl | wc -l" % output_path)
+ file_count = ad.adb.shell(
+ "find %s -type f -iname *.qmdl | wc -l" % output_path)
if not int(file_count) == 0:
qxdm_log_name = "QXDM_%s_%s" % (ad.model, ad.serial)
qxdm_log_path = os.path.join(log_path, qxdm_log_name)
@@ -328,7 +334,8 @@
ad.log.error("Mobile data is at unknown state and set to %d" % out)
def gnss_trigger_modem_ssr(ad, dwelltime=60):
- """Trigger modem SSR crash and verify if modem crash and recover successfully.
+ """Trigger modem SSR crash and verify if modem crash and recover
+ successfully.
Args:
ad: An AndroidDevice object.
@@ -415,7 +422,6 @@
remount_device(ad)
pull_gtw_gpstool(ad)
ad.adb.shell("settings put global verifier_verify_adb_installs 0")
- ad.adb.shell("settings put global package_verifier_enable 0")
reinstall_gtw_gpstool(ad)
def fastboot_factory_reset(ad):
@@ -466,7 +472,6 @@
break
ad.log.info("Re-install sl4a")
ad.adb.shell("settings put global verifier_verify_adb_installs 0")
- ad.adb.shell("settings put global package_verifier_enable 0")
ad.adb.install("-r -g -t /tmp/base.apk")
reinstall_gtw_gpstool(ad)
time.sleep(10)
@@ -532,7 +537,8 @@
for i in range(retries):
begin_time = get_current_epoch_time()
clear_aiding_data_by_gtw_gpstool(ad)
- ad.log.info("Start %s on GTW_GPSTool - attempt %d" % (type.upper(), i+1))
+ ad.log.info("Start %s on GTW_GPSTool - attempt %d" % (type.upper(),
+ i+1))
start_gnss_by_gtw_gpstool(ad, True, type)
for _ in range(10 + criteria):
logcat_results = ad.search_logcat("First fixed", begin_time)
@@ -544,16 +550,16 @@
if (first_fixed/1000) <= criteria:
return True
start_gnss_by_gtw_gpstool(ad, False, type)
- raise signals.TestFailure("Fail to get %s location fixed within "
- "%d seconds criteria." %
- (type.upper(), criteria))
+ raise signals.TestFailure("Fail to get %s location fixed "
+ "within %d seconds criteria."
+ % (type.upper(), criteria))
time.sleep(1)
if not ad.is_adb_logcat_on:
ad.start_adb_logcat()
check_currrent_focus_app(ad)
start_gnss_by_gtw_gpstool(ad, False, type)
- raise signals.TestFailure("Fail to get %s location fixed within %d attempts."
- % (type.upper(), retries))
+ raise signals.TestFailure("Fail to get %s location fixed within %d "
+ "attempts." % (type.upper(), retries))
def start_ttff_by_gtw_gpstool(ad, ttff_mode, iteration):
"""Identify which TTFF mode for different test items.
@@ -578,9 +584,9 @@
begin_time):
ad.log.info("Send TTFF start_test_action successfully.")
break
- if i == 3:
- check_currrent_focus_app(ad)
- raise signals.TestFailure("Fail to send TTFF start_test_action.")
+ else:
+ check_currrent_focus_app(ad)
+ raise signals.TestFailure("Fail to send TTFF start_test_action.")
def gnss_tracking_via_gtw_gpstool(ad, criteria, type="gnss", testtime=60):
"""Start GNSS/FLP tracking tests for input testtime on GTW_GPSTool.
@@ -621,6 +627,7 @@
track_data = {}
history_top4_cn = 0
history_cn = 0
+ l5flag = "false"
file_count = int(ad.adb.shell("find %s -type f -iname *.txt | wc -l"
% GNSSSTATUS_LOG_PATH))
if file_count != 1:
@@ -777,7 +784,8 @@
elif any(float(ttff_data[key].ttff_sec) == 0.0 for key in ttff_data.keys()):
ad.log.error("One or more TTFF %s Timeout" % ttff_mode)
return False
- elif any(float(ttff_data[key].ttff_sec) >= criteria for key in ttff_data.keys()):
+ elif any(float(ttff_data[key].ttff_sec) >= criteria for key in
+ ttff_data.keys()):
ad.log.error("One or more TTFF %s are over test criteria %d seconds"
% (ttff_mode, criteria))
return False
@@ -862,7 +870,8 @@
ad: An AndroidDevice object.
"""
time.sleep(1)
- current = ad.adb.shell("dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'")
+ current = ad.adb.shell(
+ "dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'")
ad.log.debug("\n"+current)
def check_location_api(ad, retries):
@@ -884,7 +893,8 @@
logcat_results = ad.search_logcat("REPORT_LOCATION", begin_time)
if logcat_results:
ad.log.info("%s" % logcat_results[-1]["log_message"])
- ad.log.info("GnssLocationProvider reports location successfully.")
+ ad.log.info("GnssLocationProvider reports location "
+ "successfully.")
return True
if not ad.is_adb_logcat_on:
ad.start_adb_logcat()
@@ -907,10 +917,12 @@
time.sleep(1)
begin_time = get_current_epoch_time()
ad.log.info("Try to get NLP status - attempt %d" % (i+1))
- ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool --es mode nlp")
+ ad.adb.shell(
+ "am start -S -n com.android.gpstool/.GPSTool --es mode nlp")
while get_current_epoch_time() - begin_time <= 30000:
- logcat_results = ad.search_logcat(
- "LocationManagerService: incoming location: Location", begin_time)
+ logcat_results = ad.search_logcat("LocationManagerService: "
+ "incoming location: Location",
+ begin_time)
if logcat_results:
for logcat_result in logcat_results:
if location_type in logcat_result["log_message"]:
@@ -932,7 +944,8 @@
atten_value: attenuation value
"""
try:
- ad.log.info("Set attenuation value to \"%d\" for GNSS signal." % atten_value)
+ ad.log.info(
+ "Set attenuation value to \"%d\" for GNSS signal." % atten_value)
attenuator[0].set_atten(atten_value)
except Exception as e:
ad.log.error(e)
@@ -987,7 +1000,8 @@
ad.log.info("Open an youtube video - attempt %d" % (i+1))
ad.adb.shell("am start -a android.intent.action.VIEW -d \"%s\"" % url)
time.sleep(2)
- out = ad.adb.shell("dumpsys activity | grep NewVersionAvailableActivity")
+ out = ad.adb.shell(
+ "dumpsys activity | grep NewVersionAvailableActivity")
if out:
ad.log.info("Skip Youtube New Version Update.")
ad.send_keycode("BACK")
@@ -1008,12 +1022,72 @@
"""
try:
baseband_version = ad.adb.getprop("gsm.version.baseband")
- gms_version = ad.adb.shell("dumpsys package com.google.android.gms | "
- "grep versionName").split("\n")[0].split("=")[1]
+ gms_version = ad.adb.shell(
+ "dumpsys package com.google.android.gms | grep versionName"
+ ).split("\n")[0].split("=")[1]
+ mpss_version = ad.adb.shell("cat /sys/devices/soc0/images | grep MPSS "
+ "| cut -d ':' -f 3")
if not extra_msg:
ad.log.info("TestResult Baseband_Version %s" % baseband_version)
- ad.log.info("TestResult GMS_Version %s" % gms_version.replace(" ", ""))
+ ad.log.info(
+ "TestResult GMS_Version %s" % gms_version.replace(" ", ""))
+ ad.log.info("TestResult MPSS_Version %s" % mpss_version)
else:
- ad.log.info("%s, Baseband_Version = %s" % (extra_msg, baseband_version))
+ ad.log.info(
+ "%s, Baseband_Version = %s" % (extra_msg, baseband_version))
except Exception as e:
- ad.log.error(e)
\ No newline at end of file
+ ad.log.error(e)
+
+def start_toggle_gnss_by_gtw_gpstool(ad, iteration):
+ """Send toggle gnss off/on start_test_action
+
+ Args:
+ ad: An AndroidDevice object.
+ iteration: Iteration of toggle gnss off/on cycles.
+ """
+ msg_list = []
+ begin_time = get_current_epoch_time()
+ try:
+ for i in range(1, 4):
+ ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool "
+ "--es mode toggle --es cycle %d" % iteration)
+ time.sleep(1)
+ if ad.search_logcat("cmp=com.android.gpstool/.ToggleGPS",
+ begin_time):
+ ad.log.info("Send ToggleGPS start_test_action successfully.")
+ break
+ else:
+ check_currrent_focus_app(ad)
+ raise signals.TestFailure("Fail to send ToggleGPS "
+ "start_test_action within 3 attempts.")
+ time.sleep(2)
+ test_start = ad.search_logcat("GPSTool_ToggleGPS: startService",
+ begin_time)
+ if test_start:
+ ad.log.info(test_start[-1]["log_message"].split(":")[-1].strip())
+ else:
+ raise signals.TestFailure("Fail to start toggle GPS off/on test.")
+ # Every iteration is expected to finish within 4 minutes.
+ while get_current_epoch_time() - begin_time <= iteration * 240000:
+ crash_end = ad.search_logcat("Force finishing activity "
+ "com.android.gpstool/.GPSTool",
+ begin_time)
+ if crash_end:
+ raise signals.TestFailure("GPSTool crashed. Abort test.")
+ toggle_results = ad.search_logcat("GPSTool : msg", begin_time)
+ if toggle_results:
+ for toggle_result in toggle_results:
+ msg = toggle_result["log_message"]
+ if not msg in msg_list:
+ ad.log.info(msg.split(":")[-1].strip())
+ msg_list.append(msg)
+ if "timeout" in msg:
+ raise signals.TestFailure("Fail to get location fixed "
+ "within 60 seconds.")
+ if "Test end" in msg:
+ raise signals.TestPass("Completed quick toggle GNSS "
+ "off/on test.")
+ raise signals.TestFailure("Fail to finish toggle GPS off/on test "
+ "within %d minutes" % (iteration * 4))
+ finally:
+ ad.send_keycode("HOME")
diff --git a/acts/framework/acts/test_utils/instrumentation/adb_commands/common.py b/acts/framework/acts/test_utils/instrumentation/adb_commands/common.py
index 2991600..ffd43dd 100644
--- a/acts/framework/acts/test_utils/instrumentation/adb_commands/common.py
+++ b/acts/framework/acts/test_utils/instrumentation/adb_commands/common.py
@@ -62,6 +62,11 @@
nfc = DeviceState('svc nfc', 'enable', 'disable')
+# Calling
+
+disable_dialing = DeviceSetprop('ro.telephony.disable-call', 'true', 'false')
+
+
# Screen
screen_adaptive_brightness = DeviceSetting(
@@ -115,3 +120,12 @@
disable_doze = 'dumpsys deviceidle disable'
+
+# Miscellaneous
+
+test_harness = DeviceBinaryCommandSeries(
+ [
+ DeviceSetprop('ro.monkey'),
+ DeviceSetprop('ro.test_harness')
+ ]
+)
diff --git a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py b/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
index d0e7948..fe00d33 100644
--- a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
+++ b/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py
@@ -140,25 +140,51 @@
"""Clean up device after test completion."""
pass
- def _get_controller_config(self, controller_name):
- """Get the controller config from the instrumentation config, at the
- level of the current test class or test case.
+ def _get_merged_config(self, config_name):
+ """Takes the configs with config_name from the base, testclass, and
+ testcase levels and merges them together. When the same parameter is
+ defined in different contexts, the value from the most specific context
+ is taken.
+
+ Example:
+ self._instrumentation_config = {
+ 'sample_config': {
+ 'val_a': 5,
+ 'val_b': 7
+ },
+ 'ActsTestClass': {
+ 'sample_config': {
+ 'val_b': 3,
+ 'val_c': 6
+ },
+ 'acts_test_case': {
+ 'sample_config': {
+ 'val_c': 10,
+ 'val_d': 2
+ }
+ }
+ }
+ }
+
+ self._get_merged_config('sample_config') returns
+ {
+ 'val_a': 5,
+ 'val_b': 3,
+ 'val_c': 10,
+ 'val_d': 2
+ }
Args:
- controller_name: Name of the controller config to fetch
- Returns: The controller config, as a ConfigWrapper
+ config_name: Name of the config to fetch
+ Returns: The merged config, as a ConfigWrapper
"""
+ merged_config = self._instrumentation_config.get_config(
+ config_name)
+ merged_config.update(self._class_config.get_config(config_name))
if self.current_test_name:
- # Return the testcase level config, used for setting up test
case_config = self._class_config.get_config(self.current_test_name)
- return case_config.get_config(controller_name)
- else:
- # Merge the base and testclass level configs, used for setting up
- # class.
- merged_config = self._instrumentation_config.get_config(
- controller_name)
- merged_config.update(self._class_config.get_config(controller_name))
- return merged_config
+ merged_config.update(case_config.get_config(config_name))
+ return merged_config
def adb_run(self, cmds):
"""Run the specified command, or list of commands, with the ADB shell.
diff --git a/acts/framework/acts/test_utils/instrumentation/intent_builder.py b/acts/framework/acts/test_utils/instrumentation/intent_builder.py
index 1fe4035..a1cc529 100644
--- a/acts/framework/acts/test_utils/instrumentation/intent_builder.py
+++ b/acts/framework/acts/test_utils/instrumentation/intent_builder.py
@@ -14,17 +14,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from collections import defaultdict
+import collections
-TYPE_TO_FLAG = defaultdict(lambda: '--es')
-TYPE_TO_FLAG.update(
- {
- bool: '--ez',
- int: '--ei',
- float: '--ef',
- str: '--es'
- }
-)
+TYPE_TO_FLAG = collections.defaultdict(lambda: '--es')
+TYPE_TO_FLAG.update({bool: '--ez', int: '--ei', float: '--ef', str: '--es'})
class IntentBuilder(object):
@@ -41,7 +34,7 @@
self._component = None
self._data_uri = None
self._flags = []
- self._key_value_params = {}
+ self._key_value_params = collections.OrderedDict()
def set_action(self, action):
"""Set the intent action, as marked by the -a flag"""
@@ -85,6 +78,6 @@
str_value = str(value)
if isinstance(value, bool):
str_value = str_value.lower()
- cmd.append(
- ' '.join((TYPE_TO_FLAG[type(value)], key, str_value)))
+ cmd.append(' '.join((TYPE_TO_FLAG[type(value)], key,
+ str_value)))
return ' '.join(cmd).strip()
diff --git a/acts/framework/acts/test_utils/power/PowerBaseTest.py b/acts/framework/acts/test_utils/power/PowerBaseTest.py
index 08e7a9a..92fc603 100644
--- a/acts/framework/acts/test_utils/power/PowerBaseTest.py
+++ b/acts/framework/acts/test_utils/power/PowerBaseTest.py
@@ -50,7 +50,6 @@
"""Create a random obj with unknown attributes and value.
"""
-
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
@@ -69,7 +68,6 @@
"""Base class for all wireless power related tests.
"""
-
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
@@ -94,8 +92,7 @@
self.mon.attach_device(self.dut)
# Unpack the test/device specific parameters
- TEST_PARAMS = self.TAG + '_params'
- req_params = [TEST_PARAMS, 'custom_files']
+ req_params = ['custom_files']
self.unpack_userparams(req_params)
# Unpack the custom files based on the test configs
for file in self.custom_files:
@@ -111,11 +108,14 @@
asserts.abort_class_if(
not self.threshold_file,
'Required test pass/fail threshold file is missing')
- asserts.abort_class_if(not self.rockbottom_script,
- 'Required rockbottom setting script is missing')
+ asserts.abort_class_if(
+ not self.rockbottom_script,
+ 'Required rockbottom setting script is missing')
# Unpack test specific configs
- self.unpack_testparams(getattr(self, TEST_PARAMS))
+ TEST_PARAMS = self.TAG + '_params'
+ self.test_params = self.user_params.get(TEST_PARAMS, {})
+ self.unpack_testparams(self.test_params)
if hasattr(self, 'attenuators'):
self.num_atten = self.attenuators[0].instrument.num_atten
self.atten_level = self.unpack_custom_file(self.attenuation_file)
@@ -124,7 +124,7 @@
self.mon_info = self.create_monsoon_info()
# Sync device time, timezone and country code
- utils.require_sl4a((self.dut,))
+ utils.require_sl4a((self.dut, ))
utils.sync_device_time(self.dut)
self.dut.droid.wifiSetCountryCode('US')
@@ -159,11 +159,18 @@
self.mon.usb('on')
self.power_logger.set_avg_power(self.power_result.metric_value)
self.power_logger.set_testbed(self.testbed_name)
+
# Take Bugreport
if self.bug_report:
begin_time = utils.get_current_epoch_time()
self.dut.take_bug_report(self.test_name, begin_time)
+ # Allow the device to cooldown before executing the next test
+ last_test = self.current_test_name == self.results.requested[-1]
+ cooldown = self.test_params.get('cooldown', None)
+ if cooldown and not last_test:
+ time.sleep(cooldown)
+
def teardown_class(self):
"""Clean up the test class after tests finish running
@@ -444,11 +451,10 @@
iperf_result = ipf.IPerfResult(iperf_file)
# Compute the throughput in Mbit/s
- throughput = (
- math.fsum(
- iperf_result.instantaneous_rates[self.start_meas_time:-1]) /
- len(iperf_result.instantaneous_rates[self.start_meas_time:-1])
- ) * 8 * (1.024**2)
+ throughput = (math.fsum(
+ iperf_result.instantaneous_rates[self.start_meas_time:-1]
+ ) / len(iperf_result.instantaneous_rates[self.start_meas_time:-1])
+ ) * 8 * (1.024**2)
self.log.info('The average throughput is {}'.format(throughput))
except ValueError:
diff --git a/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py b/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
index 9a3b100..d7bc63c 100644
--- a/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
+++ b/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
@@ -19,6 +19,7 @@
import acts.test_utils.power.PowerBaseTest as PBT
import acts.controllers.cellular_simulator as simulator
from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsu
+from acts.controllers.rohdeschwarz_lib import cmw500_cellular_simulator as cmw
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
@@ -75,10 +76,6 @@
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
filename_calibration_table = (
self.FILENAME_CALIBRATION_TABLE_UNFORMATTED.format(
@@ -91,9 +88,8 @@
self.log.debug(self.calibration_table)
break
- # Store the value of the key to access the test config in the
- # user_params dictionary.
- self.PARAMS_KEY = self.TAG + "_params"
+ # Ensure the calibration table only contains non-negative values
+ self.ensure_valid_calibration_table(self.calibration_table)
# Turn on airplane mode for all devices, as some might
# be unused during the test
@@ -135,6 +131,18 @@
self.md8475a_ip_address)
else:
raise ValueError('Invalid MD8475 version.')
+
+ elif hasattr(self, 'cmw500_ip') or hasattr(self, 'cmw500_port'):
+
+ for key in ['cmw500_ip', 'cmw500_port']:
+ if not hasattr(self, key):
+ raise RuntimeError('The CMW500 cellular simulator '
+ 'requires %s to be set in the '
+ 'config file.' % key)
+
+ return cmw.CMW500CellularSimulator(self.cmw500_ip,
+ self.cmw500_port)
+
else:
raise RuntimeError(
'The simulator could not be initialized because '
@@ -196,14 +204,9 @@
# Wait for new params to settle
time.sleep(5)
- # Start the simulation. This method will raise a RuntimeException if
+ # Start the simulation. This method will raise an exception if
# the phone is unable to attach.
- try:
- self.simulation.start()
- except RuntimeError:
- return False
-
- self.simulation.start_test_case()
+ self.simulation.start()
# Make the device go to sleep
self.dut.droid.goToSleepNow()
@@ -352,5 +355,22 @@
# Instantiate a new simulation
self.simulation = simulation_class(self.cellular_simulator, self.log,
self.dut,
- self.user_params[self.PARAMS_KEY],
+ self.test_params,
self.calibration_table[sim_type])
+
+ def ensure_valid_calibration_table(self, calibration_table):
+ """ Ensures the calibration table has the correct structure.
+
+ A valid calibration table is a nested dictionary with non-negative
+ number values
+
+ """
+ if not calibration_table or not isinstance(calibration_table, dict):
+ raise TypeError('The calibration table must be a dictionary')
+ for val in calibration_table.values():
+ if isinstance(val, dict):
+ self.ensure_valid_calibration_table(val)
+ elif not isinstance(val, float) and not isinstance(val, int):
+ raise TypeError('Calibration table value must be a number')
+ elif val < 0.0:
+ raise ValueError('Calibration table contains negative values')
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
index 6ce7f85..091c18e 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
@@ -18,16 +18,14 @@
from enum import Enum
import numpy as np
-
-from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
-from acts.controllers.anritsu_lib.md8475a import BtsNumber
+from acts.controllers import cellular_simulator
from acts.test_utils.tel.tel_test_utils import get_telephony_signal_strength
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import toggle_cell_data_roaming
class BaseSimulation():
- """ Base class for an Anritsu Simulation abstraction.
+ """ Base class for cellular connectivity simulations.
Classes that inherit from this base class implement different simulation
setups. The base class contains methods that are common to all simulation
@@ -37,10 +35,8 @@
NUM_UL_CAL_READS = 3
NUM_DL_CAL_READS = 5
- DL_CAL_TARGET_POWER = {'A': -15.0, 'B': -35.0}
MAX_BTS_INPUT_POWER = 30
MAX_PHONE_OUTPUT_POWER = 23
- DL_MAX_POWER = {'A': -10.0, 'B': -30.0}
UL_MIN_POWER = -60.0
# Key to read the calibration setting from the test_config dictionary.
@@ -86,6 +82,7 @@
parameters to None. """
self.output_power = None
self.input_power = None
+ self.band = None
def incorporate(self, new_config):
""" Incorporates a different configuration by replacing the current
@@ -111,7 +108,6 @@
"""
self.simulator = simulator
- self.anritsu = simulator.anritsu
self.log = log
self.dut = dut
self.calibration_table = calibration_table
@@ -128,9 +124,6 @@
self.calibration_required = test_config.get(self.KEY_CALIBRATION,
False)
- # Gets BTS1 since this sim only has 1 BTS
- self.bts1 = self.anritsu.get_BTS(BtsNumber.BTS1)
-
# Configuration object for the primary base station
self.primary_config = self.BtsConfig()
@@ -155,25 +148,17 @@
# Enable roaming on the phone
toggle_cell_data_roaming(self.dut, True)
- # Load callbox config files
- self.callbox_config_path = self.CALLBOX_PATH_FORMAT_STR.format(
- self.anritsu._md8475_version)
- self.load_config_files()
-
# Make sure airplane mode is on so the phone won't attach right away
toggle_airplane_mode(self.log, self.dut, True)
# Wait for airplane mode setting to propagate
time.sleep(2)
- # Start simulation if it wasn't started
- self.anritsu.start_simulation()
+ # Prepare the simulator for this simulation setup
+ self.setup_simulator()
- def load_config_files(self):
- """ Loads configuration files for the simulation.
-
- This method needs to be implement by derived simulation classes. """
-
+ def setup_simulator(self):
+ """ Do initial configuration in the simulator. """
raise NotImplementedError()
def attach(self):
@@ -196,7 +181,7 @@
new_config = self.BtsConfig()
new_config.input_power = -10
new_config.output_power = -30
- self.configure_bts(self.bts1, new_config)
+ self.simulator.configure_bts(new_config)
self.primary_config.incorporate(new_config)
# Try to attach the phone.
@@ -208,15 +193,14 @@
toggle_airplane_mode(self.log, self.dut, False)
# Wait for the phone to attach.
- self.anritsu.wait_for_registration_state(
- time_to_wait=self.ATTACH_WAITING_TIME)
+ self.simulator.wait_until_attached(
+ timeout=self.ATTACH_WAITING_TIME)
- except AnritsuError as e:
+ except cellular_simulator.CellularSimulatorError:
# The phone failed to attach
self.log.info(
"UE failed to attach on attempt number {}.".format(i + 1))
- self.log.info("Error message: {}".format(str(e)))
# Turn airplane mode on to prepare the phone for a retry.
toggle_airplane_mode(self.log, self.dut, True)
@@ -253,21 +237,13 @@
# Wait for APM to propagate
time.sleep(2)
- # Try to power off the basestation. An exception will be raised if the
- # simulation is not running, which is ok because it means the phone is
- # not attached.
- try:
- self.anritsu.set_simulation_state_to_poweroff()
- except AnritsuError:
- self.log.warning('Could not power off the basestation. The '
- 'simulation might be stopped.')
+ # Power off basestation
+ self.simulator.detach()
def stop(self):
""" Detach phone from the basestation by stopping the simulation.
- Send stop command to anritsu and turn on airplane mode.
-
- """
+ Stop the simulation and turn airplane mode on. """
# Set the DUT to airplane mode so it doesn't see the
# cellular network going off
@@ -277,28 +253,39 @@
time.sleep(2)
# Stop the simulation
- self.anritsu.stop_simulation()
+ self.simulator.stop()
def start(self):
""" Start the simulation by attaching the phone and setting the
required DL and UL power.
Note that this refers to starting the simulated testing environment
- and not to starting the simulation in the Anritsu callbox, which was
- done during the class initialization. """
+ and not to starting the signaling on the cellular instruments,
+ which might have been done earlier depending on the cellular
+ instrument controller implementation. """
if not self.attach():
raise RuntimeError('Could not attach to base station.')
+ # Starts IP traffic while changing this setting to force the UE to be
+ # in Communication state, as UL power cannot be set in Idle state
+ self.start_traffic_for_calibration()
+
+ # Wait until it goes to communication state
+ self.simulator.wait_until_communication_state()
+
# Set signal levels obtained from the test parameters
new_config = self.BtsConfig()
new_config.output_power = self.calibrated_downlink_rx_power(
self.primary_config, self.sim_dl_power)
new_config.input_power = self.calibrated_uplink_tx_power(
self.primary_config, self.sim_ul_power)
- self.configure_bts(self.bts1, new_config)
+ self.simulator.configure_bts(new_config)
self.primary_config.incorporate(new_config)
+ # Stop IP traffic after setting the UL power level
+ self.stop_traffic_for_calibration()
+
def parse_parameters(self, parameters):
""" Configures simulation using a list of parameters.
@@ -311,22 +298,6 @@
raise NotImplementedError()
- def configure_bts(self, bts_handle, config):
- """ Configures the base station in the Anritsu callbox.
-
- Parameters set to None in the configuration object are skipped.
-
- Args:
- bts_handle: a handle to the Anritsu base station controller.
- config: a BtsConfig object containing the desired configuration.
- """
-
- if config.output_power:
- bts_handle.output_level = config.output_power
-
- if config.input_power:
- bts_handle.input_level = config.input_power
-
def consume_parameter(self, parameters, parameter_name, num_values=0):
""" Parses a parameter from a list.
@@ -419,14 +390,12 @@
# throw an TypeError exception
try:
calibrated_power = round(power + self.dl_path_loss)
- if (calibrated_power >
- self.DL_MAX_POWER[self.anritsu._md8475_version]):
+ if calibrated_power > self.simulator.MAX_DL_POWER:
self.log.warning(
"Cannot achieve phone DL Rx power of {} dBm. Requested TX "
"power of {} dBm exceeds callbox limit!".format(
power, calibrated_power))
- calibrated_power = self.DL_MAX_POWER[
- self.anritsu._md8475_version]
+ calibrated_power = self.simulator.MAX_DL_POWER
self.log.warning(
"Setting callbox Tx power to max possible ({} dBm)".format(
calibrated_power))
@@ -467,13 +436,6 @@
else:
power = signal_level
- # Starts IP traffic while changing this setting to force the UE to be
- # in Communication state, as UL power cannot be set in Idle state
- self.start_traffic_for_calibration()
-
- # Wait until it goes to communication state
- self.anritsu.wait_for_communication_state()
-
# Try to use measured path loss value. If this was not set, it will
# throw an TypeError exception
try:
@@ -503,9 +465,6 @@
"uncalibrated).".format(round(power)))
return round(power)
- # Stop IP traffic after setting the UL power level
- self.stop_traffic_for_calibration()
-
def calibrate(self, band):
""" Calculates UL and DL path loss if it wasn't done before.
@@ -540,27 +499,15 @@
Starts UDP IP traffic before running calibration. Uses APN_1
configured in the phone.
"""
- try:
- self.anritsu.start_ip_traffic()
- except AnritsuError as inst:
- # This typically happens when traffic is already running
- self.log.warning("{}\n".format(inst))
- time.sleep(4)
+ self.simulator.start_data_traffic()
def stop_traffic_for_calibration(self):
"""
Stops IP traffic after calibration.
"""
- try:
- self.anritsu.stop_ip_traffic()
- except AnritsuError as inst:
- # This typically happens when traffic has already been stopped
- self.log.warning("{}\n".format(inst))
- time.sleep(2)
+ self.simulator.stop_data_traffic()
- def downlink_calibration(self,
- rat=None,
- power_units_conversion_func=None):
+ def downlink_calibration(self, rat=None, power_units_conversion_func=None):
""" Computes downlink path loss and returns the calibration value
The DUT needs to be attached to the base station before calling this
@@ -591,9 +538,8 @@
# Set BTS to a good output level to minimize measurement error
initial_screen_timeout = self.dut.droid.getScreenTimeout()
new_config = self.BtsConfig()
- new_config.output_power = self.DL_CAL_TARGET_POWER[
- self.anritsu._md8475_version]
- self.configure_bts(self.bts1, new_config)
+ new_config.output_power = self.simulator.MAX_DL_POWER - 5
+ self.simulator.configure_bts(new_config)
# Set phone sleep time out
self.dut.droid.setScreenTimeout(1800)
@@ -619,7 +565,7 @@
# Reset phone and bts to original settings
self.dut.droid.goToSleepNow()
self.dut.droid.setScreenTimeout(initial_screen_timeout)
- self.configure_bts(self.bts1, restoration_config)
+ self.simulator.configure_bts(restoration_config)
time.sleep(2)
# Calculate the mean of the measurements
@@ -633,8 +579,7 @@
avg_down_power = reported_asu_power
# Calculate Path Loss
- dl_target_power = self.DL_CAL_TARGET_POWER[
- self.anritsu._md8475_version]
+ dl_target_power = self.simulator.MAX_DL_POWER - 5
down_call_path_loss = dl_target_power - avg_down_power
# Validate the result
@@ -668,7 +613,7 @@
initial_screen_timeout = self.dut.droid.getScreenTimeout()
new_config = self.BtsConfig()
new_config.input_power = self.MAX_BTS_INPUT_POWER
- self.configure_bts(self.bts1, new_config)
+ self.simulator.configure_bts(new_config)
# Set phone sleep time out
self.dut.droid.setScreenTimeout(1800)
@@ -706,7 +651,7 @@
# Reset phone and bts to original settings
self.dut.droid.goToSleepNow()
self.dut.droid.setScreenTimeout(initial_screen_timeout)
- self.configure_bts(self.bts1, restoration_config)
+ self.simulator.configure_bts(restoration_config)
time.sleep(2)
# Phone only supports 1x1 Uplink so always chain 0
@@ -729,26 +674,18 @@
return up_call_path_loss
- def set_band(self, bts, band, calibrate_if_necessary=True):
- """ Sets the band used for communication.
-
- When moving to a new band, recalibrate the link.
-
- Args:
- bts: basestation handle
- band: desired band
- calibrate_if_necessary: if False calibration will be skipped
- """
-
- bts.band = band
- time.sleep(5) # It takes some time to propagate the new band
-
- # Invalidate the calibration values
+ def load_pathloss_if_required(self):
+ """ If calibration is required, try to obtain the pathloss values from
+ the calibration table and measure them if they are not available. """
+ # Invalidate the previous values
self.dl_path_loss = None
self.ul_path_loss = None
- # Only calibrate when required.
- if self.calibration_required and calibrate_if_necessary:
+ # Load the new ones
+ if self.calibration_required:
+
+ band = self.primary_config.band
+
# Try loading the path loss values from the calibration table. If
# they are not available, use the automated calibration procedure.
try:
@@ -791,19 +728,3 @@
Maximum throughput in mbps
"""
raise NotImplementedError()
-
- def start_test_case(self):
- """ Starts a test case in the current simulation.
-
- Requires the phone to be attached.
- """
-
- pass
-
- def wait_for_rrc_idle_state(self, wait_time):
- """ Waits for UE RRC state change to idle mode.
-
- Raises exception when UE fails to move to idle state
- """
-
- self.anritsu.wait_for_idle_state(wait_time)
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
index 4af6bf2..6dc2082 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
@@ -16,7 +16,9 @@
import ntpath
+import time
from acts.controllers.anritsu_lib.md8475a import BtsGprsMode
+from acts.controllers.anritsu_lib.md8475a import BtsNumber
from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsusim
from acts.test_utils.power.tel_simulations.BaseSimulation import BaseSimulation
from acts.test_utils.tel.anritsu_utils import GSM_BAND_DCS1800
@@ -27,9 +29,7 @@
class GsmSimulation(BaseSimulation):
- """ Simple GSM simulation with only one basestation.
-
- """
+ """ Single base station GSM. """
# Simulation config files in the callbox computer.
# These should be replaced in the future by setting up
@@ -55,7 +55,7 @@
}
def __init__(self, simulator, log, dut, test_config, calibration_table):
- """ Configures Anritsu system for GSM simulation with 1 basetation
+ """ Initializes the simulator for a single-carrier GSM simulation.
Loads a simple LTE simulation enviroment with 1 basestation. It also
creates the BTS handle so we can change the parameters as desired.
@@ -69,15 +69,18 @@
different bands.
"""
-
- super().__init__(simulator, log, dut, test_config, calibration_table)
-
# The GSM simulation relies on the cellular simulator to be a MD8475
if not isinstance(self.simulator, anritsusim.MD8475CellularSimulator):
raise ValueError('The GSM simulation relies on the simulator to '
'be an Anritsu MD8475 A/B instrument.')
+ # The Anritsu controller needs to be unwrapped before calling
+ # super().__init__ because setup_simulator() requires self.anritsu and
+ # will be called during the parent class initialization.
self.anritsu = self.simulator.anritsu
+ self.bts1 = self.anritsu.get_BTS(BtsNumber.BTS1)
+
+ super().__init__(simulator, log, dut, test_config, calibration_table)
if not dut.droid.telephonySetPreferredNetworkTypesForSubscription(
NETWORK_MODE_GSM_ONLY,
@@ -86,13 +89,20 @@
else:
log.info("Preferred network type set.")
- def load_config_files(self):
- """ Loads configuration files for the simulation. """
+ def setup_simulator(self):
+ """ Do initial configuration in the simulator. """
+
+ # Load callbox config files
+ callbox_config_path = self.CALLBOX_PATH_FORMAT_STR.format(
+ self.anritsu._md8475_version)
self.anritsu.load_simulation_paramfile(
- ntpath.join(self.callbox_config_path, self.GSM_BASIC_SIM_FILE))
+ ntpath.join(callbox_config_path, self.GSM_BASIC_SIM_FILE))
self.anritsu.load_cell_paramfile(
- ntpath.join(self.callbox_config_path, self.GSM_CELL_FILE))
+ ntpath.join(callbox_config_path, self.GSM_CELL_FILE))
+
+ # Start simulation if it wasn't started
+ self.anritsu.start_simulation()
def parse_parameters(self, parameters):
""" Configs a GSM simulation using a list of parameters.
@@ -113,6 +123,7 @@
"the required band number.".format(self.PARAM_BAND))
self.set_band(self.bts1, values[1])
+ self.load_pathloss_if_required()
# Setup GPRS mode
@@ -139,3 +150,14 @@
self.PARAM_SLOTS))
self.bts1.gsm_slots = (int(values[1]), int(values[2]))
+
+ def set_band(self, bts, band):
+ """ Sets the band used for communication.
+
+ Args:
+ bts: basestation handle
+ band: desired band
+ """
+
+ bts.band = band
+ time.sleep(5) # It takes some time to propagate the new band
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
index d5e2840..6273833 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
@@ -14,19 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import re
-import time
-
+from acts.controllers.anritsu_lib.md8475a import BtsNumber
from acts.controllers.anritsu_lib.md8475a import BtsTechnology
from acts.controllers.anritsu_lib.md8475a import LteMimoMode
-from acts.controllers.anritsu_lib.md8475a import BtsNumber
-from acts.controllers.anritsu_lib.md8475a import BtsPacketRate
-from acts.controllers.anritsu_lib.md8475a import TestProcedure
-from acts.controllers.anritsu_lib.md8475a import TestPowerControl
-from acts.controllers.anritsu_lib.md8475a import TestMeasurement
-from acts.test_utils.power.tel_simulations.LteSimulation import LteSimulation
+from acts.test_utils.power.tel_simulations import LteSimulation
-class LteCaSimulation(LteSimulation):
+class LteCaSimulation(LteSimulation.LteSimulation):
+ """ Carrier aggregation LTE simulation. """
# Dictionary of lower DL channel number bound for each band.
LOWEST_DL_CN_DICTIONARY = {
@@ -72,26 +67,20 @@
42: 45590
}
- # Simulation config files in the callbox computer.
- # These should be replaced in the future by setting up
- # the same configuration manually.
- LTE_BASIC_SIM_FILE = 'SIM_LTE_CA.wnssp'
- LTE_BASIC_CELL_FILE = 'CELL_LTE_CA_config.wnscp'
-
# Simulation config keywords contained in the test name
PARAM_CA = 'ca'
# Test config keywords
KEY_FREQ_BANDS = "freq_bands"
- def __init__(self, anritsu, log, dut, test_config, calibration_table):
- """ Configures Anritsu system for LTE simulation with carrier
+ def __init__(self, simulator, log, dut, test_config, calibration_table):
+ """ Initializes the simulator for LTE simulation with carrier
aggregation.
Loads a simple LTE simulation enviroment with 5 basestations.
Args:
- anritsu: the Anritsu callbox controller
+ simulator: the cellular instrument controller
log: a logger handle
dut: the android device handler
test_config: test configuration obtained from the config file
@@ -100,72 +89,57 @@
"""
- super().__init__(anritsu, log, dut, test_config, calibration_table)
+ super().__init__(simulator, log, dut, test_config, calibration_table)
- self.bts = [self.bts1, self.anritsu.get_BTS(BtsNumber.BTS2)]
+ self.anritsu = simulator.anritsu
+
+ self.bts = [
+ self.anritsu.get_BTS(BtsNumber.BTS1),
+ self.anritsu.get_BTS(BtsNumber.BTS2)
+ ]
if self.anritsu._md8475_version == 'B':
self.bts.extend([
- anritsu.get_BTS(BtsNumber.BTS3),
- anritsu.get_BTS(BtsNumber.BTS4)
+ self.anritsu.get_BTS(BtsNumber.BTS3),
+ self.anritsu.get_BTS(BtsNumber.BTS4)
])
# Create a configuration object for each base station and copy initial
# settings from the PCC base station.
self.bts_configs = [self.primary_config]
- for bts_index in range(1, len(self.bts)):
+ for bts_index in range(1, self.simulator.LTE_MAX_CARRIERS):
new_config = self.BtsConfig()
new_config.incorporate(self.primary_config)
- self.configure_bts(self.bts[bts_index], new_config)
+ self.simulator.configure_bts(new_config, bts_index)
self.bts_configs.append(new_config)
# Get LTE CA frequency bands setting from the test configuration
if self.KEY_FREQ_BANDS not in test_config:
self.log.warning("The key '{}' is not set in the config file. "
"Setting to null by default.".format(
- self.KEY_FREQ_BANDS))
+ self.KEY_FREQ_BANDS))
self.freq_bands = test_config.get(self.KEY_FREQ_BANDS, True)
- def configure_bts(self, bts_handle, config):
- """ Adds LTE with CA specific procedures. See parent class
- implementation for more details.
-
- Args:
- bts_handle: a handle to the Anritsu base station controller.
- config: a BtsConfig object containing the desired configuration.
- """
-
- # The callbox won't restore the band-dependent default values if the
- # request is to switch to the same band as the one the base station is
- # currently using. To ensure that default values are restored, go to a
- # different band before switching.
- if config.band and int(bts_handle.band) == config.band:
- # Using bands 1 and 2 but it could be any others
- bts_handle.band = '1' if config.band != 1 else '2'
- # Switching to config.band will be handled by the parent class
- # implementation of this method.
-
- super().configure_bts(bts_handle, config)
+ def setup_simulator(self):
+ """ Do initial configuration in the simulator. """
+ self.simulator.setup_lte_ca_scenario()
def parse_parameters(self, parameters):
""" Configs an LTE simulation with CA using a list of parameters.
- Calls the parent method first, then consumes parameters specific to LTE
-
Args:
parameters: list of parameters
"""
# Enable all base stations initially. The ones that are not needed after
# parsing the CA combo string can be removed.
- self.anritsu.set_simulation_model(
- BtsTechnology.LTE,
- BtsTechnology.LTE,
- BtsTechnology.LTE,
- BtsTechnology.LTE,
- reset=False)
+ self.anritsu.set_simulation_model(BtsTechnology.LTE,
+ BtsTechnology.LTE,
+ BtsTechnology.LTE,
+ BtsTechnology.LTE,
+ reset=False)
# Create an empty array for new configuration objects. Elements will be
# added to this list after parsing the CA configuration from the band
@@ -214,7 +188,7 @@
if ca_class.upper() == 'A':
- if bts_index >= len(self.bts):
+ if bts_index >= self.simulator.LTE_MAX_CARRIERS:
raise ValueError("This callbox model doesn't allow the "
"requested CA configuration")
@@ -228,7 +202,7 @@
elif ca_class.upper() == 'C':
- if bts_index + 1 >= len(self.bts):
+ if bts_index + 1 >= self.simulator.LTE_MAX_CARRIERS:
raise ValueError("This callbox model doesn't allow the "
"requested CA configuration")
@@ -355,7 +329,7 @@
for elem in LteSimulation.MimoMode})
if (requested_mimo == LteSimulation.MimoMode.MIMO_4x4
- and self.anritsu._md8475_version == 'A'):
+ and not self.simulator.LTE_SUPPORTS_4X4_MIMO):
raise ValueError("The test requires 4x4 MIMO, but that is not "
"supported by the MD8475A callbox.")
@@ -436,16 +410,16 @@
"The '{}' parameter was not set, using 100% RBs for both "
"DL and UL. To set the percentages of total RBs include "
"the '{}' parameter followed by two ints separated by an "
- "underscore indicating downlink and uplink percentages."
- .format(self.PARAM_PATTERN, self.PARAM_PATTERN))
+ "underscore indicating downlink and uplink percentages.".
+ format(self.PARAM_PATTERN, self.PARAM_PATTERN))
dl_pattern = 100
ul_pattern = 100
else:
dl_pattern = int(values[1])
ul_pattern = int(values[2])
- if (dl_pattern, ul_pattern) not in [(0, 100), (100, 0), (100,
- 100)]:
+ if (dl_pattern, ul_pattern) not in [(0, 100), (100, 0),
+ (100, 100)]:
raise ValueError(
"Only full RB allocation for DL or UL is supported in CA "
"sims. The allowed combinations are 100/0, 0/100 and "
@@ -469,58 +443,30 @@
dl_rbs, ul_rbs = self.allocation_percentages_to_rbs(
new_configs[bts_index].bandwidth,
- new_configs[bts_index].transmission_mode,
- dl_pattern, ul_pattern)
+ new_configs[bts_index].transmission_mode, dl_pattern,
+ ul_pattern)
new_configs[bts_index].dl_rbs = dl_rbs
new_configs[bts_index].ul_rbs = ul_rbs
new_configs[bts_index].dl_mcs = mcs_dl
new_configs[bts_index].ul_mcs = mcs_ul
+ # Enable the configured base stations for CA
+ for bts_config in new_configs:
+ bts_config.dl_cc_enabled = True
+
# Setup the base stations with the obtained configurations and then save
# these parameters in the current configuration objects
for bts_index in range(len(new_configs)):
- self.configure_bts(self.bts[bts_index], new_configs[bts_index])
+ self.simulator.configure_bts(new_configs[bts_index], bts_index)
self.bts_configs[bts_index].incorporate(new_configs[bts_index])
- def start_test_case(self):
- """ Attaches the phone to all the other basestations.
-
- Starts the CA test case. Requires being attached to
- basestation 1 first.
-
- """
-
# Trigger UE capability enquiry from network to get
# UE supported CA band combinations. Here freq_bands is a hex string.
-
self.anritsu.trigger_ue_capability_enquiry(self.freq_bands)
- testcase = self.anritsu.get_AnritsuTestCases()
- # Setting the procedure to selection is needed because of a bug in the
- # instrument's software (b/139547391).
- testcase.procedure = TestProcedure.PROCEDURE_SELECTION
- testcase.procedure = TestProcedure.PROCEDURE_MULTICELL
- testcase.power_control = TestPowerControl.POWER_CONTROL_DISABLE
- testcase.measurement_LTE = TestMeasurement.MEASUREMENT_DISABLE
-
- for bts_index in range(1, self.num_carriers):
- self.bts[bts_index].dl_cc_enabled = True
-
- self.anritsu.start_testcase()
-
- retry_counter = 0
- self.log.info("Waiting for the test case to start...")
- time.sleep(5)
-
- while self.anritsu.get_testcase_status() == "0":
- retry_counter += 1
- if retry_counter == 3:
- raise RuntimeError("The test case failed to start after {} "
- "retries. The connection between the phone "
- "and the basestation might be unstable."
- .format(retry_counter))
- time.sleep(10)
+ # Now that the band is set, calibrate the link for the PCC if necessary
+ self.load_pathloss_if_required()
def maximum_downlink_throughput(self):
""" Calculates maximum downlink throughput as the sum of all the active
@@ -533,17 +479,20 @@
def start(self):
""" Set the signal level for the secondary carriers, as the base class
implementation of this method will only set up downlink power for the
- primary carrier component. """
+ primary carrier component.
+
+ After that, attaches the secondary carriers."""
super().start()
- if not self.sim_dl_power:
- return
+ if self.sim_dl_power:
+ self.log.info('Setting DL power for secondary carriers.')
- for bts_index in range(1, self.num_carriers):
- self.log.info("Setting DL power for BTS{}.".format(bts_index + 1))
- new_config = self.BtsConfig()
- new_config.output_power = self.calibrated_downlink_rx_power(
- self.bts_configs[bts_index], self.sim_dl_power)
- self.configure_bts(self.bts[bts_index], new_config)
- self.bts_configs[bts_index].incorporate(new_config)
+ for bts_index in range(1, self.num_carriers):
+ new_config = self.BtsConfig()
+ new_config.output_power = self.calibrated_downlink_rx_power(
+ self.bts_configs[bts_index], self.sim_dl_power)
+ self.simulator.configure_bts(new_config, bts_index)
+ self.bts_configs[bts_index].incorporate(new_config)
+
+ self.simulator.lte_attach_secondary_carriers()
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/LteImsSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/LteImsSimulation.py
index ecbd4b9..7110246 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/LteImsSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/LteImsSimulation.py
@@ -17,6 +17,7 @@
import acts.test_utils.tel.anritsu_utils as anritsu_utils
import acts.controllers.anritsu_lib.md8475a as md8475a
+
class LteImsSimulation(LteSimulation):
LTE_BASIC_SIM_FILE = 'VoLTE_ATT_Sim.wnssp'
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
index 224cb67..c0cf063 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
@@ -14,28 +14,46 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
import math
-import ntpath
from enum import Enum
from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsusim
-from acts.controllers.anritsu_lib.md8475a import BtsBandwidth
-from acts.controllers.anritsu_lib.md8475a import BtsPacketRate
from acts.test_utils.power.tel_simulations.BaseSimulation import BaseSimulation
from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
+class TransmissionMode(Enum):
+ """ Transmission modes for LTE (e.g., TM1, TM4, ...) """
+ TM1 = "TM1"
+ TM2 = "TM2"
+ TM3 = "TM3"
+ TM4 = "TM4"
+ TM7 = "TM7"
+ TM8 = "TM8"
+ TM9 = "TM9"
+
+
+class MimoMode(Enum):
+ """ Mimo modes """
+ MIMO_1x1 = "1x1"
+ MIMO_2x2 = "2x2"
+ MIMO_4x4 = "4x4"
+
+
+class SchedulingMode(Enum):
+ """ Traffic scheduling modes (e.g., STATIC, DYNAMIC) """
+ DYNAMIC = "DYNAMIC"
+ STATIC = "STATIC"
+
+
+class DuplexMode(Enum):
+ """ DL/UL Duplex mode """
+ FDD = "FDD"
+ TDD = "TDD"
+
+
class LteSimulation(BaseSimulation):
- """ Simple LTE simulation with only one basestation.
-
- """
-
- # Simulation config files in the callbox computer.
- # These should be replaced in the future by setting up
- # the same configuration manually.
- LTE_BASIC_SIM_FILE = 'SIM_default_LTE.wnssp'
- LTE_BASIC_CELL_FILE = 'CELL_LTE_config.wnscp'
+ """ Single-carrier LTE simulation. """
# Simulation config keywords contained in the test name
PARAM_FRAME_CONFIG = "tddconfig"
@@ -56,39 +74,6 @@
KEY_DL_256_QAM = "256_qam_dl"
KEY_UL_64_QAM = "64_qam_ul"
- class TransmissionMode(Enum):
- ''' Transmission modes for LTE (e.g., TM1, TM4, ..)
-
- '''
- TM1 = "TM1"
- TM2 = "TM2"
- TM3 = "TM3"
- TM4 = "TM4"
- TM7 = "TM7"
- TM8 = "TM8"
- TM9 = "TM9"
-
- class MimoMode(Enum):
- """ Mimo modes """
-
- MIMO_1x1 = "1x1"
- MIMO_2x2 = "2x2"
- MIMO_4x4 = "4x4"
-
- class SchedulingMode(Enum):
- ''' Traffic scheduling modes (e.g., STATIC, DYNAMIC)
-
- '''
- DYNAMIC = "DYNAMIC"
- STATIC = "STATIC"
-
- class DuplexMode(Enum):
- ''' DL/UL Duplex mode
-
- '''
- FDD = "FDD"
- TDD = "TDD"
-
# Units in which signal level is defined in DOWNLINK_SIGNAL_LEVEL_DICTIONARY
DOWNLINK_SIGNAL_LEVEL_UNITS = "RSRP"
@@ -407,7 +392,6 @@
should be used or not
dl_channel: an integer indicating the downlink channel number
"""
-
def __init__(self):
""" Initialize the base station config by setting all its
parameters to None. """
@@ -426,9 +410,10 @@
self.ul_modulation_order = None
self.tbs_pattern_on = None
self.dl_channel = None
+ self.dl_cc_enabled = None
def __init__(self, simulator, log, dut, test_config, calibration_table):
- """ Configures Anritsu system for LTE simulation with 1 basetation
+ """ Initializes the simulator for a single-carrier LTE simulation.
Loads a simple LTE simulation enviroment with 1 basestation.
@@ -449,8 +434,6 @@
raise ValueError('The LTE simulation relies on the simulator to '
'be an Anritsu MD8475 A/B instrument.')
- self.anritsu = self.simulator.anritsu
-
if not dut.droid.telephonySetPreferredNetworkTypesForSubscription(
NETWORK_MODE_LTE_ONLY,
dut.droid.subscriptionGetDefaultSubId()):
@@ -475,9 +458,9 @@
self.dl_256_qam = test_config.get(self.KEY_DL_256_QAM, False)
if self.dl_256_qam:
- if self.anritsu._md8475_version == 'A':
- self.log.warning("The key '{}' is set to true but MD8475A "
- "callbox doesn't support that modulation "
+ if not self.simulator.LTE_SUPPORTS_DL_256QAM:
+ self.log.warning("The key '{}' is set to true but the "
+ "simulator doesn't support that modulation "
"order.".format(self.KEY_DL_256_QAM))
self.dl_256_qam = False
else:
@@ -492,103 +475,19 @@
self.ul_64_qam = test_config.get(self.KEY_UL_64_QAM, False)
if self.ul_64_qam:
- if self.anritsu._md8475_version == 'A':
- self.log.warning("The key '{}' is set to true but MD8475A "
- "callbox doesn't support that modulation "
+ if not self.simulator.LTE_SUPPORTS_UL_64QAM:
+ self.log.warning("The key '{}' is set to true but the "
+ "simulator doesn't support that modulation "
"order.".format(self.KEY_UL_64_QAM))
self.ul_64_qam = False
else:
self.primary_config.ul_modulation_order = "64QAM"
- self.configure_bts(self.bts1, self.primary_config)
+ self.simulator.configure_bts(self.primary_config)
- def configure_bts(self, bts_handle, config):
- """ Configures LTE parameters in the base station handle. See parent
- class implementation for more details.
-
- Args:
- bts_handle: a handle to the Anritsu base station controller.
- config: a BtsConfig object containing the desired configuration.
- """
-
- super().configure_bts(bts_handle, config)
-
- if config.band:
- # Only calibrate for the primary carrier band
- isPcc = bts_handle == self.bts1
- self.set_band(bts_handle,
- config.band,
- calibrate_if_necessary=isPcc)
-
- if config.dlul_config:
- self.set_dlul_configuration(bts_handle, config.dlul_config)
-
- if config.bandwidth:
- self.set_channel_bandwidth(bts_handle, config.bandwidth)
-
- if config.dl_channel:
- # Temporarily adding this line to workaround a bug in the
- # Anritsu callbox in which the channel number needs to be set
- # to a different value before setting it to the final one.
- bts_handle.dl_channel = str(config.dl_channel)
- time.sleep(8)
- bts_handle.dl_channel = str(config.dl_channel - 1)
-
- if config.mimo_mode:
- self.set_mimo_mode(bts_handle, config.mimo_mode)
-
- if config.transmission_mode:
- self.set_transmission_mode(bts_handle, config.transmission_mode)
-
- if config.scheduling_mode:
-
- if (config.scheduling_mode == LteSimulation.SchedulingMode.STATIC
- and not all([
- config.dl_rbs, config.ul_rbs, config.dl_mcs,
- config.ul_mcs
- ])):
- raise ValueError('When the scheduling mode is set to manual, '
- 'the RB and MCS parameters are required.')
-
- # If scheduling mode is set to Dynamic, the RB and MCS parameters
- # will be ignored by set_scheduling_mode.
- self.set_scheduling_mode(bts_handle,
- config.scheduling_mode,
- packet_rate=BtsPacketRate.LTE_MANUAL,
- nrb_dl=config.dl_rbs,
- nrb_ul=config.ul_rbs,
- mcs_ul=config.ul_mcs,
- mcs_dl=config.dl_mcs)
-
- if config.dl_modulation_order:
- bts_handle.lte_dl_modulation_order = config.dl_modulation_order
-
- if config.ul_modulation_order:
- bts_handle.lte_u_modulation_order = config.ul_modulation_order
-
- # This variable stores a boolean value so the following is needed to
- # differentiate False from None
- if config.tbs_pattern_on is not None:
- if config.tbs_pattern_on:
- bts_handle.tbs_pattern = "FULLALLOCATION"
- else:
- bts_handle.tbs_pattern = "OFF"
-
- def load_config_files(self):
- """ Loads configuration files for the simulation. """
-
- cell_file_name = self.LTE_BASIC_CELL_FILE
- sim_file_name = self.LTE_BASIC_SIM_FILE
-
- if self.anritsu._md8475_version == 'B':
- cell_file_name += '2'
- sim_file_name += '2'
-
- cell_file_path = ntpath.join(self.callbox_config_path, cell_file_name)
- sim_file_path = ntpath.join(self.callbox_config_path, sim_file_name)
-
- self.anritsu.load_simulation_paramfile(sim_file_path)
- self.anritsu.load_cell_paramfile(cell_file_path)
+ def setup_simulator(self):
+ """ Do initial configuration in the simulator. """
+ self.simulator.setup_lte_scenario()
def parse_parameters(self, parameters):
""" Configs an LTE simulation using a list of parameters.
@@ -614,15 +513,16 @@
new_config.band = values[1]
# Set DL/UL frame configuration
- if self.get_duplex_mode(new_config.band) == self.DuplexMode.TDD:
+ if self.get_duplex_mode(new_config.band) == DuplexMode.TDD:
values = self.consume_parameter(parameters,
self.PARAM_FRAME_CONFIG, 1)
if not values:
- raise ValueError("When a TDD band is selected the frame "
- "structure has to be indicated with the '{}' "
- "parameter followed by a number from 0 to 6."
- .format(self.PARAM_FRAME_CONFIG))
+ raise ValueError(
+ "When a TDD band is selected the frame "
+ "structure has to be indicated with the '{}' "
+ "parameter followed by a number from 0 to 6.".format(
+ self.PARAM_FRAME_CONFIG))
new_config.dlul_config = int(values[1])
@@ -652,7 +552,7 @@
"The test name needs to include parameter '{}' followed by the "
"mimo mode.".format(self.PARAM_MIMO))
- for mimo_mode in LteSimulation.MimoMode:
+ for mimo_mode in MimoMode:
if values[1] == mimo_mode.value:
new_config.mimo_mode = mimo_mode
break
@@ -660,10 +560,10 @@
raise ValueError("The {} parameter needs to be followed by either "
"1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
- if (new_config.mimo_mode == LteSimulation.MimoMode.MIMO_4x4
- and self.anritsu._md8475_version == 'A'):
+ if (new_config.mimo_mode == MimoMode.MIMO_4x4
+ and not self.simulator.LTE_SUPPORTS_4X4_MIMO):
raise ValueError("The test requires 4x4 MIMO, but that is not "
- "supported by the MD8475A callbox.")
+ "supported by the cellular simulator.")
# Setup transmission mode
@@ -675,7 +575,7 @@
"int value from 1 to 4 indicating transmission mode.".format(
self.PARAM_TM))
- for tm in LteSimulation.TransmissionMode:
+ for tm in TransmissionMode:
if values[1] == tm.value[2:]:
new_config.transmission_mode = tm
break
@@ -689,20 +589,20 @@
values = self.consume_parameter(parameters, self.PARAM_SCHEDULING, 1)
if not values:
- new_config.scheduling_mode = LteSimulation.SchedulingMode.STATIC
+ new_config.scheduling_mode = SchedulingMode.STATIC
self.log.warning(
"The test name does not include the '{}' parameter. Setting to "
"static by default.".format(self.PARAM_SCHEDULING))
elif values[1] == self.PARAM_SCHEDULING_DYNAMIC:
- new_config.scheduling_mode = LteSimulation.SchedulingMode.DYNAMIC
+ new_config.scheduling_mode = SchedulingMode.DYNAMIC
elif values[1] == self.PARAM_SCHEDULING_STATIC:
- new_config.scheduling_mode = LteSimulation.SchedulingMode.STATIC
+ new_config.scheduling_mode = SchedulingMode.STATIC
else:
raise ValueError(
"The test name parameter '{}' has to be followed by either "
"'dynamic' or 'static'.".format(self.PARAM_SCHEDULING))
- if new_config.scheduling_mode == LteSimulation.SchedulingMode.STATIC:
+ if new_config.scheduling_mode == SchedulingMode.STATIC:
values = self.consume_parameter(parameters, self.PARAM_PATTERN, 2)
@@ -711,8 +611,8 @@
"The '{}' parameter was not set, using 100% RBs for both "
"DL and UL. To set the percentages of total RBs include "
"the '{}' parameter followed by two ints separated by an "
- "underscore indicating downlink and uplink percentages."
- .format(self.PARAM_PATTERN, self.PARAM_PATTERN))
+ "underscore indicating downlink and uplink percentages.".
+ format(self.PARAM_PATTERN, self.PARAM_PATTERN))
dl_pattern = 100
ul_pattern = 100
else:
@@ -725,10 +625,9 @@
"positive numbers between 0 and 100.")
new_config.dl_rbs, new_config.ul_rbs = (
- self.allocation_percentages_to_rbs(new_config.bandwidth,
- new_config.transmission_mode,
- dl_pattern,
- ul_pattern))
+ self.allocation_percentages_to_rbs(
+ new_config.bandwidth, new_config.transmission_mode,
+ dl_pattern, ul_pattern))
if self.dl_256_qam and new_config.bandwidth == 1.4:
new_config.dl_mcs = 26
@@ -744,18 +643,20 @@
new_config.ul_mcs = 23
# Setup LTE RRC status change function and timer for LTE idle test case
-
+ # TODO (b/141838145): setting RRC timer parameters requires unwrapping
+ # the simulator class as it still doesn't support these methods.
values = self.consume_parameter(parameters,
self.PARAM_RRC_STATUS_CHANGE_TIMER, 1)
if not values:
self.log.info(
"The test name does not include the '{}' parameter. Disabled "
"by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER))
- self.anritsu.set_lte_rrc_status_change(False)
+ self.simulator.anritsu.set_lte_rrc_status_change(False)
else:
self.rrc_sc_timer = int(values[1])
- self.anritsu.set_lte_rrc_status_change(True)
- self.anritsu.set_lte_rrc_status_change_timer(self.rrc_sc_timer)
+ self.simulator.anritsu.set_lte_rrc_status_change(True)
+ self.simulator.anritsu.set_lte_rrc_status_change_timer(
+ self.rrc_sc_timer)
# Get uplink power
@@ -775,9 +676,12 @@
# Setup the base station with the obtained configuration and then save
# these parameters in the current configuration object
- self.configure_bts(self.bts1, new_config)
+ self.simulator.configure_bts(new_config)
self.primary_config.incorporate(new_config)
+ # Now that the band is set, calibrate the link if necessary
+ self.load_pathloss_if_required()
+
def calibrated_downlink_rx_power(self, bts_config, rsrp):
""" LTE simulation overrides this method so that it can convert from
RSRP to total signal power transmitted from the basestation.
@@ -796,9 +700,7 @@
# Use parent method to calculate signal level
return super().calibrated_downlink_rx_power(bts_config, power)
- def downlink_calibration(self,
- rat=None,
- power_units_conversion_func=None):
+ def downlink_calibration(self, rat=None, power_units_conversion_func=None):
""" Computes downlink path loss and returns the calibration value.
See base class implementation for details.
@@ -871,11 +773,11 @@
Maximum throughput in mbps.
"""
- if bts_config.mimo_mode == LteSimulation.MimoMode.MIMO_1x1:
+ if bts_config.mimo_mode == MimoMode.MIMO_1x1:
streams = 1
- elif bts_config.mimo_mode == LteSimulation.MimoMode.MIMO_2x2:
+ elif bts_config.mimo_mode == MimoMode.MIMO_2x2:
streams = 1
- elif bts_config.mimo_mode == LteSimulation.MimoMode.MIMO_4x4:
+ elif bts_config.mimo_mode == MimoMode.MIMO_4x4:
streams = 1
else:
raise ValueError('Unable to calculate maximum downlink throughput '
@@ -890,25 +792,29 @@
tdd_subframe_config = bts_config.dlul_config
duplex_mode = self.get_duplex_mode(bts_config.band)
- if duplex_mode == self.DuplexMode.TDD.value:
+ if duplex_mode == DuplexMode.TDD.value:
if self.dl_256_qam:
if mcs == "27":
if bts_config.tbs_pattern_on:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG3'][tdd_subframe_config][bandwidth]['DL']
+ 'TDD_CONFIG3'][tdd_subframe_config][bandwidth][
+ 'DL']
else:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG2'][tdd_subframe_config][bandwidth]['DL']
+ 'TDD_CONFIG2'][tdd_subframe_config][bandwidth][
+ 'DL']
else:
if mcs == "28":
if bts_config.tbs_pattern_on:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG4'][tdd_subframe_config][bandwidth]['DL']
+ 'TDD_CONFIG4'][tdd_subframe_config][bandwidth][
+ 'DL']
else:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG1'][tdd_subframe_config][bandwidth]['DL']
+ 'TDD_CONFIG1'][tdd_subframe_config][bandwidth][
+ 'DL']
- elif duplex_mode == self.DuplexMode.FDD.value:
+ elif duplex_mode == DuplexMode.FDD.value:
if (not self.dl_256_qam and bts_config.tbs_pattern_on
and mcs == "28"):
max_rate_per_stream = {
@@ -919,7 +825,7 @@
20: 72.2
}.get(bandwidth, None)
if (not self.dl_256_qam and bts_config.tbs_pattern_on
- and mcs == "27"):
+ and mcs == "27"):
max_rate_per_stream = {
1.4: 2.94,
}.get(bandwidth, None)
@@ -1001,25 +907,29 @@
tdd_subframe_config = bts_config.dlul_config
duplex_mode = self.get_duplex_mode(bts_config.band)
- if duplex_mode == self.DuplexMode.TDD.value:
+ if duplex_mode == DuplexMode.TDD.value:
if self.ul_64_qam:
if mcs == "28":
if bts_config.tbs_pattern_on:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG3'][tdd_subframe_config][bandwidth]['UL']
+ 'TDD_CONFIG3'][tdd_subframe_config][bandwidth][
+ 'UL']
else:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG2'][tdd_subframe_config][bandwidth]['UL']
+ 'TDD_CONFIG2'][tdd_subframe_config][bandwidth][
+ 'UL']
else:
if mcs == "23":
if bts_config.tbs_pattern_on:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG4'][tdd_subframe_config][bandwidth]['UL']
+ 'TDD_CONFIG4'][tdd_subframe_config][bandwidth][
+ 'UL']
else:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
- 'TDD_CONFIG1'][tdd_subframe_config][bandwidth]['UL']
+ 'TDD_CONFIG1'][tdd_subframe_config][bandwidth][
+ 'UL']
- elif duplex_mode == self.DuplexMode.FDD.value:
+ elif duplex_mode == DuplexMode.FDD.value:
if mcs == "23" and not self.ul_64_qam:
max_rate_per_stream = {
1.4: 2.85,
@@ -1047,132 +957,6 @@
return max_rate_per_stream * rb_ratio
- def set_transmission_mode(self, bts, tmode):
- """ Sets the transmission mode for the LTE basetation
-
- Args:
- bts: basestation handle
- tmode: Enum list from class 'TransmissionModeLTE'
- """
-
- # If the selected transmission mode does not support the number of DL
- # antennas, throw an exception.
- if (tmode in [self.TransmissionMode.TM1, self.TransmissionMode.TM7]
- and bts.dl_antenna != '1'):
- # TM1 and TM7 only support 1 DL antenna
- raise ValueError("{} allows only one DL antenna. Change the "
- "number of DL antennas before setting the "
- "transmission mode.".format(tmode.value))
- elif tmode == self.TransmissionMode.TM8 and bts.dl_antenna != '2':
- # TM8 requires 2 DL antennas
- raise ValueError("TM2 requires two DL antennas. Change the "
- "number of DL antennas before setting the "
- "transmission mode.")
- elif (tmode in [
- self.TransmissionMode.TM2, self.TransmissionMode.TM3,
- self.TransmissionMode.TM4, self.TransmissionMode.TM9
- ] and bts.dl_antenna == '1'):
- # TM2, TM3, TM4 and TM9 require 2 or 4 DL antennas
- raise ValueError("{} requires at least two DL atennas. Change the "
- "number of DL antennas before setting the "
- "transmission mode.".format(tmode.value))
-
- # The TM mode is allowed for the current number of DL antennas, so it
- # is safe to change this setting now
- bts.transmode = tmode.value
-
- time.sleep(5) # It takes some time to propagate the new settings
-
- def set_mimo_mode(self, bts, mimo):
- """ Sets the number of DL antennas for the desired MIMO mode.
-
- Args:
- bts: basestation handle
- mimo: object of class MimoMode
- """
-
- # If the requested mimo mode is not compatible with the current TM,
- # warn the user before changing the value.
-
- if mimo == self.MimoMode.MIMO_1x1:
- if bts.transmode not in [
- self.TransmissionMode.TM1, self.TransmissionMode.TM7
- ]:
- self.log.warning(
- "Using only 1 DL antennas is not allowed with "
- "the current transmission mode. Changing the "
- "number of DL antennas will override this "
- "setting.")
- bts.dl_antenna = 1
- elif mimo == self.MimoMode.MIMO_2x2:
- if bts.transmode not in [
- self.TransmissionMode.TM2, self.TransmissionMode.TM3,
- self.TransmissionMode.TM4, self.TransmissionMode.TM8,
- self.TransmissionMode.TM9
- ]:
- self.log.warning("Using two DL antennas is not allowed with "
- "the current transmission mode. Changing the "
- "number of DL antennas will override this "
- "setting.")
- bts.dl_antenna = 2
- elif mimo == self.MimoMode.MIMO_4x4:
- if bts.transmode not in [
- self.TransmissionMode.TM2, self.TransmissionMode.TM3,
- self.TransmissionMode.TM4, self.TransmissionMode.TM9
- ]:
- self.log.warning("Using four DL antennas is not allowed with "
- "the current transmission mode. Changing the "
- "number of DL antennas will override this "
- "setting.")
-
- bts.dl_antenna = 4
- else:
- RuntimeError("The requested MIMO mode is not supported.")
-
- def set_scheduling_mode(self,
- bts,
- scheduling,
- packet_rate=None,
- mcs_dl=None,
- mcs_ul=None,
- nrb_dl=None,
- nrb_ul=None):
- """ Sets the scheduling mode for LTE
-
- Args:
- bts: basestation handle
- scheduling: DYNAMIC or STATIC scheduling (Enum list)
- mcs_dl: Downlink MCS (only for STATIC scheduling)
- mcs_ul: Uplink MCS (only for STATIC scheduling)
- nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
- nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
- """
-
- bts.lte_scheduling_mode = scheduling.value
-
- if scheduling == self.SchedulingMode.STATIC:
-
- if not packet_rate:
- raise RuntimeError("Packet rate needs to be indicated when "
- "selecting static scheduling.")
-
- bts.packet_rate = packet_rate
-
- if packet_rate == BtsPacketRate.LTE_MANUAL:
-
- if not (mcs_dl and mcs_ul and nrb_dl and nrb_ul):
- raise RuntimeError("When using manual packet rate the "
- "number of dl/ul RBs and the dl/ul "
- "MCS needs to be indicated with the "
- "optional arguments.")
-
- bts.lte_mcs_dl = mcs_dl
- bts.lte_mcs_ul = mcs_ul
- bts.nrb_dl = nrb_dl
- bts.nrb_ul = nrb_ul
-
- time.sleep(5) # It takes some time to propagate the new settings
-
def allocation_percentages_to_rbs(self, bw, tm, dl, ul):
""" Converts usage percentages to number of DL/UL RBs
@@ -1217,10 +1001,11 @@
# Get the number of DL RBs that corresponds to
# the required percentage.
- desired_dl_rbs = percentage_to_amount(
- min_val=min_dl_rbs, max_val=max_rbs, percentage=dl)
+ desired_dl_rbs = percentage_to_amount(min_val=min_dl_rbs,
+ max_val=max_rbs,
+ percentage=dl)
- if tm == self.TransmissionMode.TM3 or tm == self.TransmissionMode.TM4:
+ if tm == TransmissionMode.TM3 or tm == TransmissionMode.TM4:
# For TM3 and TM4 the number of DL RBs needs to be max_rbs or a
# multiple of the RBG size
@@ -1239,8 +1024,9 @@
# Get the number of UL RBs that corresponds
# to the required percentage
- desired_ul_rbs = percentage_to_amount(
- min_val=min_ul_rbs, max_val=max_rbs, percentage=ul)
+ desired_ul_rbs = percentage_to_amount(min_val=min_ul_rbs,
+ max_val=max_rbs,
+ percentage=ul)
# Create a list of all possible UL RBs assignment
# The standard allows any number that can be written as
@@ -1270,60 +1056,6 @@
return dl_rbs, ul_rbs
- def set_channel_bandwidth(self, bts, bandwidth):
- """ Sets the LTE channel bandwidth (MHz)
-
- Args:
- bts: basestation handle
- bandwidth: desired bandwidth (MHz)
- """
- if bandwidth == 20:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_20MHz
- elif bandwidth == 15:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_15MHz
- elif bandwidth == 10:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_10MHz
- elif bandwidth == 5:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_5MHz
- elif bandwidth == 3:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_3MHz
- elif bandwidth == 1.4:
- bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_1dot4MHz
- else:
- msg = "Bandwidth = {} MHz is not valid for LTE".format(bandwidth)
- self.log.error(msg)
- raise ValueError(msg)
- time.sleep(5) # It takes some time to propagate the new settings
-
- def get_bandwidth(self, bts):
- """ Obtains bandwidth in MHz for a base station. The Anritsu callbox
- returns a string that needs to be mapped to the right number.
-
- Args:
- bts: base station handle
-
- Returns:
- the channel bandwidth in MHz
- """
-
- return BtsBandwidth.get_float_value(bts.bandwidth)
-
- def set_dlul_configuration(self, bts, config):
- """ Sets the frame structure for TDD bands.
-
- Args:
- config: the desired frame structure. An int between 0 and 6.
- """
-
- if not 0 <= config <= 6:
- raise ValueError("The frame structure configuration has to be a "
- "number between 0 and 6")
-
- bts.uldl_configuration = config
-
- # Wait for the setting to propagate
- time.sleep(5)
-
def calibrate(self, band):
""" Calculates UL and DL path loss if it wasn't done before
@@ -1342,17 +1074,17 @@
# Set up a temporary calibration configuration.
temporary_config = self.BtsConfig()
- temporary_config.mimo_mode = LteSimulation.MimoMode.MIMO_1x1
- temporary_config.transmission_mode = LteSimulation.TransmissionMode.TM1
+ temporary_config.mimo_mode = MimoMode.MIMO_1x1
+ temporary_config.transmission_mode = TransmissionMode.TM1
temporary_config.bandwidth = max(
self.allowed_bandwidth_dictionary[int(band)])
- self.configure_bts(self.bts1, temporary_config)
+ self.simulator.configure_bts(temporary_config)
self.primary_config.incorporate(temporary_config)
super().calibrate(band)
# Restore values as they were before changing them for calibration.
- self.configure_bts(self.bts1, restore_config)
+ self.simulator.configure_bts(restore_config)
self.primary_config.incorporate(restore_config)
def start_traffic_for_calibration(self):
@@ -1380,19 +1112,6 @@
"""
if 33 <= int(band) <= 46:
- return self.DuplexMode.TDD
+ return DuplexMode.TDD
else:
- return self.DuplexMode.FDD
-
- def set_band(self, bts, band, calibrate_if_necessary=True):
- """ Sets the right duplex mode before switching to a new band.
-
- Args:
- bts: basestation handle
- band: desired band
- calibrate_if_necessary: if False calibration will be skipped
- """
-
- bts.duplex_mode = self.get_duplex_mode(band).value
-
- super().set_band(bts, band, calibrate_if_necessary)
+ return DuplexMode.FDD
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
index d136f84..4d4aeeb 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
@@ -15,17 +15,17 @@
# limitations under the License.
import ntpath
+import time
from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsusim
+from acts.controllers.anritsu_lib.md8475a import BtsNumber
from acts.controllers.anritsu_lib.md8475a import BtsPacketRate
from acts.test_utils.power.tel_simulations.BaseSimulation import BaseSimulation
from acts.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
class UmtsSimulation(BaseSimulation):
- """ Simple UMTS simulation with only one basestation.
-
- """
+ """ Single base station simulation. """
# Simulation config files in the callbox computer.
# These should be replaced in the future by setting up
@@ -90,7 +90,7 @@
}
def __init__(self, simulator, log, dut, test_config, calibration_table):
- """ Configures Anritsu system for UMTS simulation with 1 basetation
+ """ Initializes the cellular simulator for a UMTS simulation.
Loads a simple UMTS simulation enviroment with 1 basestation. It also
creates the BTS handle so we can change the parameters as desired.
@@ -104,15 +104,18 @@
different bands.
"""
-
- super().__init__(simulator, log, dut, test_config, calibration_table)
-
# The UMTS simulation relies on the cellular simulator to be a MD8475
if not isinstance(self.simulator, anritsusim.MD8475CellularSimulator):
raise ValueError('The UMTS simulation relies on the simulator to '
'be an Anritsu MD8475 A/B instrument.')
+ # The Anritsu controller needs to be unwrapped before calling
+ # super().__init__ because setup_simulator() requires self.anritsu and
+ # will be called during the parent class initialization.
self.anritsu = self.simulator.anritsu
+ self.bts1 = self.anritsu.get_BTS(BtsNumber.BTS1)
+
+ super().__init__(simulator, log, dut, test_config, calibration_table)
if not dut.droid.telephonySetPreferredNetworkTypesForSubscription(
NETWORK_MODE_WCDMA_ONLY,
@@ -124,11 +127,18 @@
self.release_version = None
self.packet_rate = None
- def load_config_files(self):
- """ Loads configuration files for the simulation. """
+ def setup_simulator(self):
+ """ Do initial configuration in the simulator. """
+
+ # Load callbox config files
+ callbox_config_path = self.CALLBOX_PATH_FORMAT_STR.format(
+ self.anritsu._md8475_version)
self.anritsu.load_simulation_paramfile(
- ntpath.join(self.callbox_config_path, self.UMTS_BASIC_SIM_FILE))
+ ntpath.join(callbox_config_path, self.UMTS_BASIC_SIM_FILE))
+
+ # Start simulation if it wasn't started
+ self.anritsu.start_simulation()
def parse_parameters(self, parameters):
""" Configs an UMTS simulation using a list of parameters.
@@ -149,6 +159,7 @@
"the required band number.".format(self.PARAM_BAND))
self.set_band(self.bts1, values[1])
+ self.load_pathloss_if_required()
# Setup release version
@@ -279,3 +290,14 @@
# Stop IP traffic after setting the signal level
self.stop_traffic_for_calibration()
+
+ def set_band(self, bts, band):
+ """ Sets the band used for communication.
+
+ Args:
+ bts: basestation handle
+ band: desired band
+ """
+
+ bts.band = band
+ time.sleep(5) # It takes some time to propagate the new band
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/__init__.py b/acts/framework/acts/test_utils/power/tel_simulations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/acts/test_utils/power/tel_simulations/__init__.py
diff --git a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
index dbdcf7f..b4b40ed 100644
--- a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
+++ b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
@@ -103,7 +103,7 @@
self.test_id = test_id
self.result_detail = ""
self.testsignal_details = ""
- self.testsignal_extras = ""
+ self.testsignal_extras = {}
tries = int(self.user_params.get("telephony_auto_rerun", 1))
for ad in self.android_devices:
ad.log_path = self.log_path
diff --git a/acts/framework/acts/test_utils/tel/tel_test_utils.py b/acts/framework/acts/test_utils/tel/tel_test_utils.py
index 0c26235..a4cb3f2 100644
--- a/acts/framework/acts/test_utils/tel/tel_test_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_test_utils.py
@@ -1567,6 +1567,9 @@
else:
return True
finally:
+ if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
+ ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
+ ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
ad.droid.telecomShowInCallScreen()
@@ -3216,7 +3219,7 @@
def phone_switch_to_msim_mode(ad, retries=3, timeout=60):
result = False
if not ad.is_apk_installed("com.google.mdstest"):
- raise signals.TestSkipClass("mdstest is not installed")
+ raise signals.TestAbortClass("mdstest is not installed")
mode = ad.droid.telephonyGetPhoneCount()
if mode == 2:
ad.log.info("Device already in MSIM mode")
@@ -3259,7 +3262,7 @@
def phone_switch_to_ssim_mode(ad, retries=3, timeout=30):
result = False
if not ad.is_apk_installed("com.google.mdstest"):
- raise signals.TestSkipClass("mdstest is not installed")
+ raise signals.TestAbortClass("mdstest is not installed")
mode = ad.droid.telephonyGetPhoneCount()
if mode == 1:
ad.log.info("Device already in SSIM mode")
@@ -3738,17 +3741,18 @@
If None, opposite of the current state.
"""
- # TODO: b/26293960 No framework API available to set IMS by SubId.
- if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
- ad.log.info("Enhanced 4G Lte Mode Setting is not enabled by platform.")
- return False
- current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
+ current_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
if new_state is None:
new_state = not current_state
if new_state != current_state:
- ad.log.info("Toggle Enhanced 4G LTE Mode from %s to %s", current_state,
- new_state)
- ad.droid.imsSetEnhanced4gMode(new_state)
+ ad.log.info("Toggle Enhanced 4G LTE Mode from %s to %s on sub_id %s", current_state,
+ new_state, sub_id)
+ ad.droid.imsMmTelSetAdvancedCallingEnabled(sub_id, new_state)
+ check_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
+ if check_state != new_state:
+ ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, still set to %s on sub_id %s",
+ new_state, check_state, sub_id)
+ return False
return True
@@ -6660,7 +6664,7 @@
if ad.is_sl4a_installed():
break
ad.log.info("Re-install sl4a")
- ad.adb.shell("settings put global package_verifier_enable 0")
+ ad.adb.shell("settings put global verifier_verify_adb_installs 0")
ad.adb.install("-r /tmp/base.apk")
time.sleep(10)
break
diff --git a/acts/framework/acts/test_utils/wifi/wifi_performance_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_performance_test_utils.py
index e71748e..18c50a5 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_performance_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_performance_test_utils.py
@@ -16,6 +16,8 @@
import bokeh, bokeh.plotting
import collections
+import itertools
+import json
import logging
import math
import re
@@ -185,102 +187,6 @@
self.llstats_cumulative)
-# Dashboard utilities
-class BlackboxMappedMetricLogger(MetricLogger):
- """A MetricLogger for logging and publishing Blackbox metrics from a dict.
-
- The dict maps the metric name to the metric value. For additional
- information on reporting to Blackbox, see BlackBoxMetricLogger.
-
- Attributes:
- proto_module: The proto module for ActsBlackboxMetricResult.
- metric_key: The metric key to use. If unset, the logger will use the
- context's identifier.
- """
-
- PROTO_FILE = '../../metrics/loggers/protos/acts_blackbox.proto'
-
- def __init__(self, metric_key=None, event=None):
- """Initializes a logger for Blackbox metrics.
-
- Args:
- metric_key: The metric key to use. If unset, the logger will use
- the context's identifier.
- event: The event triggering the creation of this logger.
- """
- super().__init__(event=event)
- self.proto_module = self._compile_proto(self.PROTO_FILE)
- self.metric_key = metric_key
- self._metric_map = {}
-
- def _get_metric_key(self, metric_name):
- """Gets the metric key to use.
-
- If the metric_key is explicitly set, returns that value. Otherwise,
- extracts an identifier from the context.
-
- Args:
- metric_name: The name of the metric to report.
- """
- if self.metric_key:
- key = self.metric_key
- else:
- key = self._get_blackbox_identifier()
- key = '%s.%s' % (key, metric_name)
- return key
-
- def set_metric_data(self, metric_map):
- """Sets the map of metrics to be uploaded to Blackbox. Note that
- this will overwrite all existing added by this function or add_metric.
-
- Args:
- metric_map: the map of metric_name -> metric_value to publish
- to blackbox. If the metric value is set to None, the
- metric will not be reported.
- """
- self._metric_map = metric_map
-
- def add_metric(self, metric_name, metric_value):
- """Adds a metric value to be published later.
-
- Note that if the metric name has already been added, the metric value
- will be overwritten.
-
- Args:
- metric_name: the name of the metric.
- metric_value: the value of the metric.
- """
- self._metric_map[metric_name] = metric_value
-
- def _get_blackbox_identifier(self):
- """Returns the testcase identifier, as expected by Blackbox."""
- # b/119787228: Blackbox requires function names to look like Java
- # functions.
- identifier = self.context.identifier
- parts = identifier.rsplit('.', 1)
- return '#'.join(parts)
-
- def end(self, _):
- """Creates and publishes a ProtoMetric with blackbox data.
-
- Builds a list of ActsBlackboxMetricResult messages from the set
- metric data, and sends them to the publisher.
- """
- metrics = []
- for metric_name, metric_value in self._metric_map.items():
- if metric_value is None:
- continue
- result = self.proto_module.ActsBlackboxMetricResult()
- result.test_identifier = self._get_blackbox_identifier()
- result.metric_key = self._get_metric_key(metric_name)
- result.metric_value = metric_value
-
- metrics.append(
- ProtoMetric(name='blackbox_%s' % metric_name, data=result))
-
- return self.publisher.publish(metrics)
-
-
# JSON serializer
def serialize_dict(input_dict):
"""Function to serialize dicts to enable JSON output"""
@@ -343,23 +249,23 @@
def __init__(self,
title=None,
x_label=None,
- primary_y=None,
- secondary_y=None,
+ primary_y_label=None,
+ secondary_y_label=None,
height=700,
width=1300,
- title_size=15,
- axis_label_size=12):
+ title_size='15pt',
+ axis_label_size='12pt'):
self.figure_data = []
self.fig_property = {
'title': title,
'x_label': x_label,
- 'primary_y_label': primary_y,
- 'secondary_y_label': secondary_y,
+ 'primary_y_label': primary_y_label,
+ 'secondary_y_label': secondary_y_label,
'num_lines': 0,
'height': height,
'width': width,
- 'title_size': '{}pt'.format(title_size),
- 'axis_label_size': '{}pt'.format(axis_label_size)
+ 'title_size': title_size,
+ 'axis_label_size': axis_label_size
}
self.TOOLS = (
'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
@@ -382,6 +288,18 @@
self.plot.add_tools(
bokeh.models.tools.WheelZoomTool(dimensions='height'))
+ def _filter_line(self, x_data, y_data, hover_text=None):
+ """Function to remove NaN points from bokeh plots."""
+ x_data_filtered = []
+ y_data_filtered = []
+ hover_text_filtered = []
+ for x, y, hover in itertools.zip_longest(x_data, y_data, hover_text):
+ if not math.isnan(y):
+ x_data_filtered.append(x)
+ y_data_filtered.append(y)
+ hover_text_filtered.append(hover)
+ return x_data_filtered, y_data_filtered, hover_text_filtered
+
def add_line(self,
x_data,
y_data,
@@ -417,18 +335,20 @@
style = [5, 5]
if not hover_text:
hover_text = ['y={}'.format(y) for y in y_data]
+ x_data_filter, y_data_filter, hover_text_filter = self._filter_line(
+ x_data, y_data, hover_text)
self.figure_data.append({
- 'x_data': x_data,
- 'y_data': y_data,
+ 'x_data': x_data_filter,
+ 'y_data': y_data_filter,
'legend': legend,
- 'hover_text': hover_text,
+ 'hover_text': hover_text_filter,
'color': color,
'width': width,
'style': style,
'marker': marker,
'marker_size': marker_size,
'shaded_region': shaded_region,
- 'y_range_name': y_axis
+ 'y_axis': y_axis
})
self.fig_property['num_lines'] += 1
@@ -473,7 +393,7 @@
'marker': marker,
'marker_size': marker_size,
'shaded_region': None,
- 'y_range_name': y_axis
+ 'y_axis': y_axis
})
self.fig_property['num_lines'] += 1
@@ -499,8 +419,8 @@
line_width=line['width'],
color=line['color'],
line_dash=line['style'],
- name=line['y_range_name'],
- y_range_name=line['y_range_name'],
+ name=line['y_axis'],
+ y_range_name=line['y_axis'],
source=source)
if line['shaded_region']:
band_x = line['shaded_region']['x_vector']
@@ -522,10 +442,10 @@
legend=line['legend'],
line_color=line['color'],
fill_color=line['color'],
- name=line['y_range_name'],
- y_range_name=line['y_range_name'],
+ name=line['y_axis'],
+ y_range_name=line['y_axis'],
source=source)
- if line['y_range_name'] == 'secondary':
+ if line['y_axis'] == 'secondary':
two_axes = True
#x-axis formatting
@@ -554,10 +474,20 @@
self.plot.title.text_font_size = self.fig_property['title_size']
if output_file is not None:
- bokeh.plotting.output_file(output_file)
- bokeh.plotting.save(self.plot)
+ self.save_figure(output_file)
return self.plot
+ def _save_figure_json(self, output_file):
+ """Function to save a json format of a figure"""
+ figure_dict = collections.OrderedDict(
+ fig_property=self.fig_property,
+ figure_data=self.figure_data,
+ tools=self.TOOLS,
+ tooltips=self.TOOLTIPS)
+ output_file = output_file.replace('.html', '_plot_data.json')
+ with open(output_file, 'w') as outfile:
+ json.dump(figure_dict, outfile, indent=4)
+
def save_figure(self, output_file):
"""Function to save BokehFigure.
@@ -566,6 +496,7 @@
"""
bokeh.plotting.output_file(output_file)
bokeh.plotting.save(self.plot)
+ self._save_figure_json(output_file)
@staticmethod
def save_figures(figure_array, output_file_path):
@@ -575,8 +506,11 @@
figure_array: list of BokehFigure object to be plotted
output_file: string specifying output file path
"""
- for figure in figure_array:
+ for idx, figure in enumerate(figure_array):
figure.generate_figure()
+ json_file_path = output_file_path.replace(
+ '.html', '{}-plot_data.json'.format(idx))
+ figure._save_figure_json(json_file_path)
plot_array = [figure.plot for figure in figure_array]
all_plots = bokeh.layouts.column(children=plot_array)
bokeh.plotting.output_file(output_file_path)
@@ -709,23 +643,22 @@
Returns:
ping_result: dict containing ping results and other meta data
"""
- ping_count = int(ping_duration/ping_interval)
- ping_deadline = int(ping_count*ping_interval)+1
+ ping_count = int(ping_duration / ping_interval)
+ ping_deadline = int(ping_count * ping_interval) + 1
ping_cmd = 'ping -c {} -w {} -i {} -s {} -D'.format(
ping_count,
ping_deadline,
ping_interval,
ping_size,
)
- start_time = time.time()
if isinstance(src_device, AndroidDevice):
ping_cmd = '{} {}'.format(ping_cmd, dest_address)
ping_output = src_device.adb.shell(
- ping_cmd, timeout=ping_deadline+SHORT_SLEEP, ignore_status=True)
+ ping_cmd, timeout=ping_deadline + SHORT_SLEEP, ignore_status=True)
elif isinstance(src_device, ssh.connection.SshConnection):
ping_cmd = 'sudo {} {}'.format(ping_cmd, dest_address)
ping_output = src_device.run(
- ping_cmd, timeout=ping_deadline+SHORT_SLEEP,
+ ping_cmd, timeout=ping_deadline + SHORT_SLEEP,
ignore_status=True).stdout
else:
raise TypeError(
diff --git a/acts/framework/tests/acts_test_decorators_test.py b/acts/framework/tests/acts_test_decorators_test.py
index 7d98d49..f491302 100644
--- a/acts/framework/tests/acts_test_decorators_test.py
+++ b/acts/framework/tests/acts_test_decorators_test.py
@@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import shutil
import tempfile
import unittest
@@ -90,26 +91,26 @@
class TestDecoratorIntegrationTests(unittest.TestCase):
- MOCK_CONFIG = {
- "testbed": {
- "name": "SampleTestBed",
- },
- "logpath": tempfile.mkdtemp(),
- "cli_args": None,
- "testpaths": ["./"],
- }
+ @classmethod
+ def setUpClass(cls):
+ cls.MOCK_CONFIG = {
+ "testbed": {
+ "name": "SampleTestBed",
+ },
+ "logpath": tempfile.mkdtemp(),
+ "cli_args": None,
+ "testpaths": ["./"],
+ }
- MOCK_TEST_RUN_LIST = [(MockTest.__name__, [MockTest.TEST_CASE_LIST])]
-
- def setUp(self):
- pass
+ cls.MOCK_TEST_RUN_LIST = [(MockTest.__name__,
+ [MockTest.TEST_CASE_LIST])]
def _run_with_test_logic(self, func):
if hasattr(MockTest, MockTest.TEST_LOGIC_ATTR):
delattr(MockTest, MockTest.TEST_LOGIC_ATTR)
setattr(MockTest, MockTest.TEST_LOGIC_ATTR, func)
- self.test_runner = test_runner.TestRunner(TestDecoratorIntegrationTests.MOCK_CONFIG,
- TestDecoratorIntegrationTests.MOCK_TEST_RUN_LIST)
+ self.test_runner = test_runner.TestRunner(self.MOCK_CONFIG,
+ self.MOCK_TEST_RUN_LIST)
self.test_runner.run(MockTest)
def _validate_results_has_extra(self, result, extra_key, extra_value):
@@ -127,6 +128,10 @@
self._run_with_test_logic(raise_generic)
self._validate_results_has_extra(self.test_runner.results, UUID_KEY, TEST_TRACKER_UUID)
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.MOCK_CONFIG['logpath'])
+
if __name__ == "__main__":
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/acts/framework/tests/acts_test_runner_test.py b/acts/framework/tests/acts_test_runner_test.py
index e8599a7..4769fd7 100755
--- a/acts/framework/tests/acts_test_runner_test.py
+++ b/acts/framework/tests/acts_test_runner_test.py
@@ -15,16 +15,17 @@
# limitations under the License.
import mock
+import os
import shutil
import tempfile
import unittest
from acts import keys
-from acts import signals
from acts import test_runner
import acts_android_device_test
import mock_controller
+import IntegrationTest
class ActsTestRunnerTest(unittest.TestCase):
@@ -35,14 +36,14 @@
def setUp(self):
self.tmp_dir = tempfile.mkdtemp()
self.base_mock_test_config = {
- "testbed": {
- "name": "SampleTestBed",
+ 'testbed': {
+ 'name': 'SampleTestBed',
},
- "logpath": self.tmp_dir,
- "cli_args": None,
- "testpaths": ["./"],
- "icecream": 42,
- "extra_param": "haha"
+ 'logpath': self.tmp_dir,
+ 'cli_args': None,
+ 'testpaths': [os.path.dirname(IntegrationTest.__file__)],
+ 'icecream': 42,
+ 'extra_param': 'haha'
}
self.mock_run_list = [('SampleTest', None)]
@@ -59,11 +60,11 @@
tb_key = keys.Config.key_testbed.value
mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
my_config = [{
- "serial": "xxxx",
- "magic": "Magic1"
+ 'serial': 'xxxx',
+ 'magic': 'Magic1'
}, {
- "serial": "xxxx",
- "magic": "Magic2"
+ 'serial': 'xxxx',
+ 'magic': 'Magic2'
}]
mock_test_config[tb_key][mock_ctrlr_config_name] = my_config
tr = test_runner.TestRunner(mock_test_config,
@@ -73,9 +74,9 @@
tr.run()
tr.stop()
results = tr.results.summary_dict()
- self.assertEqual(results["Requested"], 2)
- self.assertEqual(results["Executed"], 2)
- self.assertEqual(results["Passed"], 2)
+ self.assertEqual(results['Requested'], 2)
+ self.assertEqual(results['Executed'], 2)
+ self.assertEqual(results['Passed'], 2)
@mock.patch(
'acts.controllers.adb.AdbProxy',
@@ -84,7 +85,7 @@
'acts.controllers.fastboot.FastbootProxy',
return_value=acts_android_device_test.MockFastbootProxy(1))
@mock.patch(
- 'acts.controllers.android_device.list_adb_devices', return_value=["1"])
+ 'acts.controllers.android_device.list_adb_devices', return_value=['1'])
@mock.patch(
'acts.controllers.android_device.get_all_instances',
return_value=acts_android_device_test.get_mock_ads(1))
@@ -107,16 +108,16 @@
tb_key = keys.Config.key_testbed.value
mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
my_config = [{
- "serial": "xxxx",
- "magic": "Magic1"
+ 'serial': 'xxxx',
+ 'magic': 'Magic1'
}, {
- "serial": "xxxx",
- "magic": "Magic2"
+ 'serial': 'xxxx',
+ 'magic': 'Magic2'
}]
mock_test_config[tb_key][mock_ctrlr_config_name] = my_config
- mock_test_config[tb_key]["AndroidDevice"] = [{
- "serial": "1",
- "skip_sl4a": True
+ mock_test_config[tb_key]['AndroidDevice'] = [{
+ 'serial': '1',
+ 'skip_sl4a': True
}]
tr = test_runner.TestRunner(mock_test_config,
[('IntegrationTest', None),
@@ -124,10 +125,10 @@
tr.run()
tr.stop()
results = tr.results.summary_dict()
- self.assertEqual(results["Requested"], 2)
- self.assertEqual(results["Executed"], 2)
- self.assertEqual(results["Passed"], 2)
+ self.assertEqual(results['Requested'], 2)
+ self.assertEqual(results['Executed'], 2)
+ self.assertEqual(results['Passed'], 2)
-if __name__ == "__main__":
+if __name__ == '__main__':
unittest.main()
diff --git a/acts/framework/tests/config/unittest_bundle.py b/acts/framework/tests/config/unittest_bundle.py
index 8e26b93..87d5bc5 100755
--- a/acts/framework/tests/config/unittest_bundle.py
+++ b/acts/framework/tests/config/unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/config/', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/controllers/android_lib/android_lib_unittest_bundle.py b/acts/framework/tests/controllers/android_lib/android_lib_unittest_bundle.py
index 3a40d31..cf8e81e 100755
--- a/acts/framework/tests/controllers/android_lib/android_lib_unittest_bundle.py
+++ b/acts/framework/tests/controllers/android_lib/android_lib_unittest_bundle.py
@@ -14,14 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/controllers/android_lib',
- pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/event/event_bus_integration_test.py b/acts/framework/tests/event/event_bus_integration_test.py
index 7dadf40..c58727d 100755
--- a/acts/framework/tests/event/event_bus_integration_test.py
+++ b/acts/framework/tests/event/event_bus_integration_test.py
@@ -13,6 +13,7 @@
# 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 shutil
import tempfile
import unittest
from threading import RLock
@@ -65,6 +66,9 @@
TestClass.instance_event_received = []
TestClass.static_event_received = []
+ def tearDown(self):
+ shutil.rmtree(self.tmp_dir)
+
def test_test_class_subscribed_fn_receives_event(self):
"""Tests that TestClasses have their subscribed functions called."""
TestRunner(self.config, [('TestClass', [])]).run(TestClass)
diff --git a/acts/framework/tests/event/event_unittest_bundle.py b/acts/framework/tests/event/event_unittest_bundle.py
index b310cb5..56c3e09 100755
--- a/acts/framework/tests/event/event_unittest_bundle.py
+++ b/acts/framework/tests/event/event_unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/event', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/libs/logging/logging_unittest_bundle.py b/acts/framework/tests/libs/logging/logging_unittest_bundle.py
index 6f384ca..cf8e81e 100755
--- a/acts/framework/tests/libs/logging/logging_unittest_bundle.py
+++ b/acts/framework/tests/libs/logging/logging_unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/libs/logging', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/libs/metrics/unittest_bundle.py b/acts/framework/tests/libs/metrics/unittest_bundle.py
index 8bf7411..87d5bc5 100755
--- a/acts/framework/tests/libs/metrics/unittest_bundle.py
+++ b/acts/framework/tests/libs/metrics/unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/libs/metrics', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/libs/ota/unittest_bundle.py b/acts/framework/tests/libs/ota/unittest_bundle.py
index e0019f1..87d5bc5 100755
--- a/acts/framework/tests/libs/ota/unittest_bundle.py
+++ b/acts/framework/tests/libs/ota/unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/libs/ota', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/libs/proc/proc_unittest_bundle.py b/acts/framework/tests/libs/proc/proc_unittest_bundle.py
index 2a25587..cf8e81e 100755
--- a/acts/framework/tests/libs/proc/proc_unittest_bundle.py
+++ b/acts/framework/tests/libs/proc/proc_unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/libs/proc', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/metrics/loggers/blackbox_test.py b/acts/framework/tests/metrics/loggers/blackbox_test.py
index bda9cc3..d40b00d 100644
--- a/acts/framework/tests/metrics/loggers/blackbox_test.py
+++ b/acts/framework/tests/metrics/loggers/blackbox_test.py
@@ -13,18 +13,19 @@
# 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 warnings
-
-from mock import Mock
-from mock import patch
+import shutil
import tempfile
import unittest
+import warnings
from unittest import TestCase
+
from acts.base_test import BaseTestClass
from acts.metrics.loggers.blackbox import BlackboxMetricLogger
from acts.test_runner import TestRunner
+from mock import Mock
+from mock import patch
-COMPILE_IMPORT_PROTO = 'acts.metrics.logger.compile_import_proto'
+COMPILE_PROTO = 'acts.metrics.logger.MetricLogger._compile_proto'
GET_CONTEXT_FOR_EVENT = 'acts.metrics.logger.get_context_for_event'
PROTO_METRIC_PUBLISHER = 'acts.metrics.logger.ProtoMetricPublisher'
@@ -42,10 +43,10 @@
self.publisher = Mock()
self._get_blackbox_identifier = lambda: str(id(self.context))
- @patch(COMPILE_IMPORT_PROTO)
- def test_default_init_attributes(self, compile_import_proto):
+ @patch(COMPILE_PROTO)
+ def test_default_init_attributes(self, compile_proto):
metric_name = Mock()
- compile_import_proto.return_value = self.proto_module
+ compile_proto.return_value = self.proto_module
logger = BlackboxMetricLogger(metric_name)
@@ -53,8 +54,8 @@
self.assertEqual(logger.proto_module, self.proto_module)
self.assertIsNone(logger.metric_key)
- @patch(COMPILE_IMPORT_PROTO)
- def test_init_with_params(self, compile_import_proto):
+ @patch(COMPILE_PROTO)
+ def test_init_with_params(self, compile_proto):
metric_name = Mock()
metric_key = Mock()
@@ -64,9 +65,8 @@
@patch(PROTO_METRIC_PUBLISHER)
@patch(GET_CONTEXT_FOR_EVENT)
- @patch(COMPILE_IMPORT_PROTO)
- def test_init_with_event(self, compile_import_proto, get_context,
- publisher_cls):
+ @patch(COMPILE_PROTO)
+ def test_init_with_event(self, compile_proto, get_context, publisher_cls):
metric_name = Mock()
logger = BlackboxMetricLogger(metric_name, event=self.event)
@@ -74,10 +74,10 @@
self.assertIsNotNone(logger.context)
self.assertIsNotNone(logger.publisher)
- @patch(COMPILE_IMPORT_PROTO)
- def test_end_populates_result(self, compile_import_proto):
+ @patch(COMPILE_PROTO)
+ def test_end_populates_result(self, compile_proto):
result = Mock()
- compile_import_proto.return_value = self.proto_module
+ compile_proto.return_value = self.proto_module
self.proto_module.ActsBlackboxMetricResult.return_value = result
logger = BlackboxMetricLogger(self.TEST_METRIC_NAME)
@@ -93,12 +93,12 @@
'%s.%s' % ('Class#test', self.TEST_METRIC_NAME))
self.assertEqual(result.metric_value, logger.metric_value)
- @patch(COMPILE_IMPORT_PROTO)
+ @patch(COMPILE_PROTO)
def test_end_uses_metric_value_on_metric_value_not_none(
- self, compile_import_proto):
+ self, compile_proto):
result = Mock()
expected_result = Mock()
- compile_import_proto.return_value = self.proto_module
+ compile_proto.return_value = self.proto_module
self.proto_module.ActsBlackboxMetricResult.return_value = result
logger = BlackboxMetricLogger(self.TEST_METRIC_NAME)
@@ -110,10 +110,10 @@
self.assertEqual(result.metric_value, expected_result)
- @patch(COMPILE_IMPORT_PROTO)
- def test_end_uses_custom_metric_key(self, compile_import_proto):
+ @patch(COMPILE_PROTO)
+ def test_end_uses_custom_metric_key(self, compile_proto):
result = Mock()
- compile_import_proto.return_value = self.proto_module
+ compile_proto.return_value = self.proto_module
self.proto_module.ActsBlackboxMetricResult.return_value = result
metric_key = 'metric_key'
@@ -122,6 +122,7 @@
logger.context = self.context
logger.publisher = self.publisher
logger._get_blackbox_identifier = self._get_blackbox_identifier
+ logger.metric_value = 'foo'
logger.end(self.event)
@@ -129,10 +130,10 @@
self.assertEqual(result.metric_key, expected_metric_key)
@patch('acts.metrics.loggers.blackbox.ProtoMetric')
- @patch(COMPILE_IMPORT_PROTO)
- def test_end_does_publish(self, compile_import_proto, proto_metric_cls):
+ @patch(COMPILE_PROTO)
+ def test_end_does_publish(self, compile_proto, proto_metric_cls):
result = Mock()
- compile_import_proto.return_value = self.proto_module
+ compile_proto.return_value = self.proto_module
self.proto_module.ActsBlackboxMetricResult.return_value = result
metric_key = 'metric_key'
@@ -141,13 +142,26 @@
logger.context = self.context
logger.publisher = self.publisher
logger._get_blackbox_identifier = self._get_blackbox_identifier
+ logger.metric_value = 'foo'
logger.end(self.event)
proto_metric_cls.assert_called_once_with(
name=self.TEST_FILE_NAME, data=result)
self.publisher.publish.assert_called_once_with(
- proto_metric_cls.return_value)
+ [proto_metric_cls.return_value])
+
+
+class _BaseTestClassWithCleanup(BaseTestClass):
+ """Subclass of ACTS base test that generates a temp directory for
+ proto compiler output and cleans up upon exit.
+ """
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ self.proto_dir = tempfile.mkdtemp()
+
+ def __del__(self):
+ shutil.rmtree(self.proto_dir)
class BlackboxMetricLoggerIntegrationTest(TestCase):
@@ -179,17 +193,19 @@
runner.run()
runner.stop()
+ shutil.rmtree(config['logpath'])
return runner
@patch('acts.metrics.logger.ProtoMetricPublisher')
def test_test_case_metric(self, publisher_cls):
result = 5.0
- class MyTest(BaseTestClass):
+ class MyTest(_BaseTestClassWithCleanup):
def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ super().__init__(controllers)
self.tests = ('test_case', )
- self.metric = BlackboxMetricLogger.for_test_case('my_metric')
+ self.metric = BlackboxMetricLogger.for_test_case(
+ 'my_metric', compiler_out=self.proto_dir)
def test_case(self):
self.metric.metric_value = result
@@ -198,7 +214,7 @@
args_list = publisher_cls().publish.call_args_list
self.assertEqual(len(args_list), 1)
- metric = self.__get_only_arg(args_list[0])
+ metric = self.__get_only_arg(args_list[0])[0]
self.assertEqual(metric.name, 'blackbox_my_metric')
self.assertEqual(metric.data.test_identifier, 'MyTest#test_case')
self.assertEqual(metric.data.metric_key, 'MyTest#test_case.my_metric')
@@ -208,14 +224,16 @@
def test_multiple_test_case_metrics(self, publisher_cls):
result = 5.0
- class MyTest(BaseTestClass):
+ class MyTest(_BaseTestClassWithCleanup):
def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ super().__init__(controllers)
self.tests = ('test_case', )
self.metric_1 = (
- BlackboxMetricLogger.for_test_case('my_metric_1'))
+ BlackboxMetricLogger.for_test_case(
+ 'my_metric_1', compiler_out=self.proto_dir))
self.metric_2 = (
- BlackboxMetricLogger.for_test_case('my_metric_2'))
+ BlackboxMetricLogger.for_test_case(
+ 'my_metric_2', compiler_out=self.proto_dir))
def test_case(self):
self.metric_1.metric_value = result
@@ -225,7 +243,7 @@
args_list = publisher_cls().publish.call_args_list
self.assertEqual(len(args_list), 2)
- metrics = [self.__get_only_arg(args) for args in args_list]
+ metrics = [self.__get_only_arg(args)[0] for args in args_list]
self.assertEqual({metric.name
for metric in metrics},
{'blackbox_my_metric_1', 'blackbox_my_metric_2'})
@@ -242,21 +260,22 @@
def test_test_case_metric_with_custom_key(self, publisher_cls):
result = 5.0
- class MyTest(BaseTestClass):
+ class MyTest(_BaseTestClassWithCleanup):
def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ super().__init__(controllers)
self.tests = ('test_case', )
- BlackboxMetricLogger.for_test_case(
- 'my_metric', metric_key='my_metric_key')
+ self.metrics = BlackboxMetricLogger.for_test_case(
+ 'my_metric', metric_key='my_metric_key',
+ compiler_out=self.proto_dir)
def test_case(self):
- self.result = result
+ self.metrics.metric_value = result
self.run_acts_test(MyTest)
args_list = publisher_cls().publish.call_args_list
self.assertEqual(len(args_list), 1)
- metric = self.__get_only_arg(args_list[0])
+ metric = self.__get_only_arg(args_list[0])[0]
self.assertEqual(metric.data.metric_key, 'my_metric_key.my_metric')
@patch('acts.metrics.logger.ProtoMetricPublisher')
@@ -265,14 +284,15 @@
result_1 = 5.0
result_2 = 8.0
- class MyTest(BaseTestClass):
+ class MyTest(_BaseTestClassWithCleanup):
def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ super().__init__(controllers)
self.tests = (
'test_case_1',
'test_case_2',
)
- self.metric = BlackboxMetricLogger.for_test_class('my_metric')
+ self.metric = BlackboxMetricLogger.for_test_class(
+ 'my_metric', compiler_out=self.proto_dir)
def setup_class(self):
self.metric.metric_value = 0
@@ -287,7 +307,7 @@
args_list = publisher_cls().publish.call_args_list
self.assertEqual(len(args_list), 1)
- metric = self.__get_only_arg(args_list[0])
+ metric = self.__get_only_arg(args_list[0])[0]
self.assertEqual(metric.data.metric_value, result_1 + result_2)
self.assertEqual(metric.data.test_identifier, MyTest.__name__)
diff --git a/acts/framework/tests/metrics/unittest_bundle.py b/acts/framework/tests/metrics/unittest_bundle.py
index 9ba0bc5..56c3e09 100755
--- a/acts/framework/tests/metrics/unittest_bundle.py
+++ b/acts/framework/tests/metrics/unittest_bundle.py
@@ -14,13 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/metrics/', pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/framework/tests/test_utils/instrumentation/instrumentation_base_test_test.py b/acts/framework/tests/test_utils/instrumentation/instrumentation_base_test_test.py
index 04ac8e8..0a3ddde 100755
--- a/acts/framework/tests/test_utils/instrumentation/instrumentation_base_test_test.py
+++ b/acts/framework/tests/test_utils/instrumentation/instrumentation_base_test_test.py
@@ -29,11 +29,13 @@
'lvl2': {'file1': 'FILE'}
},
'MockController': {
- 'param1': 1
+ 'param1': 1,
+ 'param2': 4
},
'MockInstrumentationBaseTest': {
'MockController': {
- 'param2': 2
+ 'param2': 2,
+ 'param3': 5
},
'test_case': {
'MockController': {
@@ -83,21 +85,21 @@
controller config for the current test case.
"""
self.instrumentation_test.current_test_name = 'test_case'
- config = self.instrumentation_test._get_controller_config(
+ config = self.instrumentation_test._get_merged_config(
'MockController')
- self.assertNotIn('param1', config)
- self.assertNotIn('param2', config)
- self.assertIn('param3', config)
+ self.assertEqual(config.get('param1'), 1)
+ self.assertEqual(config.get('param2'), 2)
+ self.assertEqual(config.get('param3'), 3)
def test_get_controller_config_for_test_class(self):
"""Test that _get_controller_config returns the controller config for
the current test class (while no test case is running).
"""
- config = self.instrumentation_test._get_controller_config(
+ config = self.instrumentation_test._get_merged_config(
'MockController')
- self.assertIn('param1', config)
- self.assertIn('param2', config)
- self.assertNotIn('param3', config)
+ self.assertEqual(config.get('param1'), 1)
+ self.assertEqual(config.get('param2'), 2)
+ self.assertEqual(config.get('param3'), 5)
if __name__ == '__main__':
diff --git a/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py b/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py
index c929b65..d253cb3 100755
--- a/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py
+++ b/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py
@@ -14,14 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import sys
import unittest
def main():
suite = unittest.TestLoader().discover(
- start_dir='./acts/framework/tests/test_utils/instrumentation',
- pattern='*_test.py')
+ start_dir=os.path.dirname(__file__), pattern='*_test.py')
return suite
diff --git a/acts/tests/google/ble/api/BleAdvertiseApiTest.py b/acts/tests/google/ble/api/BleAdvertiseApiTest.py
index 2a6cb26..26c459f 100644
--- a/acts/tests/google/ble/api/BleAdvertiseApiTest.py
+++ b/acts/tests/google/ble/api/BleAdvertiseApiTest.py
@@ -35,8 +35,8 @@
class BleAdvertiseApiTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ad_dut = self.android_devices[0]
@BluetoothBaseTest.bt_test_wrap
diff --git a/acts/tests/google/ble/api/BleScanApiTest.py b/acts/tests/google/ble/api/BleScanApiTest.py
index 1398715..06f2362 100644
--- a/acts/tests/google/ble/api/BleScanApiTest.py
+++ b/acts/tests/google/ble/api/BleScanApiTest.py
@@ -47,8 +47,8 @@
class BleScanApiTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ad_dut = self.android_devices[0]
def _format_defaults(self, input):
diff --git a/acts/tests/google/ble/api/GattApiTest.py b/acts/tests/google/ble/api/GattApiTest.py
index 5444e51..cc87979 100644
--- a/acts/tests/google/ble/api/GattApiTest.py
+++ b/acts/tests/google/ble/api/GattApiTest.py
@@ -24,11 +24,10 @@
class GattApiTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ad = self.android_devices[0]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
def setup_test(self):
diff --git a/acts/tests/google/ble/beacon_tests/BeaconSwarmTest.py b/acts/tests/google/ble/beacon_tests/BeaconSwarmTest.py
index 9ebfe1e..0df9a7b 100644
--- a/acts/tests/google/ble/beacon_tests/BeaconSwarmTest.py
+++ b/acts/tests/google/ble/beacon_tests/BeaconSwarmTest.py
@@ -41,10 +41,6 @@
advertising_device_name_list = []
discovered_mac_address_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
- self.scn_ad = self.android_devices[0]
-
def setup_test(self):
self.discovered_mac_address_list = []
for a in self.android_devices:
@@ -56,6 +52,7 @@
return True
def setup_class(self):
+ self.scn_ad = self.android_devices[0]
if not setup_multiple_devices_for_bt_test(self.android_devices):
return False
return self._start_special_advertisements()
diff --git a/acts/tests/google/ble/bt5/AdvertisingSetTest.py b/acts/tests/google/ble/bt5/AdvertisingSetTest.py
index 66b0028..de4192f 100644
--- a/acts/tests/google/ble/bt5/AdvertisingSetTest.py
+++ b/acts/tests/google/ble/bt5/AdvertisingSetTest.py
@@ -62,14 +62,12 @@
]
}
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
- self.adv_ad = self.android_devices[0]
-
def setup_class(self):
super(AdvertisingSetTest, self).setup_class()
+ self.adv_ad = self.android_devices[0]
+
if not self.adv_ad.droid.bluetoothIsLeExtendedAdvertisingSupported():
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Advertiser does not support LE Extended Advertising")
def teardown_test(self):
diff --git a/acts/tests/google/ble/bt5/Bt5ScanTest.py b/acts/tests/google/ble/bt5/Bt5ScanTest.py
index e4cf4c5..e2c9c83 100644
--- a/acts/tests/google/ble/bt5/Bt5ScanTest.py
+++ b/acts/tests/google/ble/bt5/Bt5ScanTest.py
@@ -60,19 +60,17 @@
]
}
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(Bt5ScanTest, self).setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
- def setup_class(self):
- super(Bt5ScanTest, self).setup_class()
if not self.scn_ad.droid.bluetoothIsLeExtendedAdvertisingSupported():
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Scanner does not support LE Extended Advertising")
if not self.adv_ad.droid.bluetoothIsLeExtendedAdvertisingSupported():
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Advertiser does not support LE Extended Advertising")
def teardown_test(self):
diff --git a/acts/tests/google/ble/bt5/PhyTest.py b/acts/tests/google/ble/bt5/PhyTest.py
index 9b95ead..0b1ecfa 100644
--- a/acts/tests/google/ble/bt5/PhyTest.py
+++ b/acts/tests/google/ble/bt5/PhyTest.py
@@ -42,11 +42,11 @@
def setup_class(self):
super(PhyTest, self).setup_class()
if not self.cen_ad.droid.bluetoothIsLe2MPhySupported():
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Central device does not support LE 2M PHY")
if not self.per_ad.droid.bluetoothIsLe2MPhySupported():
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Peripheral device does not support LE 2M PHY")
# Some controllers auto-update PHY to 2M, and both client and server
diff --git a/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisementDiscoveryTest.py b/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisementDiscoveryTest.py
index 950a370..2af4c05 100644
--- a/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisementDiscoveryTest.py
+++ b/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisementDiscoveryTest.py
@@ -46,8 +46,8 @@
max_advertisements = -1
advertise_callback_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.droid_list = get_advanced_droid_list(self.android_devices)
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
diff --git a/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisingTest.py b/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisingTest.py
index 62f06d1..94ee0f7 100644
--- a/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisingTest.py
+++ b/acts/tests/google/ble/concurrency/ConcurrentBleAdvertisingTest.py
@@ -45,8 +45,8 @@
default_timeout = 10
max_advertisements = -1
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.droid_list = get_advanced_droid_list(self.android_devices)
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
diff --git a/acts/tests/google/ble/concurrency/ConcurrentBleScanningTest.py b/acts/tests/google/ble/concurrency/ConcurrentBleScanningTest.py
index c3e71f2..512aed8 100644
--- a/acts/tests/google/ble/concurrency/ConcurrentBleScanningTest.py
+++ b/acts/tests/google/ble/concurrency/ConcurrentBleScanningTest.py
@@ -39,8 +39,8 @@
default_timeout = 20
max_concurrent_scans = 27
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
diff --git a/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py b/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
index 96cdf0a..ec5e09c 100644
--- a/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
+++ b/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
@@ -79,12 +79,10 @@
advertisement_names = []
list_of_arguments_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
- self.pri_dut = self.android_devices[0]
-
def setup_class(self):
super(BluetoothBaseTest, self).setup_class()
+ self.pri_dut = self.android_devices[0]
+
# Create 5 advertisements from different android devices
for i in range(1, self.max_connections + 1):
diff --git a/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py b/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py
index 4229630..353f507 100644
--- a/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py
+++ b/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py
@@ -42,8 +42,8 @@
class BleCoc2ConnTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.client_ad = self.android_devices[0]
# The client which is scanning will need location to be enabled in order to
# start scan and get scan results.
@@ -53,7 +53,6 @@
if len(self.android_devices) > 2:
self.server2_ad = self.android_devices[2]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
def teardown_test(self):
diff --git a/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py b/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py
index 29bbe1a..97ace9b 100644
--- a/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py
+++ b/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py
@@ -46,8 +46,8 @@
"strange new worlds, to seek out new life and new civilizations,"
" to boldly go where no man has gone before.")
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.client_ad = self.android_devices[0]
# The client which is scanning will need location to be enabled in order to
# start scan and get scan results.
@@ -57,7 +57,6 @@
if len(self.android_devices) > 2:
self.server2_ad = self.android_devices[2]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
def teardown_test(self):
diff --git a/acts/tests/google/ble/examples/BleExamplesTest.py b/acts/tests/google/ble/examples/BleExamplesTest.py
index e84e201..1ced2db 100644
--- a/acts/tests/google/ble/examples/BleExamplesTest.py
+++ b/acts/tests/google/ble/examples/BleExamplesTest.py
@@ -34,8 +34,8 @@
scn_droid = None
adv_droid = None
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.scn_droid, self.scn_ed = (self.android_devices[0].droid,
self.android_devices[0].ed)
self.adv_droid, self.adv_ed = (self.android_devices[1].droid,
diff --git a/acts/tests/google/ble/examples/GattServerExampleTest.py b/acts/tests/google/ble/examples/GattServerExampleTest.py
index 6a741a7..e1f6476 100644
--- a/acts/tests/google/ble/examples/GattServerExampleTest.py
+++ b/acts/tests/google/ble/examples/GattServerExampleTest.py
@@ -55,8 +55,8 @@
class GattServerExampleTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
@BluetoothBaseTest.bt_test_wrap
diff --git a/acts/tests/google/ble/filtering/FilteringTest.py b/acts/tests/google/ble/filtering/FilteringTest.py
index 3a3aaac..d1bdc39 100644
--- a/acts/tests/google/ble/filtering/FilteringTest.py
+++ b/acts/tests/google/ble/filtering/FilteringTest.py
@@ -64,8 +64,8 @@
service_uuid_2 = "FFFFFFFF-0000-1000-8000-00805f9b34fb"
service_uuid_3 = "3846D7A0-69C8-11E4-BA00-0002A5D5C51B"
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
self.log.info("Scanner device model: {}".format(
diff --git a/acts/tests/google/ble/filtering/UniqueFilteringTest.py b/acts/tests/google/ble/filtering/UniqueFilteringTest.py
index 35945e5..c2e837c 100644
--- a/acts/tests/google/ble/filtering/UniqueFilteringTest.py
+++ b/acts/tests/google/ble/filtering/UniqueFilteringTest.py
@@ -38,8 +38,8 @@
class UniqueFilteringTest(BluetoothBaseTest):
default_timeout = 10
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
diff --git a/acts/tests/google/ble/gatt/GattConnectTest.py b/acts/tests/google/ble/gatt/GattConnectTest.py
index c276c0e..52f3601 100644
--- a/acts/tests/google/ble/gatt/GattConnectTest.py
+++ b/acts/tests/google/ble/gatt/GattConnectTest.py
@@ -58,8 +58,8 @@
default_timeout = 10
default_discovery_timeout = 3
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.cen_ad = self.android_devices[0]
self.per_ad = self.android_devices[1]
diff --git a/acts/tests/google/ble/gatt/GattToolTest.py b/acts/tests/google/ble/gatt/GattToolTest.py
index fc61cb5..8e7a9f0 100644
--- a/acts/tests/google/ble/gatt/GattToolTest.py
+++ b/acts/tests/google/ble/gatt/GattToolTest.py
@@ -49,8 +49,8 @@
adv_instances = []
timer_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
# Central role Android device
self.cen_ad = self.android_devices[0]
self.ble_mac_address = self.user_params['ble_mac_address']
diff --git a/acts/tests/google/ble/power/GattPowerTest.py b/acts/tests/google/ble/power/GattPowerTest.py
index c4239bd..2817d74 100644
--- a/acts/tests/google/ble/power/GattPowerTest.py
+++ b/acts/tests/google/ble/power/GattPowerTest.py
@@ -50,14 +50,12 @@
PMC_GATT_CMD = ("am broadcast -a com.android.pmc.GATT ")
GATT_SERVER_MSG = "%s--es GattServer 1" % (PMC_GATT_CMD)
- def __init__(self, controllers):
- PowerBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(GattPowerTest, self).setup_class()
self.cen_ad = self.android_devices[0]
self.per_ad = self.android_devices[1]
- def setup_class(self):
- super(GattPowerTest, self).setup_class()
if not bluetooth_enabled_check(self.per_ad):
self.log.error("Failed to turn on Bluetooth on peripheral")
diff --git a/acts/tests/google/ble/scan/BleBackgroundScanTest.py b/acts/tests/google/ble/scan/BleBackgroundScanTest.py
index 3a10793..6839602 100644
--- a/acts/tests/google/ble/scan/BleBackgroundScanTest.py
+++ b/acts/tests/google/ble/scan/BleBackgroundScanTest.py
@@ -45,13 +45,11 @@
active_scan_callback_list = []
active_adv_callback_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(BluetoothBaseTest, self).setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
- def setup_class(self):
- super(BluetoothBaseTest, self).setup_class()
utils.set_location_service(self.scn_ad, True)
utils.set_location_service(self.adv_ad, True)
return True
diff --git a/acts/tests/google/ble/scan/BleOnLostOnFoundTest.py b/acts/tests/google/ble/scan/BleOnLostOnFoundTest.py
index dd40b6a..01f7976 100644
--- a/acts/tests/google/ble/scan/BleOnLostOnFoundTest.py
+++ b/acts/tests/google/ble/scan/BleOnLostOnFoundTest.py
@@ -39,13 +39,11 @@
active_scan_callback_list = []
active_adv_callback_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(BluetoothBaseTest, self).setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
- def setup_class(self):
- super(BluetoothBaseTest, self).setup_class()
utils.set_location_service(self.scn_ad, True)
utils.set_location_service(self.adv_ad, True)
return True
diff --git a/acts/tests/google/ble/scan/BleOpportunisticScanTest.py b/acts/tests/google/ble/scan/BleOpportunisticScanTest.py
index 7b64cfe..9e59128 100644
--- a/acts/tests/google/ble/scan/BleOpportunisticScanTest.py
+++ b/acts/tests/google/ble/scan/BleOpportunisticScanTest.py
@@ -45,13 +45,11 @@
active_scan_callback_list = []
active_adv_callback_list = []
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(BluetoothBaseTest, self).setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
- def setup_class(self):
- super(BluetoothBaseTest, self).setup_class()
utils.set_location_service(self.scn_ad, True)
utils.set_location_service(self.adv_ad, True)
return True
diff --git a/acts/tests/google/ble/scan/BleScanScreenStateTest.py b/acts/tests/google/ble/scan/BleScanScreenStateTest.py
index b6d128a..07ae898 100644
--- a/acts/tests/google/ble/scan/BleScanScreenStateTest.py
+++ b/acts/tests/google/ble/scan/BleScanScreenStateTest.py
@@ -42,13 +42,11 @@
scan_callback = -1
shorter_scan_timeout = 4
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(BluetoothBaseTest, self).setup_class()
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
- def setup_class(self):
- super(BluetoothBaseTest, self).setup_class()
utils.set_location_service(self.scn_ad, True)
utils.set_location_service(self.adv_ad, True)
return True
diff --git a/acts/tests/google/ble/system_tests/BleStressTest.py b/acts/tests/google/ble/system_tests/BleStressTest.py
index be0a9fe..f97907f 100644
--- a/acts/tests/google/ble/system_tests/BleStressTest.py
+++ b/acts/tests/google/ble/system_tests/BleStressTest.py
@@ -38,8 +38,8 @@
default_timeout = 10
PAIRING_TIMEOUT = 20
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.droid_list = get_advanced_droid_list(self.android_devices)
self.scn_ad = self.android_devices[0]
self.adv_ad = self.android_devices[1]
diff --git a/acts/tests/google/bt/AkXB10PairingTest.py b/acts/tests/google/bt/AkXB10PairingTest.py
index 51e1e59..10e7335 100644
--- a/acts/tests/google/bt/AkXB10PairingTest.py
+++ b/acts/tests/google/bt/AkXB10PairingTest.py
@@ -28,8 +28,8 @@
class AkXB10PairingTest(BluetoothBaseTest):
DISCOVERY_TIME = 5
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
# Do factory reset and then do delay for 3-seconds
self.dut.droid.bluetoothFactoryReset()
diff --git a/acts/tests/google/bt/BtAirplaneModeTest.py b/acts/tests/google/bt/BtAirplaneModeTest.py
index bb90b10..e2dd7eb 100644
--- a/acts/tests/google/bt/BtAirplaneModeTest.py
+++ b/acts/tests/google/bt/BtAirplaneModeTest.py
@@ -31,8 +31,8 @@
grace_timeout = 4
WAIT_TIME_ANDROID_STATE_SETTLING = 5
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
def setup_test(self):
diff --git a/acts/tests/google/bt/BtBasicFunctionalityTest.py b/acts/tests/google/bt/BtBasicFunctionalityTest.py
index 0cb4ea8..3194d76 100644
--- a/acts/tests/google/bt/BtBasicFunctionalityTest.py
+++ b/acts/tests/google/bt/BtBasicFunctionalityTest.py
@@ -36,12 +36,11 @@
default_timeout = 10
scan_discovery_time = 5
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.droid_ad = self.android_devices[0]
self.droid1_ad = self.android_devices[1]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
def setup_test(self):
diff --git a/acts/tests/google/bt/BtFactoryResetTest.py b/acts/tests/google/bt/BtFactoryResetTest.py
index 8c9d399..f33b210 100644
--- a/acts/tests/google/bt/BtFactoryResetTest.py
+++ b/acts/tests/google/bt/BtFactoryResetTest.py
@@ -25,8 +25,8 @@
default_timeout = 10
grace_timeout = 4
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.pri_dut = self.android_devices[0]
self.sec_dut = self.android_devices[1]
diff --git a/acts/tests/google/bt/BtKillProcessTest.py b/acts/tests/google/bt/BtKillProcessTest.py
index 2b17d28..ed53e20 100644
--- a/acts/tests/google/bt/BtKillProcessTest.py
+++ b/acts/tests/google/bt/BtKillProcessTest.py
@@ -25,8 +25,8 @@
class BtKillProcessTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
def _get_bt_pid(self):
diff --git a/acts/tests/google/bt/RfcommTest.py b/acts/tests/google/bt/RfcommTest.py
index 272fc89..58de1be 100644
--- a/acts/tests/google/bt/RfcommTest.py
+++ b/acts/tests/google/bt/RfcommTest.py
@@ -47,12 +47,11 @@
"strange new worlds, to seek out new life and new civilizations,"
" to boldly go where no man has gone before.")
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.client_ad = self.android_devices[0]
self.server_ad = self.android_devices[1]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
def teardown_test(self):
diff --git a/acts/tests/google/bt/SonyXB2PairingTest.py b/acts/tests/google/bt/SonyXB2PairingTest.py
index 3907135..4dcf863 100644
--- a/acts/tests/google/bt/SonyXB2PairingTest.py
+++ b/acts/tests/google/bt/SonyXB2PairingTest.py
@@ -28,8 +28,8 @@
class SonyXB2PairingTest(BluetoothBaseTest):
DISCOVERY_TIME = 5
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
# Do factory reset and then do delay for 3-seconds
self.dut.droid.bluetoothFactoryReset()
diff --git a/acts/tests/google/bt/audio_lab/BtChameleonTest.py b/acts/tests/google/bt/audio_lab/BtChameleonTest.py
index 4a43cd3..d268344 100644
--- a/acts/tests/google/bt/audio_lab/BtChameleonTest.py
+++ b/acts/tests/google/bt/audio_lab/BtChameleonTest.py
@@ -47,8 +47,8 @@
audio_file_2k1k_300_sec = "audio_file_2k1k_300_sec.wav"
android_sdcard_music_path = "/sdcard/Music"
- def __init__(self, controllers):
- BtFunhausBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.chameleon = self.chameleon_devices[0]
self.dut = self.android_devices[0]
self.raw_audio_dest = "{}/{}".format(self.android_devices[0].log_path,
diff --git a/acts/tests/google/bt/audio_lab/BtFunhausTest.py b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
index e82c955..42cbc22 100644
--- a/acts/tests/google/bt/audio_lab/BtFunhausTest.py
+++ b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
@@ -26,8 +26,8 @@
music_file_to_play = ""
device_fails_to_connect_list = []
- def __init__(self, controllers):
- BtFunhausBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
@test_tracker_info(uuid='80a4cc4c-7c2a-428d-9eaf-46239a7926df')
def test_run_bt_audio_12_hours(self):
diff --git a/acts/tests/google/bt/audio_lab/ThreeButtonDongleTest.py b/acts/tests/google/bt/audio_lab/ThreeButtonDongleTest.py
index cf9add5..abf97be 100644
--- a/acts/tests/google/bt/audio_lab/ThreeButtonDongleTest.py
+++ b/acts/tests/google/bt/audio_lab/ThreeButtonDongleTest.py
@@ -26,8 +26,8 @@
class ThreeButtonDongleTest(BluetoothBaseTest):
iterations = 10
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
self.dongle = self.relay_devices[0]
self.log.info("Target dongle is {}".format(self.dongle.name))
diff --git a/acts/tests/google/bt/car_bt/BtCarBasicFunctionalityTest.py b/acts/tests/google/bt/car_bt/BtCarBasicFunctionalityTest.py
index 431e49e..99f2851 100644
--- a/acts/tests/google/bt/car_bt/BtCarBasicFunctionalityTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarBasicFunctionalityTest.py
@@ -36,11 +36,10 @@
default_timeout = 10
scan_discovery_time = 5
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.car_ad = self.android_devices[0]
- def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
@test_tracker_info(uuid='b52a032a-3438-4b84-863f-c46a969882a4')
diff --git a/acts/tests/google/bt/car_bt/BtCarPairingTest.py b/acts/tests/google/bt/car_bt/BtCarPairingTest.py
index b4fde56..603f1a8 100644
--- a/acts/tests/google/bt/car_bt/BtCarPairingTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarPairingTest.py
@@ -33,8 +33,8 @@
class BtCarPairingTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.car = self.android_devices[0]
self.ph = self.android_devices[1]
diff --git a/acts/tests/google/bt/car_bt/BtCarPbapTest.py b/acts/tests/google/bt/car_bt/BtCarPbapTest.py
index ab605a2..6d5bccb 100644
--- a/acts/tests/google/bt/car_bt/BtCarPbapTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarPbapTest.py
@@ -40,16 +40,14 @@
class BtCarPbapTest(BluetoothBaseTest):
contacts_destination_path = ""
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ if not super(BtCarPbapTest, self).setup_class():
+ return False
self.pce = self.android_devices[0]
self.pse = self.android_devices[1]
self.pse2 = self.android_devices[2]
self.contacts_destination_path = self.log_path + "/"
- def setup_class(self):
- if not super(BtCarPbapTest, self).setup_class():
- return False
permissions_list = [
"android.permission.READ_CONTACTS",
"android.permission.WRITE_CONTACTS",
diff --git a/acts/tests/google/bt/gatt/GattOverBrEdrTest.py b/acts/tests/google/bt/gatt/GattOverBrEdrTest.py
index dcf916d..7985540 100644
--- a/acts/tests/google/bt/gatt/GattOverBrEdrTest.py
+++ b/acts/tests/google/bt/gatt/GattOverBrEdrTest.py
@@ -47,13 +47,11 @@
default_discovery_timeout = 3
per_droid_mac_address = None
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super(BluetoothBaseTest, self).setup_class()
self.cen_ad = self.android_devices[0]
self.per_ad = self.android_devices[1]
- def setup_class(self):
- super(BluetoothBaseTest, self).setup_class()
self.per_droid_mac_address = self.per_ad.droid.bluetoothGetLocalAddress(
)
if not self.per_droid_mac_address:
diff --git a/acts/tests/google/bt/hid/HidDeviceTest.py b/acts/tests/google/bt/hid/HidDeviceTest.py
index cdd1094..e7e1778 100644
--- a/acts/tests/google/bt/hid/HidDeviceTest.py
+++ b/acts/tests/google/bt/hid/HidDeviceTest.py
@@ -34,8 +34,8 @@
tests = None
default_timeout = 10
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.host_ad = self.android_devices[0]
self.device_ad = self.android_devices[1]
diff --git a/acts/tests/google/bt/ota/BtOtaTest.py b/acts/tests/google/bt/ota/BtOtaTest.py
index 91e51bb..86e3098 100644
--- a/acts/tests/google/bt/ota/BtOtaTest.py
+++ b/acts/tests/google/bt/ota/BtOtaTest.py
@@ -32,14 +32,14 @@
# Pairing devices
if not pair_pri_to_sec(self.dut, self.android_devices[1]):
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed to bond devices prior to update")
#Run OTA below, if ota fails then abort all tests
try:
ota_updater.update(self.dut)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
@BluetoothBaseTest.bt_test_wrap
diff --git a/acts/tests/google/bt/pan/BtPanTest.py b/acts/tests/google/bt/pan/BtPanTest.py
index 0539851..01f6078 100644
--- a/acts/tests/google/bt/pan/BtPanTest.py
+++ b/acts/tests/google/bt/pan/BtPanTest.py
@@ -32,8 +32,8 @@
class BtPanTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.pan_dut = self.android_devices[0]
self.panu_dut = self.android_devices[1]
diff --git a/acts/tests/google/bt/performance/BtCodecSweepTest.py b/acts/tests/google/bt/performance/BtCodecSweepTest.py
index c8e6819..a6504a5 100644
--- a/acts/tests/google/bt/performance/BtCodecSweepTest.py
+++ b/acts/tests/google/bt/performance/BtCodecSweepTest.py
@@ -28,8 +28,8 @@
class BtCodecSweepTest(A2dpCodecBaseTest):
- def __init__(self, configs):
- super().__init__(configs)
+ def setup_class(self):
+ super().setup_class()
self.bt_logger = BluetoothMetricLogger.for_test_case()
self.start_time = time.time()
diff --git a/acts/tests/google/bt/performance/BtInterferenceRSSITest.py b/acts/tests/google/bt/performance/BtInterferenceRSSITest.py
index dbc1e9e..6c92c61 100644
--- a/acts/tests/google/bt/performance/BtInterferenceRSSITest.py
+++ b/acts/tests/google/bt/performance/BtInterferenceRSSITest.py
@@ -26,8 +26,8 @@
module) terminates the sequence and keeps it from looping.
"""
- def __init__(self, configs):
- super().__init__(configs)
+ def setup_class(self):
+ super().setup_class()
req_params = ["bt_atten_sequences", "RelayDevice", "codec"]
opt_params = ["audio_params"]
self.unpack_userparams(req_params, opt_params)
diff --git a/acts/tests/google/bt/performance/BtRangeCodecTest.py b/acts/tests/google/bt/performance/BtRangeCodecTest.py
old mode 100755
new mode 100644
index 8070997..e20b864
--- a/acts/tests/google/bt/performance/BtRangeCodecTest.py
+++ b/acts/tests/google/bt/performance/BtRangeCodecTest.py
@@ -31,8 +31,8 @@
class BtRangeCodecTest(A2dpCodecBaseTest):
- def __init__(self, configs):
- super().__init__(configs)
+ def setup_class(self):
+ super().setup_class()
self.bt_logger = log.BluetoothMetricLogger.for_test_case()
self.start_time = time.time()
self.attenuator = self.attenuators[0]
diff --git a/acts/tests/google/bt/pts/A2dpPtsTest.py b/acts/tests/google/bt/pts/A2dpPtsTest.py
index 1b16c2a..25ed3ce 100644
--- a/acts/tests/google/bt/pts/A2dpPtsTest.py
+++ b/acts/tests/google/bt/pts/A2dpPtsTest.py
@@ -28,8 +28,8 @@
ble_advertise_interval = 100
pts_action_mapping = None
- def __init__(self, controllers):
- super(A2dpPtsTest, self).__init__(controllers)
+ def setup_class(self):
+ super(A2dpPtsTest, self).setup_class()
self.dut.initialize_bluetooth_controller()
# self.dut.set_bluetooth_local_name(self.dut_bluetooth_local_name)
local_dut_mac_address = self.dut.get_local_bluetooth_address()
@@ -58,8 +58,6 @@
self.pts.set_ics_and_ixit(ics, ixit)
- def setup_class(self):
- super(A2dpPtsTest, self).setup_class()
self.dut.unbond_all_known_devices()
self.dut.start_pairing_helper()
diff --git a/acts/tests/google/bt/pts/BtCmdLineTest.py b/acts/tests/google/bt/pts/BtCmdLineTest.py
index c75aa35..8d925ed 100644
--- a/acts/tests/google/bt/pts/BtCmdLineTest.py
+++ b/acts/tests/google/bt/pts/BtCmdLineTest.py
@@ -34,8 +34,8 @@
class BtCmdLineTest(BluetoothBaseTest):
target_mac_address = ""
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
if not "target_mac_address" in self.user_params.keys():
self.log.warning("Missing user config \"target_mac_address\"!")
self.target_mac_address = ""
@@ -71,6 +71,7 @@
music_path = self.user_params[music_path_str]
self._add_music_to_primary_android_device(music_path,
android_music_path)
+ return True
def _add_music_to_primary_android_device(self, music_path,
android_music_path):
@@ -82,9 +83,6 @@
self.android_devices[0].adb.push("{} {}".format(
file, android_music_path))
- def setup_class(self):
- return True
-
def test_pts_cmd_line_helper(self):
cmd_line = CmdInput()
cmd_line.setup_vars(self.android_devices, self.target_mac_address,
diff --git a/acts/tests/google/bt/pts/GattPtsTest.py b/acts/tests/google/bt/pts/GattPtsTest.py
index 318fb51..7883f37 100644
--- a/acts/tests/google/bt/pts/GattPtsTest.py
+++ b/acts/tests/google/bt/pts/GattPtsTest.py
@@ -32,8 +32,8 @@
ble_advertise_interval = 100
pts_action_mapping = None
- def __init__(self, controllers):
- super(GattPtsTest, self).__init__(controllers)
+ def setup_class(self):
+ super(GattPtsTest, self).setup_class()
self.dut_bluetooth_local_name = "fs_test"
self.dut.initialize_bluetooth_controller()
self.dut.set_bluetooth_local_name(self.dut_bluetooth_local_name)
@@ -74,8 +74,6 @@
self.pts.set_ics_and_ixit(ics, ixit)
- def setup_class(self):
- super(GattPtsTest, self).setup_class()
self.dut.unbond_all_known_devices()
self.dut.start_pairing_helper()
diff --git a/acts/tests/google/bt/pts/SdpPtsTest.py b/acts/tests/google/bt/pts/SdpPtsTest.py
index 2535671..84c7ab7 100644
--- a/acts/tests/google/bt/pts/SdpPtsTest.py
+++ b/acts/tests/google/bt/pts/SdpPtsTest.py
@@ -97,8 +97,8 @@
class SdpPtsTest(PtsBaseClass):
- def __init__(self, controllers):
- super(SdpPtsTest, self).__init__(controllers)
+ def setup_class(self):
+ super(SdpPtsTest, self).setup_class()
self.dut.initialize_bluetooth_controller()
# self.dut.set_bluetooth_local_name(self.dut_bluetooth_local_name)
local_dut_mac_address = self.dut.get_local_bluetooth_address()
@@ -127,8 +127,6 @@
self.pts.set_ics_and_ixit(ics, ixit)
- def setup_class(self):
- super(SdpPtsTest, self).setup_class()
self.dut.unbond_all_known_devices()
self.dut.set_discoverable(True)
diff --git a/acts/tests/google/bt/sdp/SdpSetupTest.py b/acts/tests/google/bt/sdp/SdpSetupTest.py
index cb63724..938d720 100644
--- a/acts/tests/google/bt/sdp/SdpSetupTest.py
+++ b/acts/tests/google/bt/sdp/SdpSetupTest.py
@@ -77,8 +77,8 @@
class SdpSetupTest(BaseTestClass):
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super(SdpSetupTest, self).setup_class()
if 'dut' in self.user_params:
if self.user_params['dut'] == 'fuchsia_devices':
self.dut = create_bluetooth_device(self.fuchsia_devices[0])
@@ -92,8 +92,6 @@
self.dut = create_bluetooth_device(self.fuchsia_devices[0])
self.dut.initialize_bluetooth_controller()
- def setup_class(self):
- super(SdpSetupTest, self).setup_class()
def setup_test(self):
self.dut.sdp_clean_up()
diff --git a/acts/tests/google/bt/system_tests/BtStressTest.py b/acts/tests/google/bt/system_tests/BtStressTest.py
index 163ee37..0473aa0 100644
--- a/acts/tests/google/bt/system_tests/BtStressTest.py
+++ b/acts/tests/google/bt/system_tests/BtStressTest.py
@@ -33,8 +33,8 @@
default_timeout = 20
iterations = 100
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
def teardown_test(self):
super(BluetoothBaseTest, self).teardown_test()
diff --git a/acts/tests/google/bt/system_tests/RfcommLongevityTest.py b/acts/tests/google/bt/system_tests/RfcommLongevityTest.py
index 3e39344..d1d4fe5 100644
--- a/acts/tests/google/bt/system_tests/RfcommLongevityTest.py
+++ b/acts/tests/google/bt/system_tests/RfcommLongevityTest.py
@@ -39,8 +39,8 @@
"strange new worlds, to seek out new life and new civilizations,"
" to boldly go where no man has gone before.")
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.client_ad = self.android_devices[0]
self.server_ad = self.android_devices[1]
diff --git a/acts/tests/google/bt/system_tests/RfcommStressTest.py b/acts/tests/google/bt/system_tests/RfcommStressTest.py
index 8e56ef0..3fac543 100644
--- a/acts/tests/google/bt/system_tests/RfcommStressTest.py
+++ b/acts/tests/google/bt/system_tests/RfcommStressTest.py
@@ -38,8 +38,8 @@
"strange new worlds, to seek out new life and new civilizations,"
" to boldly go where no man has gone before.")
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.client_ad = self.android_devices[0]
self.server_ad = self.android_devices[1]
diff --git a/acts/tests/google/experimental/BluetoothLatencyTest.py b/acts/tests/google/experimental/BluetoothLatencyTest.py
index ebb3019..811a41c 100644
--- a/acts/tests/google/experimental/BluetoothLatencyTest.py
+++ b/acts/tests/google/experimental/BluetoothLatencyTest.py
@@ -41,8 +41,8 @@
data_transfer_type: Data transfer protocol used for the test
"""
- def __init__(self, configs):
- BaseTestClass.__init__(self, configs)
+ def setup_class(self):
+ super().setup_class()
# Sanity check of the devices under test
# TODO(b/119051823): Investigate using a config validator to replace this.
diff --git a/acts/tests/google/experimental/BluetoothPairAndConnectTest.py b/acts/tests/google/experimental/BluetoothPairAndConnectTest.py
index f021702..e54e4e7 100644
--- a/acts/tests/google/experimental/BluetoothPairAndConnectTest.py
+++ b/acts/tests/google/experimental/BluetoothPairAndConnectTest.py
@@ -52,8 +52,8 @@
bt_utils: BTUtils test action object
"""
- def __init__(self, configs):
- BaseTestClass.__init__(self, configs)
+ def setup_class(self):
+ super().setup_class()
# Sanity check of the devices under test
# TODO(b/119051823): Investigate using a config validator to replace this.
if not self.android_devices:
diff --git a/acts/tests/google/experimental/BluetoothReconnectTest.py b/acts/tests/google/experimental/BluetoothReconnectTest.py
index 717f444..a03ec7b 100644
--- a/acts/tests/google/experimental/BluetoothReconnectTest.py
+++ b/acts/tests/google/experimental/BluetoothReconnectTest.py
@@ -46,8 +46,8 @@
dut_bt_addr: The Bluetooth address of the Apollo earbuds
"""
- def __init__(self, configs):
- BaseTestClass.__init__(self, configs)
+ def setup_class(self):
+ super().setup_class()
# sanity check of the dut devices.
# TODO(b/119051823): Investigate using a config validator to replace this.
if not self.android_devices:
diff --git a/acts/tests/google/experimental/BluetoothThroughputTest.py b/acts/tests/google/experimental/BluetoothThroughputTest.py
index 8b4fd48..3403ded 100644
--- a/acts/tests/google/experimental/BluetoothThroughputTest.py
+++ b/acts/tests/google/experimental/BluetoothThroughputTest.py
@@ -37,8 +37,8 @@
data_transfer_type: Data transfer protocol used for the test
"""
- def __init__(self, configs):
- BaseTestClass.__init__(self, configs)
+ def setup_class(self):
+ super().setup_class()
# Sanity check of the devices under test
# TODO(b/119051823): Investigate using a config validator to replace this.
diff --git a/acts/tests/google/fuchsia/bt/BleFuchsiaAndroidTest.py b/acts/tests/google/fuchsia/bt/BleFuchsiaAndroidTest.py
index 59c5006..6c5798a 100644
--- a/acts/tests/google/fuchsia/bt/BleFuchsiaAndroidTest.py
+++ b/acts/tests/google/fuchsia/bt/BleFuchsiaAndroidTest.py
@@ -37,8 +37,8 @@
active_adv_callback_list = []
droid = None
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
# Android device under test
self.ad = self.android_devices[0]
diff --git a/acts/tests/google/fuchsia/bt/BleFuchsiaTest.py b/acts/tests/google/fuchsia/bt/BleFuchsiaTest.py
index 4597ed7..7b368ca 100644
--- a/acts/tests/google/fuchsia/bt/BleFuchsiaTest.py
+++ b/acts/tests/google/fuchsia/bt/BleFuchsiaTest.py
@@ -30,8 +30,8 @@
active_adv_callback_list = []
droid = None
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
if (len(self.fuchsia_devices) < 2):
self.log.error("BleFuchsiaTest Init: Not enough fuchsia devices.")
diff --git a/acts/tests/google/fuchsia/bt/FuchsiaBtMacAddressTest.py b/acts/tests/google/fuchsia/bt/FuchsiaBtMacAddressTest.py
index ec2042c..c4124b7 100644
--- a/acts/tests/google/fuchsia/bt/FuchsiaBtMacAddressTest.py
+++ b/acts/tests/google/fuchsia/bt/FuchsiaBtMacAddressTest.py
@@ -32,10 +32,9 @@
class FuchsiaBtMacAddressTest(BaseTestClass):
scan_timeout_seconds = 10
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
-
def setup_class(self):
+ super().setup_class()
+
if len(self.fuchsia_devices) < 2:
raise signals.TestAbortAll("Need at least two Fuchsia devices")
for device in self.fuchsia_devices:
diff --git a/acts/tests/google/fuchsia/bt/FuchsiaBtScanTest.py b/acts/tests/google/fuchsia/bt/FuchsiaBtScanTest.py
index 5e0ebc3..722a446 100644
--- a/acts/tests/google/fuchsia/bt/FuchsiaBtScanTest.py
+++ b/acts/tests/google/fuchsia/bt/FuchsiaBtScanTest.py
@@ -32,12 +32,11 @@
class FuchsiaBtScanTest(BaseTestClass):
scan_timeout_seconds = 30
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.pri_dut = self.fuchsia_devices[0]
self.sec_dut = self.fuchsia_devices[1]
- def setup_class(self):
self.pri_dut.btc_lib.initBluetoothControl()
self.sec_dut.btc_lib.initBluetoothControl()
diff --git a/acts/tests/google/fuchsia/bt/FuchsiaCmdLineTest.py b/acts/tests/google/fuchsia/bt/FuchsiaCmdLineTest.py
index d34dc62..63c7845 100644
--- a/acts/tests/google/fuchsia/bt/FuchsiaCmdLineTest.py
+++ b/acts/tests/google/fuchsia/bt/FuchsiaCmdLineTest.py
@@ -32,8 +32,8 @@
class FuchsiaCmdLineTest(BaseTestClass):
target_device_name = ""
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
if not "target_device_name" in self.user_params.keys():
self.log.warning("Missing user config \"target_device_name\"!")
self.target_device_name = ""
diff --git a/acts/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py b/acts/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py
index caba8f5..5c46548 100644
--- a/acts/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py
+++ b/acts/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py
@@ -42,8 +42,8 @@
scan_timeout_seconds = 10
default_iterations = 1000
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.fuchsia_client_dut = self.fuchsia_devices[0]
self.fuchsia_server_dut = self.fuchsia_devices[1]
self.default_iterations = self.user_params.get(
diff --git a/acts/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py b/acts/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
index 67ef6f8..83418e4 100644
--- a/acts/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
+++ b/acts/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
@@ -31,8 +31,8 @@
class GattServerSetupTest(BaseTestClass):
err_message = "Setting up database failed with: {}"
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.fuchsia_dut = self.fuchsia_devices[0]
def setup_database(self, database):
diff --git a/acts/tests/google/fuchsia/examples/Sl4fSanityTest.py b/acts/tests/google/fuchsia/examples/Sl4fSanityTest.py
index 7d95e2d..d2116a9 100644
--- a/acts/tests/google/fuchsia/examples/Sl4fSanityTest.py
+++ b/acts/tests/google/fuchsia/examples/Sl4fSanityTest.py
@@ -29,10 +29,9 @@
class Sl4fSanityTest(BaseTestClass):
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
-
def setup_class(self):
+ super().setup_class()
+
success_str = ("Congratulations! Fuchsia controllers have been "
"initialized successfully!")
err_str = ("Sorry, please try verifying FuchsiaDevice is in your "
@@ -40,7 +39,7 @@
if len(self.fuchsia_devices) > 0:
self.log.info(success_str)
else:
- raise signals.TestSkipClass("err_str")
+ raise signals.TestAbortClass("err_str")
def test_example(self):
self.log.info("Congratulations! You've run your first test.")
diff --git a/acts/tests/google/fuchsia/logging/FuchsiaLoggingTest.py b/acts/tests/google/fuchsia/logging/FuchsiaLoggingTest.py
index e76f274..28d6998 100644
--- a/acts/tests/google/fuchsia/logging/FuchsiaLoggingTest.py
+++ b/acts/tests/google/fuchsia/logging/FuchsiaLoggingTest.py
@@ -20,8 +20,8 @@
class FuchsiaLoggingTest(BaseTestClass):
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.fuchsia_devices[0]
self.message = "Logging Test"
diff --git a/acts/tests/google/fuchsia/wlan/ConnectionStressTest.py b/acts/tests/google/fuchsia/wlan/ConnectionStressTest.py
index 02d21af..51bc59c 100644
--- a/acts/tests/google/fuchsia/wlan/ConnectionStressTest.py
+++ b/acts/tests/google/fuchsia/wlan/ConnectionStressTest.py
@@ -44,8 +44,8 @@
channel_2G = hostapd_constants.AP_DEFAULT_CHANNEL_2G
channel_5G = hostapd_constants.AP_DEFAULT_CHANNEL_5G
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ssid = rand_ascii_str(10)
self.fd = self.fuchsia_devices[0]
self.dut = create_wlan_device(self.fd)
diff --git a/acts/tests/google/fuchsia/wlan/DownloadStressTest.py b/acts/tests/google/fuchsia/wlan/DownloadStressTest.py
index 97d5720..f3f3803 100644
--- a/acts/tests/google/fuchsia/wlan/DownloadStressTest.py
+++ b/acts/tests/google/fuchsia/wlan/DownloadStressTest.py
@@ -52,8 +52,8 @@
num_of_small_downloads = 5
download_threads_result = []
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ssid = rand_ascii_str(10)
self.fd = self.fuchsia_devices[0]
self.wlan_device = create_wlan_device(self.fd)
@@ -62,7 +62,6 @@
self.user_params.get("download_stress_test_iterations",
self.num_of_iterations))
- def setup_class(self):
setup_ap_and_associate(
access_point=self.ap,
client=self.wlan_device,
diff --git a/acts/tests/google/fuchsia/wlan/PingStressTest.py b/acts/tests/google/fuchsia/wlan/PingStressTest.py
index 911e3d7..2aa1d00 100644
--- a/acts/tests/google/fuchsia/wlan/PingStressTest.py
+++ b/acts/tests/google/fuchsia/wlan/PingStressTest.py
@@ -43,10 +43,9 @@
google_dns_1 = '8.8.8.8'
google_dns_2 = '8.8.4.4'
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
-
def setup_class(self):
+ super().setup_class()
+
self.ssid = rand_ascii_str(10)
self.fd = self.fuchsia_devices[0]
self.wlan_device = create_wlan_device(self.fd)
diff --git a/acts/tests/google/fuchsia/wlan/RebootAPStressTest.py b/acts/tests/google/fuchsia/wlan/RebootAPStressTest.py
index 6e37409..cbe9d12 100644
--- a/acts/tests/google/fuchsia/wlan/RebootAPStressTest.py
+++ b/acts/tests/google/fuchsia/wlan/RebootAPStressTest.py
@@ -56,8 +56,8 @@
# after AP reboot.
wait_after_ap_reboot_s = 1
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ssid = rand_ascii_str(10)
self.wlan_device = create_wlan_device(self.fuchsia_devices[0])
self.ap = self.access_points[0]
diff --git a/acts/tests/google/fuchsia/wlan/RebootStressTest.py b/acts/tests/google/fuchsia/wlan/RebootStressTest.py
index 86bafbb..fb9a870 100644
--- a/acts/tests/google/fuchsia/wlan/RebootStressTest.py
+++ b/acts/tests/google/fuchsia/wlan/RebootStressTest.py
@@ -38,8 +38,8 @@
# Eg: "reboot_stress_test_iterations": "10"
num_of_iterations = 3
- def __init__(self, controllers):
- BaseTestClass.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.ssid = rand_ascii_str(10)
self.fd = self.fuchsia_devices[0]
self.wlan_device = create_wlan_device(self.fd)
@@ -48,7 +48,6 @@
self.user_params.get("reboot_stress_test_iterations",
self.num_of_iterations))
- def setup_class(self):
setup_ap_and_associate(
access_point=self.ap,
client=self.wlan_device,
diff --git a/acts/tests/google/fugu/AndroidFuguRemotePairingTest.py b/acts/tests/google/fugu/AndroidFuguRemotePairingTest.py
old mode 100755
new mode 100644
index 03b443f..a41f9fc
--- a/acts/tests/google/fugu/AndroidFuguRemotePairingTest.py
+++ b/acts/tests/google/fugu/AndroidFuguRemotePairingTest.py
@@ -22,8 +22,8 @@
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
class AndroidFuguRemotePairingTest(BluetoothBaseTest):
- def __init__(self, controllers):
- BluetoothBaseTest.__init__(self, controllers)
+ def setup_class(self):
+ super().setup_class()
self.dut = self.android_devices[0]
self.fugu_remote = self.relay_devices[0]
diff --git a/acts/tests/google/gnss/AGNSSPerformanceTest.py b/acts/tests/google/gnss/AGNSSPerformanceTest.py
index 60dce02..a14a1ba 100644
--- a/acts/tests/google/gnss/AGNSSPerformanceTest.py
+++ b/acts/tests/google/gnss/AGNSSPerformanceTest.py
@@ -18,7 +18,7 @@
from acts import base_test
from acts import asserts
-from acts.controllers.gnssinst_lib.rohdeschwarz import contest
+from acts.controllers.rohdeschwarz_lib import contest
from acts.test_utils.tel import tel_test_utils
import json
diff --git a/acts/tests/google/gnss/FlpTtffTest.py b/acts/tests/google/gnss/FlpTtffTest.py
index 77e8cf0..0a36923 100644
--- a/acts/tests/google/gnss/FlpTtffTest.py
+++ b/acts/tests/google/gnss/FlpTtffTest.py
@@ -56,7 +56,6 @@
for network in self.pixel_lab_network:
SSID = network['SSID']
self.ssid_map[SSID] = network
-
if int(self.ad.adb.shell("settings get global airplane_mode_on")) != 0:
self.ad.log.info("Force airplane mode off")
force_airplane_mode(self.ad, False)
diff --git a/acts/tests/google/gnss/GnssSanityTest.py b/acts/tests/google/gnss/GnssSanityTest.py
index 4d707d5..28c2ccf 100644
--- a/acts/tests/google/gnss/GnssSanityTest.py
+++ b/acts/tests/google/gnss/GnssSanityTest.py
@@ -69,6 +69,8 @@
from acts.test_utils.gnss.gnss_test_utils import check_xtra_download
from acts.test_utils.gnss.gnss_test_utils import gnss_tracking_via_gtw_gpstool
from acts.test_utils.gnss.gnss_test_utils import parse_gtw_gpstool_log
+from acts.test_utils.gnss.gnss_test_utils import enable_supl_mode
+from acts.test_utils.gnss.gnss_test_utils import start_toggle_gnss_by_gtw_gpstool
class GnssSanityTest(BaseTestClass):
@@ -77,8 +79,8 @@
super().setup_class()
self.ad = self.android_devices[0]
req_params = ["pixel_lab_network", "standalone_cs_criteria",
- "supl_cs_criteria", "xtra_ws_criteria", "xtra_cs_criteria",
- "weak_signal_supl_cs_criteria",
+ "supl_cs_criteria", "xtra_ws_criteria",
+ "xtra_cs_criteria", "weak_signal_supl_cs_criteria",
"weak_signal_xtra_ws_criteria",
"weak_signal_xtra_cs_criteria",
"default_gnss_signal_attenuation",
@@ -98,7 +100,6 @@
else:
self.wifi_xtra_cs_criteria = self.xtra_cs_criteria
self.flash_new_radio_or_mbn()
-
set_attenuator_gnss_signal(self.ad, self.attenuators,
self.default_gnss_signal_attenuation)
_init_device(self.ad)
@@ -259,7 +260,8 @@
self.ad.log.error("\n%s" % error)
else:
self.ad.log.info("NO \"%s\" initialization error found." % attr)
- asserts.assert_true(error_mismatch, "Error message found after GNSS init")
+ asserts.assert_true(error_mismatch, "Error message found after GNSS "
+ "init")
@test_tracker_info(uuid="ff318483-411c-411a-8b1a-422bd54f4a3f")
def test_supl_capabilities(self):
@@ -436,7 +438,8 @@
4. DUT hang up call.
Expected Results:
- All SUPL TTFF Cold Start results should be less than supl_cs_criteria.
+ All SUPL TTFF Cold Start results should be less than
+ supl_cs_criteria.
"""
begin_time = get_current_epoch_time()
start_qxdm_logger(self.ad, begin_time)
@@ -539,9 +542,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="cs", iteration=3)
ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- supl_ssr_test_result = check_ttff_data(self.ad, ttff_data,
- ttff_mode="Cold Start",
- criteria=self.supl_cs_criteria)
+ supl_ssr_test_result = check_ttff_data(
+ self.ad, ttff_data, ttff_mode="Cold Start",
+ criteria=self.supl_cs_criteria)
self.ad.log.info("SUPL after Modem SSR test %d times -> %s"
% (times, supl_ssr_test_result))
supl_ssr_test_result_all.append(supl_ssr_test_result)
@@ -713,7 +716,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="ws", iteration=10)
ws_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- ws_result = check_ttff_data(self.ad, ws_ttff_data, ttff_mode="Warm Start",
+ ws_result = check_ttff_data(self.ad,
+ ws_ttff_data,
+ ttff_mode="Warm Start",
criteria=self.xtra_ws_criteria)
xtra_result.append(ws_result)
begin_time = get_current_epoch_time()
@@ -721,7 +726,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="cs", iteration=10)
cs_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- cs_result = check_ttff_data(self.ad, cs_ttff_data, ttff_mode="Cold Start",
+ cs_result = check_ttff_data(self.ad,
+ cs_ttff_data,
+ ttff_mode="Cold Start",
criteria=self.xtra_cs_criteria)
xtra_result.append(cs_result)
asserts.assert_true(all(xtra_result),
@@ -752,7 +759,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="ws", iteration=10)
ws_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- ws_result = check_ttff_data(self.ad, ws_ttff_data, ttff_mode="Warm Start",
+ ws_result = check_ttff_data(self.ad,
+ ws_ttff_data,
+ ttff_mode="Warm Start",
criteria=self.weak_signal_xtra_ws_criteria)
xtra_result.append(ws_result)
begin_time = get_current_epoch_time()
@@ -760,7 +769,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="cs", iteration=10)
cs_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- cs_result = check_ttff_data(self.ad, cs_ttff_data, ttff_mode="Cold Start",
+ cs_result = check_ttff_data(self.ad,
+ cs_ttff_data,
+ ttff_mode="Cold Start",
criteria=self.weak_signal_xtra_cs_criteria)
xtra_result.append(cs_result)
asserts.assert_true(all(xtra_result),
@@ -787,13 +798,15 @@
self.ad.log.info("Turn airplane mode on")
force_airplane_mode(self.ad, True)
wifi_toggle_state(self.ad, True)
- connect_to_wifi_network(self.ad,
- self.ssid_map[self.pixel_lab_network[0]["SSID"]])
+ connect_to_wifi_network(
+ self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
process_gnss_by_gtw_gpstool(self.ad, self.standalone_cs_criteria)
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="ws", iteration=10)
ws_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- ws_result = check_ttff_data(self.ad, ws_ttff_data, ttff_mode="Warm Start",
+ ws_result = check_ttff_data(self.ad,
+ ws_ttff_data,
+ ttff_mode="Warm Start",
criteria=self.xtra_ws_criteria)
xtra_result.append(ws_result)
begin_time = get_current_epoch_time()
@@ -801,7 +814,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="cs", iteration=10)
cs_ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- cs_result = check_ttff_data(self.ad, cs_ttff_data, ttff_mode="Cold Start",
+ cs_result = check_ttff_data(self.ad,
+ cs_ttff_data,
+ ttff_mode="Cold Start",
criteria=self.wifi_xtra_cs_criteria)
xtra_result.append(cs_result)
asserts.assert_true(all(xtra_result),
@@ -833,9 +848,9 @@
start_ttff_by_gtw_gpstool(self.ad, ttff_mode="cs", iteration=3)
ttff_data = process_ttff_by_gtw_gpstool(self.ad, begin_time,
self.pixel_lab_location)
- xtra_ssr_test_result = check_ttff_data(self.ad, ttff_data,
- ttff_mode="Cold Start",
- criteria=self.xtra_cs_criteria)
+ xtra_ssr_test_result = check_ttff_data(
+ self.ad, ttff_data, ttff_mode="Cold Start",
+ criteria=self.xtra_cs_criteria)
self.ad.log.info("XTRA after Modem SSR test %d times -> %s"
% (times, xtra_ssr_test_result))
xtra_ssr_test_result_all.append(xtra_ssr_test_result)
@@ -889,8 +904,8 @@
self.ad.log.info("Turn airplane mode on")
force_airplane_mode(self.ad, True)
wifi_toggle_state(self.ad, True)
- connect_to_wifi_network(self.ad,
- self.ssid_map[self.pixel_lab_network[0]["SSID"]])
+ connect_to_wifi_network(
+ self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
for i in range(1, 6):
begin_time = get_current_epoch_time()
process_gnss_by_gtw_gpstool(self.ad, self.standalone_cs_criteria)
@@ -901,3 +916,23 @@
self.ad.log.info("Iteraion %d => %s" % (i, wifi_xtra_result))
asserts.assert_true(all(wifi_xtra_result_all),
"Fail to Download XTRA file")
+
+ @test_tracker_info(uuid="2a9f2890-3c0a-48b8-821d-bf97e36355e9")
+ def test_quick_toggle_gnss_state(self):
+ """Verify GNSS can still work properly after quick toggle GNSS off
+ to on.
+
+ Steps:
+ 1. Launch GTW_GPSTool.
+ 2. Go to "Advance setting"
+ 3. Set Cycle = 10 & Time-out = 60
+ 4. Go to "Toggle GPS" tab
+ 5. Execute "Start"
+
+ Expected Results:
+ No single Timeout is seen in 10 iterations.
+ """
+ enable_supl_mode(self.ad)
+ reboot(self.ad)
+ start_qxdm_logger(self.ad, get_current_epoch_time())
+ start_toggle_gnss_by_gtw_gpstool(self.ad, iteration=10)
diff --git a/acts/tests/google/native/NativeTest.py b/acts/tests/google/native/NativeTest.py
index be5fd2a..90ebceb 100644
--- a/acts/tests/google/native/NativeTest.py
+++ b/acts/tests/google/native/NativeTest.py
@@ -24,7 +24,6 @@
def __init__(self, controllers):
BaseTestClass.__init__(self, controllers)
- self.droid = self.native_android_devices[0].droid
self.tests = (
"test_bool_return_true",
"test_bool_return_false",
@@ -33,6 +32,10 @@
"test_max_param_size",
)
+ def setup_class(self):
+ super().setup_class()
+ self.droid = self.native_android_devices[0].droid
+
def test_bool_return_true(self):
return self.droid.TestBoolTrueReturn()
diff --git a/acts/tests/google/native/bt/BtNativeTest.py b/acts/tests/google/native/bt/BtNativeTest.py
index 5315e34..55674bc 100644
--- a/acts/tests/google/native/bt/BtNativeTest.py
+++ b/acts/tests/google/native/bt/BtNativeTest.py
@@ -1,4 +1,3 @@
-mport time
from acts.base_test import BaseTestClass
from acts.controllers import native_android_device
from acts.test_utils.bt.native_bt_test_utils import setup_native_bluetooth
@@ -10,13 +9,15 @@
def __init__(self, controllers):
BaseTestClass.__init__(self, controllers)
- setup_native_bluetooth(self.native_android_devices)
- self.droid = self.native_android_devices[0].droid
self.tests = (
"test_binder_get_name",
"test_binder_get_name_invalid_parameter",
"test_binder_set_name_get_name",
"test_binder_get_address", )
+
+ def setup_class(self):
+ setup_native_bluetooth(self.native_android_devices)
+ self.droid = self.native_android_devices[0].droid
if len(self.native_android_devices) > 1:
self.droid1 = self.native_android_devices[1].droid
self.tests = self.tests + ("test_two_devices_set_get_name", )
diff --git a/acts/tests/google/net/CoreNetworkingOTATest.py b/acts/tests/google/net/CoreNetworkingOTATest.py
index 2444971..5b350f8 100755
--- a/acts/tests/google/net/CoreNetworkingOTATest.py
+++ b/acts/tests/google/net/CoreNetworkingOTATest.py
@@ -84,7 +84,7 @@
for ad in self.android_devices:
ota_updater.update(ad)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def on_fail(self, test_name, begin_time):
diff --git a/acts/tests/google/net/DnsOverTlsTest.py b/acts/tests/google/net/DnsOverTlsTest.py
index e69a5ae..e8a883d 100644
--- a/acts/tests/google/net/DnsOverTlsTest.py
+++ b/acts/tests/google/net/DnsOverTlsTest.py
@@ -86,28 +86,27 @@
"""
return stop_tcpdump(ad, self.tcpdump_pid, self.test_name)
- def _verify_dns_queries_over_tls(self, pcap_file, dns, tls=True):
+ def _verify_dns_queries_over_tls(self, pcap_file, tls=True):
""" Verify if DNS queries were over TLS or not
Args:
1. pcap_file: tcpdump file
- 2. dns: private DNS set in strict mode
- 3. tls: if queries should be over TLS or port 853
+ 2. tls: if queries should be over TLS or port 853
"""
- if not dns:
- dns = cconst.DNS_GOOGLE
try:
packets = rdpcap(pcap_file)
- except Scapy_Exception:
+ except Scapy_Excaption:
asserts.fail("Not a valid pcap file")
for pkt in packets:
summary = "%s" % pkt.summary()
- if tls and UDP in pkt and pkt[UDP].dport == 53 and \
- dns not in summary and 'mtalk.google.com' not in summary:
- asserts.fail("Found query to port 53: %s" % summary)
- elif not tls and TCP in pkt and pkt[TCP].dport == 853 and \
- not pkt[TCP].flags:
- asserts.fail("Found query to port 853: %s" % summary)
+ for host in self.ping_hosts:
+ host = host.split('.')[-2]
+ if tls and UDP in pkt and pkt[UDP].dport == 53 and \
+ host in summary:
+ asserts.fail("Found query to port 53: %s" % summary)
+ elif not tls and TCP in pkt and pkt[TCP].dport == 853 and \
+ not pkt[TCP].flags:
+ asserts.fail("Found query to port 853: %s" % summary)
def _verify_rst_packets(self, pcap_file):
""" Verify if RST packets are found in the pcap file
@@ -155,7 +154,7 @@
pcap_file = self._stop_tcp_dump(self.dut)
# verify DNS queries
- self._verify_dns_queries_over_tls(pcap_file, hostname, use_tls)
+ self._verify_dns_queries_over_tls(pcap_file, use_tls)
# reset wifi
wutils.reset_wifi(self.dut)
diff --git a/acts/tests/google/power/tel/lab/PowerTelHotspotTest.py b/acts/tests/google/power/tel/lab/PowerTelHotspotTest.py
index 59a9dc6..66aa458 100644
--- a/acts/tests/google/power/tel/lab/PowerTelHotspotTest.py
+++ b/acts/tests/google/power/tel/lab/PowerTelHotspotTest.py
@@ -106,12 +106,14 @@
dut.droid.wifiSetCountryCode(country_code)
# Setup tethering
- wutils.start_wifi_tethering(
- self.dut, self.network[wutils.WifiEnums.SSID_KEY],
- self.network[wutils.WifiEnums.PWD_KEY], self.wifi_band)
+ wutils.start_wifi_tethering(self.dut,
+ self.network[wutils.WifiEnums.SSID_KEY],
+ self.network[wutils.WifiEnums.PWD_KEY],
+ self.wifi_band)
- wutils.wifi_connect(
- self.android_devices[1], self.network, check_connectivity=False)
+ wutils.wifi_connect(self.android_devices[1],
+ self.network,
+ check_connectivity=False)
# Start data traffic
iperf_helpers = self.start_tel_traffic(self.android_devices[1])
diff --git a/acts/tests/google/power/tel/lab/PowerTelIdleTest.py b/acts/tests/google/power/tel/lab/PowerTelIdleTest.py
index 7af7cdc..934fe20 100644
--- a/acts/tests/google/power/tel/lab/PowerTelIdleTest.py
+++ b/acts/tests/google/power/tel/lab/PowerTelIdleTest.py
@@ -24,17 +24,16 @@
cellular idle scenarios to verify the ability to set power consumption
to a minimum during connectivity power tests.
"""
-
def power_tel_idle_test(self):
""" Measures power when the device is on LTE RRC idle state. """
idle_wait_time = self.simulation.rrc_sc_timer + 30
# Wait for RRC status change to trigger
- self.simulation.wait_for_rrc_idle_state(idle_wait_time)
+ self.cellular_simulator.wait_until_idle_state(idle_wait_time)
# Measure power
self.collect_power_data()
# Check if power measurement is below the required value
- self.pass_fail_check()
\ No newline at end of file
+ self.pass_fail_check()
diff --git a/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py b/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
index 9e9a85f..97094e3 100644
--- a/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
+++ b/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
@@ -55,6 +55,11 @@
super().__init__(controllers)
+ # Verify that at least one PacketSender controller has been initialized
+ if not hasattr(self, 'packet_senders'):
+ raise RuntimeError('At least one packet sender controller needs '
+ 'to be defined in the test config files.')
+
# These variables are passed to iPerf when starting data
# traffic with the -b parameter to limit throughput on
# the application layer.
@@ -212,8 +217,9 @@
"current simulation class.")
else:
- self.log.info("The expected {} throughput is {} Mbit/s.".format(
- direction, expected_t))
+ self.log.info(
+ "The expected {} throughput is {} Mbit/s.".format(
+ direction, expected_t))
asserts.assert_true(
0.90 < throughput / expected_t < 1.10,
"{} throughput differed more than 10% from the expected "
@@ -237,7 +243,8 @@
"""
# The iPerf server is hosted in this computer
- self.iperf_server_address = scapy.get_if_addr(self.pkt_sender.interface)
+ self.iperf_server_address = scapy.get_if_addr(
+ self.packet_senders[0].interface)
# Start iPerf traffic
iperf_helpers = []
@@ -320,7 +327,8 @@
config = {
'traffic_type': 'TCP',
- 'duration': self.mon_duration + self.mon_offset + self.IPERF_MARGIN,
+ 'duration':
+ self.mon_duration + self.mon_offset + self.IPERF_MARGIN,
'start_meas_time': 4,
'server_idx': server_idx,
'port': self.iperf_servers[server_idx].port,
diff --git a/acts/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py b/acts/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
index c9378e4..135f583 100644
--- a/acts/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
+++ b/acts/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
@@ -37,6 +37,7 @@
from acts.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts.test_utils.tel.tel_test_utils import get_model_name
from acts.test_utils.tel.tel_test_utils import get_operator_name
+from acts.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
from acts.test_utils.tel.tel_test_utils import hangup_call
from acts.test_utils.tel.tel_test_utils import last_call_drop_reason
from acts.test_utils.tel.tel_test_utils import reboot_device
@@ -125,9 +126,11 @@
self.ad_reference = self.android_devices[1]
self.dut_model = get_model_name(self.dut)
self.dut_operator = get_operator_name(self.log, self.dut)
- self.dut_capabilities = self.dut.telephony.get("capabilities", [])
- self.dut_wfc_modes = self.dut.telephony.get("wfc_modes", [])
- self.reference_capabilities = self.ad_reference.telephony.get(
+ self.dut_subID = get_outgoing_voice_sub_id(self.dut)
+ self.dut_capabilities = self.dut.telephony["subscription"][self.dut_subID].get("capabilities", [])
+ self.dut_wfc_modes = self.dut.telephony["subscription"][self.dut_subID].get("wfc_modes", [])
+ self.ad_reference_subID = get_outgoing_voice_sub_id(self.ad_reference)
+ self.reference_capabilities = self.ad_reference.telephony["subscription"][self.ad_reference_subID].get(
"capabilities", [])
self.dut.log.info("DUT capabilities: %s", self.dut_capabilities)
self.skip_reset_between_cases = False
diff --git a/acts/tests/google/tel/live/TelLiveImsSettingsTest.py b/acts/tests/google/tel/live/TelLiveImsSettingsTest.py
index 64f81ca..7a6d384 100644
--- a/acts/tests/google/tel/live/TelLiveImsSettingsTest.py
+++ b/acts/tests/google/tel/live/TelLiveImsSettingsTest.py
@@ -86,9 +86,9 @@
subid].get("capabilities", [])
self.dut.log.info("DUT capabilities: %s", self.dut_capabilities)
if CAPABILITY_VOLTE not in self.dut_capabilities:
- raise signals.TestSkipClass("VoLTE is not supported")
+ raise signals.TestAbortClass("VoLTE is not supported")
if CAPABILITY_WFC not in self.dut_capabilities:
- raise signals.TestSkipClass("WFC is not supported")
+ raise signals.TestAbortClass("WFC is not supported")
self.default_volte = (CAPABILITY_VOLTE in self.dut_capabilities) and (
self.carrier_configs[CarrierConfigs.
diff --git a/acts/tests/google/tel/live/TelLiveNoQXDMLogTest.py b/acts/tests/google/tel/live/TelLiveNoQXDMLogTest.py
index 94c2cbf..86e9927 100644
--- a/acts/tests/google/tel/live/TelLiveNoQXDMLogTest.py
+++ b/acts/tests/google/tel/live/TelLiveNoQXDMLogTest.py
@@ -69,10 +69,12 @@
def setup_class(self):
super().setup_class()
self.dut = self.android_devices[0]
- self.ad_reference = self.android_devices[1] if len(
- self.android_devices) > 1 else None
+ if len(self.android_devices) > 1:
+ self.ad_reference = self.android_devices[1]
+ setattr(self.ad_reference, "qxdm_log", False)
+ else:
+ self.ad_reference = None
setattr(self.dut, "qxdm_log", False)
- setattr(self.ad_reference, "qxdm_log", False)
self.stress_test_number = int(
self.user_params.get("stress_test_number", 5))
self.skip_reset_between_cases = False
@@ -379,9 +381,8 @@
begin_time = get_current_epoch_time()
for i in range(3):
try:
- bugreport_path = os.path.join(ad.log_path, self.test_name)
- create_dir(bugreport_path)
ad.take_bug_report(self.test_name, begin_time)
+ bugreport_path = ad.device_log_path
break
except Exception as e:
ad.log.error("bugreport attempt %s error: %s", i + 1, e)
@@ -406,9 +407,11 @@
exe_cmd("tar -xvf %s" %
(bugreport_path + "/dumpstate_board.tar"))
os.chdir(current_dir)
- if os.path.isfile(bugreport_path + "/power_anomaly_data.txt"):
- ad.log.info("Modem Power Anomaly File Exists!!")
- return True
+ else:
+ ad.log.info("The dumpstate_path file %s does not exist" % dumpstate_path)
+ if os.path.isfile(bugreport_path + "/power_anomaly_data.txt"):
+ ad.log.info("Modem Power Anomaly File Exists!!")
+ return True
ad.log.info("Modem Power Anomaly File DO NOT Exist!!")
return False
except Exception as e:
@@ -504,7 +507,8 @@
ad.wait_for_boot_completion()
ad.root_adb()
ad.log.info("Re-install sl4a")
- ad.adb.shell("settings put global package_verifier_enable 0")
+ ad.adb.shell("settings put global verifier_verify_adb_installs"
+ " 0")
ad.adb.install("-r /tmp/base.apk")
time.sleep(10)
try:
diff --git a/acts/tests/google/tel/live/TelLiveRebootStressTest.py b/acts/tests/google/tel/live/TelLiveRebootStressTest.py
index 70677e1..2936d9e 100644
--- a/acts/tests/google/tel/live/TelLiveRebootStressTest.py
+++ b/acts/tests/google/tel/live/TelLiveRebootStressTest.py
@@ -95,8 +95,9 @@
self.user_params["check_crash"] = False
self.skip_reset_between_cases = False
- self.dut_capabilities = self.dut.telephony.get("capabilities", [])
- self.dut_wfc_modes = self.dut.telephony.get("wfc_modes", [])
+ self.dut_subID = get_outgoing_voice_sub_id(self.dut)
+ self.dut_capabilities = self.dut.telephony["subscription"][self.dut_subID].get("capabilities", [])
+ self.dut_wfc_modes = self.dut.telephony["subscription"][self.dut_subID].get("wfc_modes", [])
self.default_testing_func_names = []
for method in ("_check_volte", "_check_vt", "_check_csfb",
"_check_tethering", "_check_wfc_apm",
diff --git a/acts/tests/google/tel/live/TelLiveSettingsTest.py b/acts/tests/google/tel/live/TelLiveSettingsTest.py
index 791e9e7..10b045f 100644
--- a/acts/tests/google/tel/live/TelLiveSettingsTest.py
+++ b/acts/tests/google/tel/live/TelLiveSettingsTest.py
@@ -51,7 +51,8 @@
self.number_of_devices = 1
self.stress_test_number = self.get_stress_test_number()
self.carrier_configs = dumpsys_carrier_config(self.dut)
- self.dut_capabilities = self.dut.telephony.get("capabilities", [])
+ self.dut_subID = get_outgoing_voice_sub_id(self.dut)
+ self.dut_capabilities = self.dut.telephony["subscription"][self.dut_subID].get("capabilities", [])
@test_tracker_info(uuid="c6149bd6-7080-453d-af37-1f9bd350a764")
@TelephonyBaseTest.tel_test_wrap
diff --git a/acts/tests/google/tel/live/TelLiveStressTest.py b/acts/tests/google/tel/live/TelLiveStressTest.py
index 899e758..6a4276d 100644
--- a/acts/tests/google/tel/live/TelLiveStressTest.py
+++ b/acts/tests/google/tel/live/TelLiveStressTest.py
@@ -125,7 +125,9 @@
self.file_download_method = "curl"
else:
self.android_devices = self.android_devices[:2]
+ self.sdm_log = self.user_params.get("sdm_log", False)
for ad in self.android_devices:
+ setattr(ad, "sdm_log", self.sdm_log)
ad.adb.shell("setprop nfc.debug_enable 1")
if self.user_params.get("turn_on_tcpdump", False):
start_adb_tcpdump(ad, interface="any", mask="all")
@@ -150,7 +152,6 @@
self.dut_incall = False
self.dsds_esim = self.user_params.get("dsds_esim", False)
self.cbrs_esim = self.user_params.get("cbrs_esim", False)
- self.sdm_log = self.user_params.get("sdm_log", False)
telephony_info = getattr(self.dut, "telephony", {})
self.dut_capabilities = telephony_info.get("capabilities", [])
self.dut_wfc_modes = telephony_info.get("wfc_modes", [])
@@ -1102,7 +1103,7 @@
def test_lte_volte_parallel_stress(self):
""" VoLTE on stress test"""
if CAPABILITY_VOLTE not in self.dut_capabilities:
- raise signals.TestSkipClass("VoLTE is not supported")
+ raise signals.TestAbortClass("VoLTE is not supported")
return self.parallel_tests(
setup_func=self._setup_lte_volte_enabled,
call_verification_func=is_phone_in_call_volte)
@@ -1120,7 +1121,7 @@
def test_wfc_parallel_stress(self):
""" Wifi calling APM mode off stress test"""
if CAPABILITY_WFC not in self.dut_capabilities:
- raise signals.TestSkipClass("WFC is not supported")
+ raise signals.TestAbortClass("WFC is not supported")
if WFC_MODE_WIFI_PREFERRED not in self.dut_wfc_modes:
raise signals.TestSkip("WFC_MODE_WIFI_PREFERRED is not supported")
return self.parallel_tests(
@@ -1132,7 +1133,7 @@
def test_wfc_apm_parallel_stress(self):
""" Wifi calling in APM mode on stress test"""
if CAPABILITY_WFC not in self.dut_capabilities:
- raise signals.TestSkipClass("WFC is not supported")
+ raise signals.TestAbortClass("WFC is not supported")
return self.parallel_tests(
setup_func=self._setup_wfc_apm,
call_verification_func=is_phone_in_call_iwlan)
@@ -1158,7 +1159,7 @@
def test_volte_modeprefchange_parallel_stress(self):
""" VoLTE Mode Pref call stress test"""
if CAPABILITY_VOLTE not in self.dut_capabilities:
- raise signals.TestSkipClass("VoLTE is not supported")
+ raise signals.TestAbortClass("VoLTE is not supported")
return self.parallel_with_network_change_tests(
setup_func=self._setup_lte_volte_enabled)
diff --git a/acts/tests/google/wifi/WifiAutoUpdateTest.py b/acts/tests/google/wifi/WifiAutoUpdateTest.py
index 04fb850..33369a2 100755
--- a/acts/tests/google/wifi/WifiAutoUpdateTest.py
+++ b/acts/tests/google/wifi/WifiAutoUpdateTest.py
@@ -93,7 +93,7 @@
try:
ota_updater.update(self.dut)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def setup_test(self):
diff --git a/acts/tests/google/wifi/WifiCrashStressTest.py b/acts/tests/google/wifi/WifiCrashStressTest.py
index bf17ada..837112a 100644
--- a/acts/tests/google/wifi/WifiCrashStressTest.py
+++ b/acts/tests/google/wifi/WifiCrashStressTest.py
@@ -41,7 +41,7 @@
wutils.wifi_test_device_init(self.dut)
wutils.wifi_test_device_init(self.dut_client)
if not self.dut.is_apk_installed("com.google.mdstest"):
- raise signals.TestSkipClass("mdstest is not installed")
+ raise signals.TestAbortClass("mdstest is not installed")
req_params = ["dbs_supported_models", "stress_count"]
opt_param = ["reference_networks"]
self.unpack_userparams(
diff --git a/acts/tests/google/wifi/WifiPingTest.py b/acts/tests/google/wifi/WifiPingTest.py
index 551719d..8abe9eb 100644
--- a/acts/tests/google/wifi/WifiPingTest.py
+++ b/acts/tests/google/wifi/WifiPingTest.py
@@ -25,6 +25,7 @@
from acts import base_test
from acts import utils
from acts.controllers.utils_lib import ssh
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import ota_chamber
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from acts.test_utils.wifi import wifi_retail_ap as retail_ap
@@ -57,9 +58,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
self.tests = self.generate_test_cases(
@@ -107,6 +108,11 @@
self.testclass_results = []
# Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def teardown_class(self):
@@ -190,15 +196,15 @@
self.testcase_metric_logger.add_metric('ping_range',
result['range'])
# Evaluate test pass/fail
+ test_message = ('Attenuation at range is {}dB. Golden range is {}dB. '
+ 'LLStats at Range: {}'.format(
+ result['range'], rvr_range,
+ result['llstats_at_range']))
if result['range'] - rvr_range < -self.testclass_params[
'range_gap_threshold']:
- asserts.fail(
- 'Attenuation at range is {}dB. Golden range is {}dB'.format(
- result['range'], rvr_range))
+ asserts.fail(test_message)
else:
- asserts.explicit_pass(
- 'Attenuation at range is {}dB. Golden range is {}dB'.format(
- result['range'], rvr_range))
+ asserts.explicit_pass(test_message)
def pass_fail_check(self, result):
if 'range' in result['testcase_params']['test_type']:
@@ -233,6 +239,15 @@
ping_loss_over_att)
ping_range_result['range'] = (ping_range_result['atten_at_range'] +
ping_range_result['fixed_attenuation'])
+ ping_range_result['llstats_at_range'] = (
+ 'TX MCS = {0} ({1:.1f}%). '
+ 'RX MCS = {2} ({3:.1f}%)'.format(
+ ping_range_result['llstats'][range_index]['summary']
+ ['common_tx_mcs'], ping_range_result['llstats'][range_index]
+ ['summary']['common_tx_mcs_freq'] * 100,
+ ping_range_result['llstats'][range_index]['summary']
+ ['common_rx_mcs'], ping_range_result['llstats'][range_index]
+ ['summary']['common_rx_mcs_freq'] * 100))
# Save results
results_file_path = os.path.join(
@@ -241,22 +256,24 @@
json.dump(ping_range_result, results_file, indent=4)
# Plot results
- figure = wputils.BokehFigure(
- self.current_test_name,
- x_label='Timestamp (s)',
- primary_y='Round Trip Time (ms)')
- for idx, result in enumerate(ping_range_result['ping_results']):
- if len(result['rtt']) > 1:
- x_data = [
- t - result['time_stamp'][0] for t in result['time_stamp']
- ]
- figure.add_line(
- x_data, result['rtt'],
- 'RTT @ {}dB'.format(ping_range_result['attenuation'][idx]))
+ if 'range' not in self.current_test_name:
+ figure = wputils.BokehFigure(
+ self.current_test_name,
+ x_label='Timestamp (s)',
+ primary_y_label='Round Trip Time (ms)')
+ for idx, result in enumerate(ping_range_result['ping_results']):
+ if len(result['rtt']) > 1:
+ x_data = [
+ t - result['time_stamp'][0]
+ for t in result['time_stamp']
+ ]
+ figure.add_line(
+ x_data, result['rtt'], 'RTT @ {}dB'.format(
+ ping_range_result['attenuation'][idx]))
- output_file_path = os.path.join(
- self.log_path, '{}.html'.format(self.current_test_name))
- figure.generate_figure(output_file_path)
+ output_file_path = os.path.join(
+ self.log_path, '{}.html'.format(self.current_test_name))
+ figure.generate_figure(output_file_path)
def get_range_from_rvr(self):
"""Function gets range from RvR golden results
@@ -302,6 +319,7 @@
test_result: dict containing ping results and other meta data
"""
# Prepare results dict
+ llstats_obj = wputils.LinkLayerStats(self.dut)
test_result = collections.OrderedDict()
test_result['testcase_params'] = testcase_params.copy()
test_result['test_name'] = self.current_test_name
@@ -311,6 +329,7 @@
'fixed_attenuation'][str(testcase_params['channel'])]
test_result['rssi_results'] = []
test_result['ping_results'] = []
+ test_result['llstats'] = []
# Run ping and sweep attenuation as needed
zero_counter = 0
for atten in testcase_params['atten_range']:
@@ -321,12 +340,17 @@
int(testcase_params['ping_duration'] / 2 /
self.RSSI_POLL_INTERVAL), self.RSSI_POLL_INTERVAL,
testcase_params['ping_duration'] / 2)
+ # Refresh link layer stats
+ llstats_obj.update_stats()
current_ping_stats = wputils.get_ping_stats(
self.ping_server, self.dut_ip,
testcase_params['ping_duration'],
testcase_params['ping_interval'], testcase_params['ping_size'])
current_rssi = rssi_future.result()
test_result['rssi_results'].append(current_rssi)
+ llstats_obj.update_stats()
+ curr_llstats = llstats_obj.llstats_incremental.copy()
+ test_result['llstats'].append(curr_llstats)
if current_ping_stats['connected']:
self.log.info(
'Attenuation = {0}dB\tPacket Loss = {1}%\t'
@@ -395,9 +419,12 @@
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
current_network = self.dut.droid.wifiGetConnectionInfo()
- valid_connection = wutils.validate_connection(self.dut)
- if valid_connection and current_network['SSID'] == self.main_network[
- band]['SSID']:
+ try:
+ connected = wutils.validate_connection(self.dut) is not None
+ except:
+ connected = False
+ if connected and current_network['SSID'] == self.main_network[band][
+ 'SSID']:
self.log.info('Already connected to desired network')
else:
wutils.reset_wifi(self.dut)
@@ -541,9 +568,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = False
def setup_class(self):
@@ -567,10 +594,13 @@
range_vs_angle[curr_config]['position'].append(
curr_params['position'])
range_vs_angle[curr_config]['range'].append(test['range'])
+ range_vs_angle[curr_config]['llstats_at_range'].append(
+ test['llstats_at_range'])
else:
range_vs_angle[curr_config] = {
'position': [curr_params['position']],
- 'range': [test['range']]
+ 'range': [test['range']],
+ 'llstats_at_range': [test['llstats_at_range']]
}
chamber_mode = self.testclass_results[0]['testcase_params'][
'chamber_mode']
@@ -581,11 +611,14 @@
figure = wputils.BokehFigure(
title='Range vs. Position',
x_label=x_label,
- primary_y='Range (dB)',
+ primary_y_label='Range (dB)',
)
for channel, channel_data in range_vs_angle.items():
- figure.add_line(channel_data['position'], channel_data['range'],
- 'Channel {}'.format(channel))
+ figure.add_line(
+ x_data=channel_data['position'],
+ y_data=channel_data['range'],
+ hover_text=channel_data['llstats_at_range'],
+ legend='Channel {}'.format(channel))
average_range = sum(channel_data['range']) / len(
channel_data['range'])
self.log.info('Average range for Channel {} is: {}dB'.format(
diff --git a/acts/tests/google/wifi/WifiRoamingPerformanceTest.py b/acts/tests/google/wifi/WifiRoamingPerformanceTest.py
index f05cc01..da57bf5 100644
--- a/acts/tests/google/wifi/WifiRoamingPerformanceTest.py
+++ b/acts/tests/google/wifi/WifiRoamingPerformanceTest.py
@@ -16,13 +16,13 @@
import collections
import json
-import logging
import math
import os
import time
from acts import asserts
from acts import base_test
from acts import context
+from acts import utils
from acts.controllers import iperf_server as ipf
from acts.controllers.utils_lib import ssh
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
@@ -89,6 +89,11 @@
self.log.info("RF Map (by Atten): {}".format(self.rf_map_by_atten))
#Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def pass_fail_traffic_continuity(self, result):
@@ -206,8 +211,8 @@
figure = wputils.BokehFigure(
title=self.current_test_name,
x_label='Time (ms)',
- primary_y=primary_y_axis,
- secondary_y='RSSI (dBm)')
+ primary_y_label=primary_y_axis,
+ secondary_y_label='RSSI (dBm)')
roam_stats[secondary_atten] = collections.OrderedDict()
for result in results_list:
self.detect_roam_events(result)
@@ -361,8 +366,8 @@
figure = wputils.BokehFigure(
title=self.current_test_name,
x_label='Time (ms)',
- primary_y='RTT (ms)',
- secondary_y='RSSI (dBm)')
+ primary_y_label='RTT (ms)',
+ secondary_y_label='RSSI (dBm)')
figure.add_line(
x_data=result['ping_result']['time_stamp'],
y_data=result['ping_result']['rtt'],
@@ -395,8 +400,8 @@
figure = wputils.BokehFigure(
title=self.current_test_name,
x_label='Time (s)',
- primary_y='Throughput (Mbps)',
- secondary_y='RSSI (dBm)')
+ primary_y_label='Throughput (Mbps)',
+ secondary_y_label='RSSI (dBm)')
iperf_time_stamps = [
idx * IPERF_INTERVAL for idx in range(len(result['throughput']))
]
diff --git a/acts/tests/google/wifi/WifiRssiTest.py b/acts/tests/google/wifi/WifiRssiTest.py
index 7b1e68e..91bfa9f 100644
--- a/acts/tests/google/wifi/WifiRssiTest.py
+++ b/acts/tests/google/wifi/WifiRssiTest.py
@@ -28,6 +28,7 @@
from acts import utils
from acts.controllers.utils_lib import ssh
from acts.controllers import iperf_server as ipf
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import ota_chamber
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from acts.test_utils.wifi import wifi_retail_ap as retail_ap
@@ -55,9 +56,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_test_metrics = True
def setup_class(self):
@@ -92,6 +93,11 @@
self.testclass_results = []
# Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def teardown_test(self):
@@ -301,7 +307,7 @@
figure = wputils.BokehFigure(
self.current_test_name,
x_label='Attenuation (dB)',
- primary_y='RSSI (dBm)')
+ primary_y_label='RSSI (dBm)')
figure.add_line(
postprocessed_results['total_attenuation'],
postprocessed_results['signal_poll_rssi']['mean'],
@@ -345,7 +351,7 @@
figure = wputils.BokehFigure(
self.current_test_name,
x_label='Time (s)',
- primary_y=center_curves * 'Centered' + 'RSSI (dBm)',
+ primary_y_label=center_curves * 'Centered' + 'RSSI (dBm)',
)
# yapf: disable
@@ -421,8 +427,8 @@
figure = wputils.BokehFigure(
self.current_test_name,
x_label='RSSI (dBm)',
- primary_y='p(RSSI = x)',
- secondary_y='p(RSSI <= x)')
+ primary_y_label='p(RSSI = x)',
+ secondary_y_label='p(RSSI <= x)')
for rssi_key, rssi_data in rssi_dist.items():
figure.add_line(
x_data=rssi_data['rssi_values'],
@@ -876,9 +882,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_test_metrics = False
def setup_class(self):
@@ -947,7 +953,7 @@
current_plot = wputils.BokehFigure(
title='Channel {} - Rssi vs. Position'.format(channel),
x_label=x_label,
- primary_y='RSSI (dBm)',
+ primary_y_label='RSSI (dBm)',
)
for rssi_metric, rssi_metric_value in channel_data['rssi'].items():
legend = rssi_metric
diff --git a/acts/tests/google/wifi/WifiRvrTest.py b/acts/tests/google/wifi/WifiRvrTest.py
index 7d72c16..43c9bbb 100644
--- a/acts/tests/google/wifi/WifiRvrTest.py
+++ b/acts/tests/google/wifi/WifiRvrTest.py
@@ -25,6 +25,7 @@
from acts import utils
from acts.controllers import iperf_server as ipf
from acts.controllers.utils_lib import ssh
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import ota_chamber
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from acts.test_utils.wifi import wifi_retail_ap as retail_ap
@@ -50,9 +51,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
def setup_class(self):
@@ -99,6 +100,11 @@
self.testclass_results = []
# Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def teardown_test(self):
@@ -124,7 +130,7 @@
result['testcase_params']['mode'],
result['testcase_params']['traffic_type']),
x_label='Attenuation (dB)',
- primary_y='Throughput (Mbps)')
+ primary_y_label='Throughput (Mbps)')
plots[plot_id].add_line(
result['total_attenuation'],
result['throughput_receive'],
@@ -251,7 +257,7 @@
figure = wputils.BokehFigure(
title=test_name,
x_label='Attenuation (dB)',
- primary_y='Throughput (Mbps)')
+ primary_y_label='Throughput (Mbps)')
try:
golden_path = next(file_name
for file_name in self.golden_files_list
@@ -314,11 +320,13 @@
]
for idx in range(len(tput_below_limit)):
if all(tput_below_limit[idx:]):
- rvr_result['metrics']['high_tput_range'] = rvr_result[
- 'total_attenuation'][max(idx, 1) - 1]
+ if idx == 0:
+ #Throughput was never above limit
+ rvr_result['metrics']['high_tput_range'] = -1
+ else:
+ rvr_result['metrics']['high_tput_range'] = rvr_result[
+ 'total_attenuation'][max(idx, 1) - 1]
break
- else:
- rvr_result['metrics']['high_tput_range'] = -1
if self.publish_testcase_metrics:
self.testcase_metric_logger.add_metric(
'high_tput_range', rvr_result['metrics']['high_tput_range'])
@@ -468,15 +476,18 @@
# Check battery level before test
if not wputils.health_check(
self.dut, 20) and testcase_params['traffic_direction'] == 'UL':
- asserts.skip('Battery level too low. Skipping test.')
+ asserts.skip('Overheating or Battery level low. Skipping test.')
# Turn screen off to preserve battery
self.dut.go_to_sleep()
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
current_network = self.dut.droid.wifiGetConnectionInfo()
- valid_connection = wutils.validate_connection(self.dut)
- if valid_connection and current_network['SSID'] == self.main_network[
- band]['SSID']:
+ try:
+ connected = wutils.validate_connection(self.dut) is not None
+ except:
+ connected = False
+ if connected and current_network['SSID'] == self.main_network[band][
+ 'SSID']:
self.log.info('Already connected to desired network')
else:
wutils.reset_wifi(self.dut)
@@ -682,9 +693,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = False
def setup_class(self):
@@ -726,7 +737,7 @@
result['testcase_params']['traffic_type'],
result['testcase_params']['traffic_direction']),
x_label='Attenuation (dB)',
- primary_y='Throughput (Mbps)')
+ primary_y_label='Throughput (Mbps)')
# Compile test id data and metrics
compiled_data[test_id]['throughput'].append(
result['throughput_receive'])
diff --git a/acts/tests/google/wifi/WifiSensitivityTest.py b/acts/tests/google/wifi/WifiSensitivityTest.py
index b262679..1947684 100644
--- a/acts/tests/google/wifi/WifiSensitivityTest.py
+++ b/acts/tests/google/wifi/WifiSensitivityTest.py
@@ -27,6 +27,7 @@
from acts import utils
from acts.controllers import iperf_client
from acts.controllers.utils_lib import ssh
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import ota_chamber
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from acts.test_utils.wifi import wifi_test_utils as wutils
@@ -126,9 +127,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
def setup_class(self):
@@ -175,6 +176,11 @@
self.testclass_results = []
# Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def teardown_class(self):
@@ -378,9 +384,12 @@
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
current_network = self.dut.droid.wifiGetConnectionInfo()
- valid_connection = wutils.validate_connection(self.dut)
- if valid_connection and current_network['SSID'] == self.main_network[
- band]['SSID']:
+ try:
+ connected = wutils.validate_connection(self.dut) is not None
+ except:
+ connected = False
+ if connected and current_network['SSID'] == self.main_network[band][
+ 'SSID']:
self.log.info('Already connected to desired network')
else:
wutils.reset_wifi(self.dut)
@@ -615,9 +624,9 @@
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = False
def setup_class(self):
@@ -680,7 +689,7 @@
curr_plot = wputils.BokehFigure(
title=str(test_id_str),
x_label='Orientation (deg)',
- primary_y='Sensitivity (dBm)')
+ primary_y_label='Sensitivity (dBm)')
for channel, channel_results in test_data.items():
curr_plot.add_line(
channel_results['orientation'],
diff --git a/acts/tests/google/wifi/WifiSoftApPerformanceTest.py b/acts/tests/google/wifi/WifiSoftApPerformanceTest.py
index f764b9f..a31812f 100644
--- a/acts/tests/google/wifi/WifiSoftApPerformanceTest.py
+++ b/acts/tests/google/wifi/WifiSoftApPerformanceTest.py
@@ -21,7 +21,7 @@
from acts import utils
from acts.controllers import iperf_server as ipf
from acts.controllers import iperf_client as ipc
-from acts.metrics.loggers.blackbox import BlackboxMetricLogger
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import wifi_test_utils as wutils
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from WifiRvrTest import WifiRvrTest
@@ -36,9 +36,9 @@
self.tests = ("test_rvr_TCP_DL_2GHz", "test_rvr_TCP_UL_2GHz",
"test_rvr_TCP_DL_5GHz", "test_rvr_TCP_UL_5GHz")
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
def setup_class(self):
diff --git a/acts/tests/google/wifi/WifiStressTest.py b/acts/tests/google/wifi/WifiStressTest.py
index 7ca8034..40a3108 100644
--- a/acts/tests/google/wifi/WifiStressTest.py
+++ b/acts/tests/google/wifi/WifiStressTest.py
@@ -61,7 +61,8 @@
req_params = []
opt_param = [
"open_network", "reference_networks", "iperf_server_address",
- "stress_count", "stress_hours", "attn_vals", "pno_interval"]
+ "stress_count", "stress_hours", "attn_vals", "pno_interval",
+ "iperf_server_port"]
self.unpack_userparams(
req_param_names=req_params, opt_param_names=opt_param)
@@ -76,12 +77,6 @@
self.open_2g = self.open_network[0]["2g"]
self.open_5g = self.open_network[0]["5g"]
self.networks = [self.wpa_2g, self.wpa_5g, self.open_2g, self.open_5g]
- if "iperf_server_address" in self.user_params:
- self.iperf_server = self.iperf_servers[0]
- if hasattr(self, 'iperf_server'):
- self.iperf_server.start()
- if(len(self.iperf_servers) > 1):
- self.iperf_servers[1].start()
def setup_test(self):
self.dut.droid.wakeLockAcquireBright()
@@ -100,10 +95,6 @@
def teardown_class(self):
wutils.reset_wifi(self.dut)
- if hasattr(self, 'iperf_server'):
- self.iperf_server.stop()
- if(len(self.iperf_servers) > 1):
- self.iperf_servers[1].stop()
if "AccessPoint" in self.user_params:
del self.user_params["reference_networks"]
del self.user_params["open_network"]
@@ -295,7 +286,7 @@
self.scan_and_connect_by_id(self.wpa_5g, net_id)
# Start IPerf traffic from phone to server.
# Upload data for 10s.
- args = "-p {} -t {}".format(self.iperf_server.port, 10)
+ args = "-p {} -t {}".format(self.iperf_server_port, 10)
self.log.info("Running iperf client {}".format(args))
result, data = self.dut.run_iperf_client(self.iperf_server_address, args)
if not result:
@@ -328,7 +319,7 @@
sec = self.stress_hours * 60 * 60
start_time = time.time()
- dl_args = "-p {} -t {} -R".format(self.iperf_server.port, sec)
+ dl_args = "-p {} -t {} -R".format(self.iperf_server_port, sec)
dl = threading.Thread(target=self.run_long_traffic, args=(sec, dl_args, q))
dl.start()
if(len(self.iperf_servers) > 1):
diff --git a/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py b/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py
index a603e01..0716158 100755
--- a/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py
+++ b/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py
@@ -52,7 +52,7 @@
try:
ota_updater.update(self.hotspot_device)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def on_fail(self, test_name, begin_time):
diff --git a/acts/tests/google/wifi/WifiTethering2GPskOTATest.py b/acts/tests/google/wifi/WifiTethering2GPskOTATest.py
index e9fedcd..7399e32 100755
--- a/acts/tests/google/wifi/WifiTethering2GPskOTATest.py
+++ b/acts/tests/google/wifi/WifiTethering2GPskOTATest.py
@@ -52,7 +52,7 @@
try:
ota_updater.update(self.hotspot_device)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def on_fail(self, test_name, begin_time):
diff --git a/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py b/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py
index 6648d0e..985e7a7 100755
--- a/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py
+++ b/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py
@@ -52,7 +52,7 @@
try:
ota_updater.update(self.hotspot_device)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def on_fail(self, test_name, begin_time):
diff --git a/acts/tests/google/wifi/WifiTethering5GPskOTATest.py b/acts/tests/google/wifi/WifiTethering5GPskOTATest.py
index 7450578..9e68f22 100755
--- a/acts/tests/google/wifi/WifiTethering5GPskOTATest.py
+++ b/acts/tests/google/wifi/WifiTethering5GPskOTATest.py
@@ -52,7 +52,7 @@
try:
ota_updater.update(self.hotspot_device)
except Exception as err:
- raise signals.TestSkipClass(
+ raise signals.TestAbortClass(
"Failed up apply OTA update. Aborting tests")
def on_fail(self, test_name, begin_time):
diff --git a/acts/tests/google/wifi/WifiThroughputStabilityTest.py b/acts/tests/google/wifi/WifiThroughputStabilityTest.py
index fd51961..f3e942f 100644
--- a/acts/tests/google/wifi/WifiThroughputStabilityTest.py
+++ b/acts/tests/google/wifi/WifiThroughputStabilityTest.py
@@ -27,6 +27,7 @@
from acts import utils
from acts.controllers import iperf_server as ipf
from acts.controllers.utils_lib import ssh
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts.test_utils.wifi import ota_chamber
from acts.test_utils.wifi import wifi_performance_test_utils as wputils
from acts.test_utils.wifi import wifi_retail_ap as retail_ap
@@ -52,9 +53,9 @@
base_test.BaseTestClass.__init__(self, controllers)
# Define metrics to be uploaded to BlackBox
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
# Generate test cases
self.tests = self.generate_test_cases(
@@ -132,6 +133,11 @@
self.testclass_results = []
# Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(
+ utils.force_airplane_mode(self.dut, True),
+ "Can not turn on airplane mode.")
wutils.wifi_toggle_state(self.dut, True)
def teardown_test(self):
@@ -221,7 +227,7 @@
json.dump(test_result_dict, results_file)
# Plot and save
figure = wputils.BokehFigure(
- test_name, x_label='Time (s)', primary_y='Throughput (Mbps)')
+ test_name, x_label='Time (s)', primary_y_label='Throughput (Mbps)')
time_data = list(range(0, len(instantaneous_rates_Mbps)))
figure.add_line(
time_data,
@@ -270,9 +276,12 @@
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
current_network = self.dut.droid.wifiGetConnectionInfo()
- valid_connection = wutils.validate_connection(self.dut)
- if valid_connection and current_network['SSID'] == self.main_network[
- band]['SSID']:
+ try:
+ connected = wutils.validate_connection(self.dut) is not None
+ except:
+ connected = False
+ if connected and current_network['SSID'] == self.main_network[band][
+ 'SSID']:
self.log.info('Already connected to desired network')
else:
wutils.wifi_toggle_state(self.dut, True)
@@ -448,9 +457,9 @@
base_test.BaseTestClass.__init__(self, controllers)
# Define metrics to be uploaded to BlackBox
self.testcase_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_case())
+ BlackboxMappedMetricLogger.for_test_case())
self.testclass_metric_logger = (
- wputils.BlackboxMappedMetricLogger.for_test_class())
+ BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = False
def setup_class(self):
@@ -517,7 +526,7 @@
current_plot = wputils.BokehFigure(
title='Channel {} - Rate vs. Position'.format(channel),
x_label=x_label,
- primary_y='Rate (Mbps)',
+ primary_y_label='Rate (Mbps)',
)
for test_id, test_data in channel_data.items():
test_id_dict = dict(test_id)
diff --git a/acts/tests/meta/ActsUnitTest.py b/acts/tests/meta/ActsUnitTest.py
new file mode 100755
index 0000000..f383ade
--- /dev/null
+++ b/acts/tests/meta/ActsUnitTest.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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 logging
+import os
+import subprocess
+import sys
+
+import acts
+from acts import base_test
+from acts import signals
+
+# The files under acts/framework to consider as unit tests.
+UNITTEST_FILES = [
+ 'tests/acts_adb_test.py',
+ 'tests/acts_android_device_test.py',
+ 'tests/acts_asserts_test.py',
+ 'tests/acts_base_class_test.py',
+ 'tests/config/unittest_bundle.py',
+ 'tests/acts_context_test.py',
+ 'tests/acts_error_test.py',
+ 'tests/acts_host_utils_test.py',
+ 'tests/acts_import_test_utils_test.py',
+ 'tests/acts_import_unit_test.py',
+ 'tests/acts_job_test.py',
+ 'tests/libs/ota/unittest_bundle.py',
+ 'tests/acts_logger_test.py',
+ 'tests/libs/metrics/unittest_bundle.py',
+ 'tests/acts_records_test.py',
+ 'tests/acts_relay_controller_test.py',
+ 'tests/acts_test_runner_test.py',
+ 'tests/acts_unittest_suite.py',
+ 'tests/acts_utils_test.py',
+ 'tests/controllers/android_lib/android_lib_unittest_bundle.py',
+ 'tests/event/event_unittest_bundle.py',
+ 'tests/test_utils/instrumentation/unit_test_suite.py',
+ 'tests/libs/logging/logging_unittest_bundle.py',
+ 'tests/metrics/unittest_bundle.py',
+ 'tests/libs/proc/proc_unittest_bundle.py',
+ 'tests/controllers/sl4a_lib/test_suite.py',
+ 'tests/test_runner_test.py',
+ 'tests/libs/version_selector_test.py',
+]
+
+# The number of seconds to wait before considering the unit test to have timed
+# out.
+UNITTEST_TIMEOUT = 60
+
+
+class ActsUnitTest(base_test.BaseTestClass):
+ """A class to run the ACTS unit tests in parallel.
+
+ This is a hack to run the ACTS unit tests through CI. Please use the main
+ function below if you need to run these tests.
+ """
+
+ def test_units(self):
+ """Runs all the ACTS unit tests in parallel."""
+ acts_unittest_path = os.path.dirname(acts.__path__[0])
+ test_processes = []
+
+ fail_test = False
+
+ for unittest_file in UNITTEST_FILES:
+ file_path = os.path.join(acts_unittest_path, unittest_file)
+ test_processes.append(
+ subprocess.Popen(
+ [sys.executable, file_path],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT))
+
+ for test_process in test_processes:
+ killed = False
+ try:
+ stdout, _ = test_process.communicate(timeout=UNITTEST_TIMEOUT)
+ except subprocess.TimeoutExpired:
+ killed = True
+ self.log.error('Unit test %s timed out after %s seconds.' %
+ (test_process.args, UNITTEST_TIMEOUT))
+ test_process.kill()
+ stdout, _ = test_process.communicate()
+ if test_process.returncode != 0 or killed:
+ self.log.error('=' * 79)
+ self.log.error('Unit Test %s failed with error %s.' %
+ (test_process.args, test_process.returncode))
+ self.log.error('=' * 79)
+ self.log.error('Failure for `%s`:\n%s' %
+ (test_process.args,
+ stdout.decode('utf-8', errors='replace')))
+ fail_test = True
+ else:
+ self.log.debug('Output for `%s`:\n%s' %
+ (test_process.args,
+ stdout.decode('utf-8', errors='replace')))
+
+ if fail_test:
+ raise signals.TestFailure(
+ 'One or more unit tests failed. See the logs.')
+
+
+def main():
+ ActsUnitTest({'log': logging.getLogger()}).test_units()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/acts/tests/meta/__init__.py b/acts/tests/meta/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/tests/meta/__init__.py
diff --git a/tools/create_virtualenv.sh b/tools/create_virtualenv.sh
new file mode 100755
index 0000000..3746ba2
--- /dev/null
+++ b/tools/create_virtualenv.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+python3 -m pip install virtualenv
+
+if [ $? -ne 0 ]; then
+ echo "Virtualenv must be installed to run the upload tests. Run: " >&2
+ echo " sudo python3 -m pip install virtualenv" >&2
+ exit 1
+fi
+
+virtualenv='/tmp/acts_preupload_virtualenv'
+
+python3 -m virtualenv -p python3 $virtualenv
+cp -r acts/framework $virtualenv/
+cd $virtualenv/framework
+$virtualenv/bin/python3 setup.py develop
+cd -