diff options
50 files changed, 724 insertions, 4051 deletions
diff --git a/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py b/acts/framework/acts/controllers/anritsu_lib/band_constants.py index d253cb33ad..c7f5771e54 100755..100644 --- a/acts/framework/tests/test_utils/instrumentation/unit_test_suite.py +++ b/acts/framework/acts/controllers/anritsu_lib/band_constants.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright 2019 - The Android Open Source Project +# Copyright 2020 - 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. @@ -14,19 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import sys -import unittest +# GSM BAND constants +GSM_BAND_GSM450 = "GSM450" +GSM_BAND_GSM480 = "GSM480" +GSM_BAND_GSM850 = "GSM850" +GSM_BAND_PGSM900 = "P-GSM900" +GSM_BAND_EGSM900 = "E-GSM900" +GSM_BAND_RGSM900 = "R-GSM900" +GSM_BAND_DCS1800 = "DCS1800" +GSM_BAND_PCS1900 = "PCS1900" - -def main(): - suite = unittest.TestLoader().discover( - start_dir=os.path.dirname(__file__), pattern='*_test.py') - return suite - - -if __name__ == '__main__': - test_suite = main() - runner = unittest.TextTestRunner() - test_run = runner.run(test_suite) - sys.exit(not test_run.wasSuccessful()) +LTE_BAND_2 = 2 +LTE_BAND_4 = 4 +LTE_BAND_12 = 12 +WCDMA_BAND_1 = 1 +WCDMA_BAND_2 = 2 diff --git a/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py b/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py index a8d79b5ebe..636b03f0a6 100644 --- a/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py +++ b/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py @@ -16,14 +16,14 @@ """ Sanity tests for voice tests in telephony """ +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_PCS1900 +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_GSM850 +from acts.controllers.anritsu_lib.band_constants import LTE_BAND_2 +from acts.controllers.anritsu_lib.band_constants import LTE_BAND_4 +from acts.controllers.anritsu_lib.band_constants import LTE_BAND_12 +from acts.controllers.anritsu_lib.band_constants import WCDMA_BAND_1 +from acts.controllers.anritsu_lib.band_constants import WCDMA_BAND_2 from acts.controllers.anritsu_lib.md8475a import BtsBandwidth -from acts.test_utils.tel.anritsu_utils import GSM_BAND_PCS1900 -from acts.test_utils.tel.anritsu_utils import GSM_BAND_GSM850 -from acts.test_utils.tel.anritsu_utils import LTE_BAND_2 -from acts.test_utils.tel.anritsu_utils import LTE_BAND_4 -from acts.test_utils.tel.anritsu_utils import LTE_BAND_12 -from acts.test_utils.tel.anritsu_utils import WCDMA_BAND_1 -from acts.test_utils.tel.anritsu_utils import WCDMA_BAND_2 # Different Cell configurations # TMO bands diff --git a/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py b/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py index 20c731b8fa..b7237f354c 100644 --- a/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py +++ b/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py @@ -17,15 +17,15 @@ import ntpath import time +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_DCS1800 +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_EGSM900 +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_GSM850 +from acts.controllers.anritsu_lib.band_constants import GSM_BAND_RGSM900 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.controllers.cellular_lib import BaseCellularDut from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation -from acts.test_utils.tel.anritsu_utils import GSM_BAND_DCS1800 -from acts.test_utils.tel.anritsu_utils import GSM_BAND_EGSM900 -from acts.test_utils.tel.anritsu_utils import GSM_BAND_GSM850 -from acts.test_utils.tel.anritsu_utils import GSM_BAND_RGSM900 class GsmSimulation(BaseSimulation): diff --git a/acts/framework/acts/test_utils/instrumentation/config_wrapper.py b/acts/framework/acts/test_utils/instrumentation/config_wrapper.py deleted file mode 100644 index 4bd1aa37f2..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/config_wrapper.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/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 collections -import os - - -class InvalidParamError(Exception): - pass - - -class ConfigWrapper(collections.UserDict): - """Class representing a test or preparer config.""" - - def __init__(self, config=None): - """Initialize a ConfigWrapper - - Args: - config: A dict representing the preparer/test parameters - """ - if config is None: - config = {} - super().__init__( - { - key: (ConfigWrapper(val) if isinstance(val, dict) else val) - for key, val in config.items() - } - ) - - def get(self, param_name, default=None, verify_fn=lambda _: True, - failure_msg=''): - """Get parameter from config, verifying that the value is valid - with verify_fn. - - Args: - param_name: Name of the param to fetch - default: Default value of param. - verify_fn: Callable to verify the param value. If it returns False, - an exception will be raised. - failure_msg: Exception message upon verify_fn failure. - """ - result = self.data.get(param_name, default) - if not verify_fn(result): - raise InvalidParamError('Invalid value "%s" for param %s. %s' - % (result, param_name, failure_msg)) - return result - - def get_config(self, param_name): - """Get a sub-config from config. Returns an empty ConfigWrapper if no - such sub-config is found. - """ - return self.get(param_name, default=ConfigWrapper()) - - def get_int(self, param_name, default=0): - """Get integer parameter from config. Will raise an exception - if result is not of type int. - """ - return self.get(param_name, default=default, - verify_fn=lambda val: type(val) is int, - failure_msg='Param must be of type int.') - - def get_numeric(self, param_name, default=0): - """Get int or float parameter from config. Will raise an exception if - result is not of type int or float. - """ - return self.get(param_name, default=default, - verify_fn=lambda val: type(val) in (int, float), - failure_msg='Param must be of type int or float.') diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py b/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/apps/__init__.py +++ /dev/null diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/app_installer.py b/acts/framework/acts/test_utils/instrumentation/device/apps/app_installer.py deleted file mode 100644 index 1688f0b7f0..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/apps/app_installer.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/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 os -import re - -from acts.libs.proc import job - -PKG_NAME_PATTERN = r"^package:\s+name='(?P<pkg_name>.*?)'" -PM_PATH_PATTERN = r"^package:(?P<apk_path>.*)" - - -class AppInstaller(object): - """Class that represents an app on an Android device. Includes methods - for install, uninstall, and getting info. - """ - def __init__(self, ad, apk_path): - """Initializes an AppInstaller. - - Args: - ad: device to install the apk - apk_path: path to the apk - """ - self._ad = ad - self._apk_path = apk_path - self._pkg_name = None - - @staticmethod - def pull_from_device(ad, pkg_name, dest): - """Initializes an AppInstaller by pulling the apk file from the device, - given the package name - - Args: - ad: device on which the apk is installed - pkg_name: package name - dest: destination directory - (Note: If path represents a directory, it must already exist as - a directory) - - Returns: AppInstaller object representing the pulled apk, or None if - package not installed - """ - if not ad.is_apk_installed(pkg_name): - ad.log.warning('Unable to find package %s on device. Pull aborted.' - % pkg_name) - return None - path_on_device = re.compile(PM_PATH_PATTERN).search( - ad.adb.shell('pm path %s' % pkg_name)).group('apk_path') - ad.pull_files(path_on_device, dest) - if os.path.isdir(dest): - dest = os.path.join(dest, os.path.basename(path_on_device)) - return AppInstaller(ad, dest) - - @property - def apk_path(self): - return self._apk_path - - @property - def pkg_name(self): - """Get the package name corresponding to the apk from aapt - - Returns: The package name, or empty string if not found. - """ - if self._pkg_name is None: - dump = job.run( - 'aapt dump badging %s' % self.apk_path, - ignore_status=True).stdout - match = re.compile(PKG_NAME_PATTERN).search(dump) - self._pkg_name = match.group('pkg_name') if match else '' - return self._pkg_name - - def install(self, *extra_args): - """Installs the apk on the device. - - Args: - extra_args: Additional flags to the ADB install command. - Note that '-r' is included by default. - """ - self._ad.log.info('Installing app %s from %s' % - (self.pkg_name, self.apk_path)) - args = '-r %s' % ' '.join(extra_args) - self._ad.adb.install('%s %s' % (args, self.apk_path)) - - def uninstall(self, *extra_args): - """Uninstalls the apk from the device. - - Args: - extra_args: Additional flags to the uninstall command. - """ - self._ad.log.info('Uninstalling app %s' % self.pkg_name) - if not self.is_installed(): - self._ad.log.warning('Unable to uninstall app %s. App is not ' - 'installed.' % self.pkg_name) - return - self._ad.adb.shell( - 'pm uninstall %s %s' % (' '.join(extra_args), self.pkg_name)) - - def is_installed(self): - """Verifies that the apk is installed on the device. - - Returns: True if the apk is installed on the device. - """ - if not self.pkg_name: - self._ad.log.warning('No package name found for %s' % self.apk_path) - return False - return self._ad.is_apk_installed(self.pkg_name) diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/dismiss_dialogs.py b/acts/framework/acts/test_utils/instrumentation/device/apps/dismiss_dialogs.py deleted file mode 100644 index 909326abcd..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/apps/dismiss_dialogs.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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 os - -from acts.test_utils.instrumentation.device.apps.app_installer import \ - AppInstaller -from acts.test_utils.instrumentation.device.command.instrumentation_command_builder \ - import InstrumentationCommandBuilder - -DISMISS_DIALOGS_RUNNER = '.DismissDialogsInstrumentation' -SCREENSHOTS_DIR = 'dialog-dismissal' -DISMISS_DIALOGS_TIMEOUT = 300 - - -class DialogDismissalUtil(object): - """Utility for dismissing app dialogs.""" - def __init__(self, dut, util_apk): - self._dut = dut - self._dismiss_dialogs_apk = AppInstaller(dut, util_apk) - self._dismiss_dialogs_apk.install('-g') - - def dismiss_dialogs(self, apps, screenshots=True, quit_on_error=True): - """Dismiss dialogs for the given apps. - - Args: - apps: List of apps to dismiss dialogs - screenshots: Boolean to enable screenshots upon dialog dismissal - quit_on_error: Boolean to indicate if tool should quit on failure - """ - if not apps: - return - if not isinstance(apps, list): - apps = [apps] - self._dut.log.info('Dismissing app dialogs for %s' % apps) - cmd_builder = InstrumentationCommandBuilder() - cmd_builder.set_manifest_package(self._dismiss_dialogs_apk.pkg_name) - cmd_builder.set_runner(DISMISS_DIALOGS_RUNNER) - cmd_builder.add_flag('-w') - cmd_builder.add_key_value_param('apps', ','.join(apps)) - cmd_builder.add_key_value_param('screenshots', screenshots) - cmd_builder.add_key_value_param('quitOnError', quit_on_error) - self._dut.adb.shell(cmd_builder.build(), - timeout=DISMISS_DIALOGS_TIMEOUT) - - # Pull screenshots if screenshots=True - if screenshots: - self._dut.pull_files( - os.path.join(self._dut.external_storage_path, SCREENSHOTS_DIR), - self._dut.device_log_path - ) - - def close(self): - """Clean up util by uninstalling the dialog dismissal APK.""" - self._dismiss_dialogs_apk.uninstall() diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/hotword_model_extractor.py b/acts/framework/acts/test_utils/instrumentation/device/apps/hotword_model_extractor.py deleted file mode 100644 index 57386b97ad..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/apps/hotword_model_extractor.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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 os -import tempfile -import zipfile - -from acts.test_utils.instrumentation.device.apps.app_installer \ - import AppInstaller - -DEFAULT_MODEL_NAME = 'en_us.mmap' -MODEL_DIR = 'res/raw' - - -class HotwordModelExtractor(object): - """ - Extracts a voice model data file from the Hotword APK and pushes it - onto the device. - """ - def __init__(self, dut): - self._dut = dut - - def extract_to_dut(self, hotword_pkg, model_name=DEFAULT_MODEL_NAME): - with tempfile.TemporaryDirectory() as tmp_dir: - extracted_model = self._extract(hotword_pkg, model_name, tmp_dir) - if not extracted_model: - return - device_dir = self._dut.adb.shell('echo $EXTERNAL_STORAGE') - self._dut.adb.push( - extracted_model, os.path.join(device_dir, model_name)) - - def _extract(self, hotword_pkg, model_name, dest): - """Extracts the model file from the given Hotword APK. - - Args: - hotword_pkg: Package name of the Hotword APK - model_name: File name of the model file. - dest: Destination directory - - Returns: Full path to the extracted model file. - """ - self._dut.log.info('Extracting voice model from Hotword APK.') - hotword_apk = AppInstaller.pull_from_device( - self._dut, hotword_pkg, dest) - if not hotword_apk: - self._dut.log.warning('Cannot extract Hotword voice model: ' - 'Hotword APK not installed.') - return None - - model_rel_path = os.path.join(MODEL_DIR, model_name) - with zipfile.ZipFile(hotword_apk.apk_path) as hotword_zip: - try: - return hotword_zip.extract(model_rel_path, dest) - except KeyError: - self._dut.log.warning( - 'Cannot extract Hotword voice model: Model file %s not ' - 'found.' % model_rel_path) - return None diff --git a/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py b/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py deleted file mode 100644 index 3973751573..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/apps/permissions.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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.test_utils.instrumentation.device.apps.app_installer import \ - AppInstaller -from acts.test_utils.instrumentation.device.command.instrumentation_command_builder \ - import InstrumentationCommandBuilder - -PERMISSION_RUNNER = '.PermissionInstrumentation' - - -class PermissionsUtil(object): - """Utility for granting all revoked runtime permissions.""" - def __init__(self, dut, util_apk): - self._dut = dut - self._permissions_apk = AppInstaller(dut, util_apk) - self._permissions_apk.install() - - def grant_all(self): - """Grant all runtime permissions with PermissionUtils.""" - self._dut.log.info('Granting all revoked runtime permissions.') - cmd_builder = InstrumentationCommandBuilder() - cmd_builder.set_manifest_package(self._permissions_apk.pkg_name) - cmd_builder.set_runner(PERMISSION_RUNNER) - cmd_builder.add_flag('-w') - cmd_builder.add_flag('-r') - cmd_builder.add_key_value_param('command', 'grant-all') - self._dut.adb.shell(cmd_builder.build()) - - def close(self): - """Clean up util by uninstalling the permissions APK.""" - self._permissions_apk.uninstall() diff --git a/acts/framework/acts/test_utils/instrumentation/device/command/adb_command_types.py b/acts/framework/acts/test_utils/instrumentation/device/command/adb_command_types.py deleted file mode 100644 index 072e1aecf7..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/command/adb_command_types.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/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.test_utils.instrumentation.device.command.intent_builder import \ - IntentBuilder - - -class DeviceState(object): - """Class for adb commands for setting device properties to a value.""" - - def __init__(self, base_cmd, on_val='1', off_val='0'): - """Create a DeviceState. - - Args: - base_cmd: The base adb command. Needs to accept an argument/value to - generate the full command. - on_val: Value used for the 'on' state - off_val: Value used for the 'off' state - """ - self._base_cmd = base_cmd - self._on_val = on_val - self._off_val = off_val - - def set_value(self, *values): - """Returns the adb command with the given arguments/values. - - Args: - values: The value(s) to run the command with - """ - try: - return self._base_cmd % values - except TypeError: - return str.strip(' '.join( - [self._base_cmd] + [str(value) for value in values])) - - def toggle(self, enabled): - """Returns the command corresponding to the desired state. - - Args: - enabled: True for the 'on' state. - """ - return self.set_value(self._on_val if enabled else self._off_val) - - -class DeviceSetprop(DeviceState): - """Class for setprop commands.""" - - def __init__(self, prop, on_val='1', off_val='0'): - """Create a DeviceSetprop. - - Args: - prop: Property name - on_val: Value used for the 'on' state - off_val: Value used for the 'off' state - """ - super().__init__('setprop %s' % prop, on_val, off_val) - - -class DeviceSetting(DeviceState): - """Class for commands to set a settings.db entry to a value.""" - - def __init__(self, namespace, setting, on_val='1', off_val='0'): - """Create a DeviceSetting. - - Args: - namespace: Namespace of the setting - setting: Setting name - on_val: Value used for the 'on' state - off_val: Value used for the 'off' state - """ - super().__init__('settings put %s %s' % (namespace, setting), - on_val, off_val) - - -class DeviceGServices(DeviceState): - """Class for overriding a GServices value.""" - - OVERRIDE_GSERVICES_INTENT = ('com.google.gservices.intent.action.' - 'GSERVICES_OVERRIDE') - - def __init__(self, setting, on_val='true', off_val='false'): - """Create a DeviceGServices. - - Args: - setting: Name of the GServices setting - on_val: Value used for the 'on' state - off_val: Value used for the 'off' state - """ - super().__init__(None, on_val, off_val) - self._intent_builder = IntentBuilder('am broadcast') - self._intent_builder.set_action(self.OVERRIDE_GSERVICES_INTENT) - self._setting = setting - - def set_value(self, value): - """Returns the adb command with the given value.""" - self._intent_builder.add_key_value_param(self._setting, value) - return self._intent_builder.build() - - -class DeviceBinaryCommandSeries(object): - """Class for toggling multiple settings at once.""" - - def __init__(self, binary_commands): - """Create a DeviceBinaryCommandSeries. - - Args: - binary_commands: List of commands for setting toggleable options - """ - self.cmd_list = binary_commands - - def toggle(self, enabled): - """Returns the list of command corresponding to the desired state. - - Args: - enabled: True for the 'on' state. - """ - return [cmd.toggle(enabled) for cmd in self.cmd_list] diff --git a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/__init__.py b/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/__init__.py +++ /dev/null diff --git a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/common.py b/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/common.py deleted file mode 100644 index bf853dc118..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/common.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/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.test_utils.instrumentation.device.command.adb_command_types \ - import DeviceBinaryCommandSeries -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetprop -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetting -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceState - -GLOBAL = 'global' -SYSTEM = 'system' -SECURE = 'secure' - -"""Common device settings for power testing.""" - -# TODO: add descriptions to each setting - -# Network/Connectivity - -airplane_mode = DeviceBinaryCommandSeries( - [ - DeviceSetting(GLOBAL, 'airplane_mode_on'), - DeviceState( - 'am broadcast -a android.intent.action.AIRPLANE_MODE --ez state', - 'true', 'false') - ] -) - -mobile_data = DeviceBinaryCommandSeries( - [ - DeviceSetting(GLOBAL, 'mobile_data'), - DeviceState('svc data', 'enable', 'disable') - ] -) - -cellular = DeviceSetting(GLOBAL, 'cell_on') - -wifi = DeviceBinaryCommandSeries( - [ - DeviceSetting(GLOBAL, 'wifi_on'), - DeviceState('svc wifi', 'enable', 'disable') - ] -) - -ethernet = DeviceState('ifconfig eth0', 'up', 'down') - -bluetooth = DeviceState('service call bluetooth_manager', '6', '8') - -nfc = DeviceState('svc nfc', 'enable', 'disable') - - -# Calling - -disable_dialing = DeviceSetprop('ro.telephony.disable-call', 'true', 'false') - - -# Screen - -screen_adaptive_brightness = DeviceSetting(SYSTEM, 'screen_brightness_mode') - -screen_brightness = DeviceSetting(SYSTEM, 'screen_brightness') - -screen_always_on = DeviceState('svc power stayon', 'true', 'false') - -screen_timeout_ms = DeviceSetting(SYSTEM, 'screen_off_timeout') - -doze_mode = DeviceSetting(SECURE, 'doze_enabled') - -doze_always_on = DeviceSetting(SECURE, 'doze_always_on') - -wake_gesture = DeviceSetting(SECURE, 'wake_gesture_enabled') - -screensaver = DeviceSetting(SECURE, 'screensaver_enabled') - -notification_led = DeviceSetting(SYSTEM, 'notification_light_pulse') - - -# Accelerometer - -auto_rotate = DeviceSetting(SYSTEM, 'accelerometer_rotation') - - -# Time - -auto_time = DeviceSetting(GLOBAL, 'auto_time') - -auto_timezone = DeviceSetting(GLOBAL, 'auto_timezone') - -timezone = DeviceSetprop('persist.sys.timezone') - - -# Location - -location_gps = DeviceSetting(SECURE, 'location_providers_allowed', - '+gps', '-gps') - -location_network = DeviceSetting(SECURE, 'location_providers_allowed', - '+network', '-network') - - -# Power - -battery_saver_mode = DeviceSetting(GLOBAL, 'low_power') - -battery_saver_trigger = DeviceSetting(GLOBAL, 'low_power_trigger_level') - -enable_full_batterystats_history = 'dumpsys batterystats --enable full-history' - -disable_doze = 'dumpsys deviceidle disable' - - -# Sensors - -disable_sensors = 'dumpsys sensorservice restrict blah' - -MOISTURE_DETECTION_SETTING_FILE = '/sys/class/power_supply/usb/moisture_detection_enabled' -disable_moisture_detection = 'echo 0 > %s' % MOISTURE_DETECTION_SETTING_FILE - -## Ambient EQ: https://support.google.com/googlenest/answer/9137130?hl=en -ambient_eq = DeviceSetting(SECURE, 'display_white_balance_enabled') - -# Miscellaneous - -test_harness = DeviceBinaryCommandSeries( - [ - DeviceSetprop('ro.monkey'), - DeviceSetprop('ro.test_harness') - ] -) - -dismiss_keyguard = 'wm dismiss-keyguard' diff --git a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/goog.py b/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/goog.py deleted file mode 100644 index 48f6bf1bf1..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/command/adb_commands/goog.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/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.test_utils.instrumentation.device.command.adb_command_types \ - import DeviceBinaryCommandSeries -from acts.test_utils.instrumentation.device.command.adb_command_types \ - import DeviceGServices -from acts.test_utils.instrumentation.device.command.adb_command_types \ - import DeviceState - -"""Google-internal device settings for power testing.""" - -# TODO: add descriptions to each setting - -# Location - -location_collection = DeviceGServices( - 'location:collection_enabled', on_val='1', off_val='0') - -location_opt_in = DeviceBinaryCommandSeries( - [ - DeviceState('content insert --uri content://com.google.settings/' - 'partner --bind name:s:use_location_for_services ' - '--bind value:s:%s'), - DeviceState('content insert --uri content://com.google.settings/' - 'partner --bind name:s:network_location_opt_in ' - '--bind value:s:%s') - ] -) - -# Cast - -cast_broadcast = DeviceGServices('gms:cast:mdns_device_scanner:is_enabled') - - -# Apps - -disable_playstore = 'pm disable-user com.android.vending' - - -# Volta - -disable_volta = 'pm disable-user com.google.android.volta' - - -# CHRE - -disable_chre = 'setprop ctl.stop vendor.chre' - - -# MusicIQ - -disable_musiciq = 'pm disable-user com.google.intelligence.sense' - - -# Hotword - -disable_hotword = ( - 'am start -a com.android.intent.action.MANAGE_VOICE_KEYPHRASES ' - '--ei com.android.intent.extra.VOICE_KEYPHRASE_ACTION 2 ' - '--es com.android.intent.extra.VOICE_KEYPHRASE_HINT_TEXT "demo" ' - '--es com.android.intent.extra.VOICE_KEYPHRASE_LOCALE "en-US" ' - 'com.android.hotwordenrollment.okgoogle/' - 'com.android.hotwordenrollment.okgoogle.EnrollmentActivity') diff --git a/acts/framework/acts/test_utils/instrumentation/device/command/intent_builder.py b/acts/framework/acts/test_utils/instrumentation/device/command/intent_builder.py deleted file mode 100644 index a1cc529f7a..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/device/command/intent_builder.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/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 collections - -TYPE_TO_FLAG = collections.defaultdict(lambda: '--es') -TYPE_TO_FLAG.update({bool: '--ez', int: '--ei', float: '--ef', str: '--es'}) - - -class IntentBuilder(object): - """Helper class to build am broadcast <INTENT> commands.""" - - def __init__(self, base_cmd=''): - """Initializes the intent command builder. - - Args: - base_cmd: The base am command, e.g. am broadcast, am start - """ - self._base_cmd = base_cmd - self._action = None - self._component = None - self._data_uri = None - self._flags = [] - self._key_value_params = collections.OrderedDict() - - def set_action(self, action): - """Set the intent action, as marked by the -a flag""" - self._action = action - - def set_component(self, package, component=None): - """Set the package and/or component, as marked by the -n flag. - Only the package name will be used if no component is specified. - """ - if component: - self._component = '%s/%s' % (package, component) - else: - self._component = package - - def set_data_uri(self, data_uri): - """Set the data URI, as marked by the -d flag""" - self._data_uri = data_uri - - def add_flag(self, flag): - """Add any additional flags to the intent argument""" - self._flags.append(flag) - - def add_key_value_param(self, key, value=None): - """Add any extra data as a key-value pair""" - self._key_value_params[key] = value - - def build(self): - """Returns the full intent command string.""" - cmd = [self._base_cmd] - if self._action: - cmd.append('-a %s' % self._action) - if self._component: - cmd.append('-n %s' % self._component) - if self._data_uri: - cmd.append('-d %s' % self._data_uri) - cmd += self._flags - for key, value in self._key_value_params.items(): - if value is None: - cmd.append('--esn %s' % key) - else: - str_value = str(value) - if isinstance(value, bool): - str_value = str_value.lower() - cmd.append(' '.join((TYPE_TO_FLAG[type(value)], key, - str_value))) - return ' '.join(cmd).strip() diff --git a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py b/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py deleted file mode 100644 index 5b9fda3b54..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/instrumentation_base_test.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/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 os - -import yaml -from acts.keys import Config -from acts.test_utils.instrumentation import instrumentation_proto_parser \ - as proto_parser -from acts.test_utils.instrumentation.config_wrapper import ConfigWrapper -from acts.test_utils.instrumentation.device.command.adb_commands import common - -from acts import base_test -from acts import context -from acts import utils - -RESOLVE_FILE_MARKER = 'FILE' -FILE_NOT_FOUND = 'File is missing from ACTS config' -DEFAULT_INSTRUMENTATION_CONFIG_FILE = 'instrumentation_config.yaml' - - -class InstrumentationTestError(Exception): - pass - - -class InstrumentationBaseTest(base_test.BaseTestClass): - """Base class for tests based on am instrument.""" - - def __init__(self, configs): - """Initialize an InstrumentationBaseTest - - Args: - configs: Dict representing the test configuration - """ - super().__init__(configs) - # Take instrumentation config path directly from ACTS config if found, - # otherwise try to find the instrumentation config in the same directory - # as the ACTS config - instrumentation_config_path = '' - if 'instrumentation_config' in self.user_params: - instrumentation_config_path = ( - self.user_params['instrumentation_config'][0]) - elif Config.key_config_path.value in self.user_params: - instrumentation_config_path = os.path.join( - self.user_params[Config.key_config_path.value], - DEFAULT_INSTRUMENTATION_CONFIG_FILE) - self._instrumentation_config = ConfigWrapper() - if os.path.exists(instrumentation_config_path): - self._instrumentation_config = self._load_instrumentation_config( - instrumentation_config_path) - self._class_config = self._instrumentation_config.get_config( - self.__class__.__name__) - else: - self.log.warning( - 'Instrumentation config file %s does not exist' % - instrumentation_config_path) - - def _load_instrumentation_config(self, path): - """Load the instrumentation config file into an - InstrumentationConfigWrapper object. - - Args: - path: Path to the instrumentation config file. - - Returns: The loaded instrumentation config as an - InstrumentationConfigWrapper - """ - try: - with open(path, mode='r', encoding='utf-8') as f: - config_dict = yaml.safe_load(f) - except Exception as e: - raise InstrumentationTestError( - 'Cannot open or parse instrumentation config file %s' - % path) from e - - # Write out a copy of the instrumentation config - with open(os.path.join( - self.log_path, 'instrumentation_config.yaml'), - mode='w', encoding='utf-8') as f: - yaml.safe_dump(config_dict, f) - - return ConfigWrapper(config_dict) - - def setup_class(self): - """Class setup""" - self.ad_dut = self.android_devices[0] - - def teardown_test(self): - """Test teardown. Takes bugreport and cleans up device.""" - self._ad_take_bugreport(self.ad_dut, 'teardown_class', - utils.get_current_epoch_time()) - self._cleanup_device() - - def _prepare_device(self): - """Prepares the device for testing.""" - pass - - def _cleanup_device(self): - """Clean up device after test completion.""" - pass - - 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: - 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: - case_config = self._class_config.get_config(self.current_test_name) - merged_config.update(case_config.get_config(config_name)) - return merged_config - - def get_files_from_config(self, config_key): - """Get a list of file paths on host from self.user_params with the - given key. Verifies that each file exists. - - Args: - config_key: Key in which the files are found. - - Returns: list of str file paths - """ - if config_key not in self.user_params: - raise InstrumentationTestError( - 'Cannot get files for key "%s": Key missing from config.' - % config_key) - files = self.user_params[config_key] - for f in files: - if not os.path.exists(f): - raise InstrumentationTestError( - 'Cannot get files for key "%s": No file exists for %s.' % - (config_key, f)) - return files - - def get_file_from_config(self, config_key): - """Get a single file path on host from self.user_params with the given - key. See get_files_from_config for details. - """ - return self.get_files_from_config(config_key)[-1] - - def adb_run(self, cmds): - """Run the specified command, or list of commands, with the ADB shell. - - Args: - cmds: A string or list of strings representing ADB shell command(s) - - Returns: dict mapping command to resulting stdout - """ - if isinstance(cmds, str): - cmds = [cmds] - out = {} - for cmd in cmds: - out[cmd] = self.ad_dut.adb.shell(cmd) - return out - - def adb_run_async(self, cmds): - """Run the specified command, or list of commands, with the ADB shell. - (async) - - Args: - cmds: A string or list of strings representing ADB shell command(s) - - Returns: dict mapping command to resulting subprocess.Popen object - """ - if isinstance(cmds, str): - cmds = [cmds] - procs = {} - for cmd in cmds: - procs[cmd] = self.ad_dut.adb.shell_nb(cmd) - return procs - - def dump_instrumentation_result_proto(self): - """Dump the instrumentation result proto as a human-readable txt file - in the log directory. - - Returns: The parsed instrumentation_data_pb2.Session - """ - session = proto_parser.get_session_from_device(self.ad_dut) - proto_txt_path = os.path.join( - context.get_current_context().get_full_output_path(), - 'instrumentation_proto.txt') - with open(proto_txt_path, 'w') as f: - f.write(str(session)) - return session - - # Basic setup methods - - def mode_airplane(self): - """Mode for turning on airplane mode only.""" - self.log.info('Enabling airplane mode.') - self.adb_run(common.airplane_mode.toggle(True)) - self.adb_run(common.auto_time.toggle(False)) - self.adb_run(common.auto_timezone.toggle(False)) - self.adb_run(common.location_gps.toggle(False)) - self.adb_run(common.location_network.toggle(False)) - self.adb_run(common.wifi.toggle(False)) - self.adb_run(common.bluetooth.toggle(False)) - - def mode_wifi(self): - """Mode for turning on airplane mode and wifi.""" - self.log.info('Enabling airplane mode and wifi.') - self.adb_run(common.airplane_mode.toggle(True)) - self.adb_run(common.location_gps.toggle(False)) - self.adb_run(common.location_network.toggle(False)) - self.adb_run(common.wifi.toggle(True)) - self.adb_run(common.bluetooth.toggle(False)) - - def mode_bluetooth(self): - """Mode for turning on airplane mode and bluetooth.""" - self.log.info('Enabling airplane mode and bluetooth.') - self.adb_run(common.airplane_mode.toggle(True)) - self.adb_run(common.auto_time.toggle(False)) - self.adb_run(common.auto_timezone.toggle(False)) - self.adb_run(common.location_gps.toggle(False)) - self.adb_run(common.location_network.toggle(False)) - self.adb_run(common.wifi.toggle(False)) - self.adb_run(common.bluetooth.toggle(True)) diff --git a/acts/framework/acts/test_utils/instrumentation/instrumentation_proto_parser.py b/acts/framework/acts/test_utils/instrumentation/instrumentation_proto_parser.py deleted file mode 100644 index bdff9b4061..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/instrumentation_proto_parser.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/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 collections -import os -import tempfile - -from acts.test_utils.instrumentation.proto.gen import instrumentation_data_pb2 - -DEFAULT_INST_LOG_DIR = 'instrument-logs' - -START_TIMESTAMP = 'start' -END_TIMESTAMP = 'end' - - -class ProtoParserError(Exception): - """Class for exceptions raised by the proto parser.""" - - -def pull_proto(ad, dest_dir, source_path=None): - """Pull latest instrumentation result proto from device. - - Args: - ad: AndroidDevice object - dest_dir: Directory on the host where the proto will be sent - source_path: Path on the device where the proto is generated. If None, - pull the latest proto from DEFAULT_INST_PROTO_DIR. - - Returns: Path to the retrieved proto file - """ - if source_path: - filename = os.path.basename(source_path) - else: - default_full_proto_dir = os.path.join( - ad.external_storage_path, DEFAULT_INST_LOG_DIR) - filename = ad.adb.shell('ls %s -t | head -n1' % default_full_proto_dir) - if not filename: - raise ProtoParserError( - 'No instrumentation result protos found at default location.') - source_path = os.path.join(default_full_proto_dir, filename) - ad.pull_files(source_path, dest_dir) - dest_path = os.path.join(dest_dir, filename) - if not os.path.exists(dest_path): - raise ProtoParserError( - 'Failed to pull instrumentation result proto: %s -> %s' - % (source_path, dest_path)) - return dest_path - - -def get_session_from_local_file(proto_file): - """Get a instrumentation_data_pb2.Session object from a proto file on the - host. - - Args: - proto_file: Path to the proto file (on host) - - Returns: A instrumentation_data_pb2.Session - """ - with open(proto_file, 'rb') as f: - return instrumentation_data_pb2.Session.FromString(f.read()) - - -def get_session_from_device(ad, proto_file=None): - """Get a instrumentation_data_pb2.Session object from a proto file on - device. - - Args: - ad: AndroidDevice object - proto_file: Path to the proto file (on device). If None, defaults to - latest proto from DEFAULT_INST_PROTO_DIR. - - Returns: A instrumentation_data_pb2.Session - """ - with tempfile.TemporaryDirectory() as tmp_dir: - pulled_proto = pull_proto(ad, tmp_dir, proto_file) - return get_session_from_local_file(pulled_proto) - - -def get_test_timestamps(session): - """Parse an instrumentation_data_pb2.Session to get the timestamps for each - test. - - Args: - session: an instrumentation_data.Session object - - Returns: a dict in the format - { - <test name> : (<begin_time>, <end_time>), - ... - } - """ - timestamps = collections.defaultdict(dict) - for test_status in session.test_status: - entries = test_status.results.entries - # Timestamp entries have the key 'timestamp-message' - if any(entry.key == 'timestamps-message' for entry in entries): - test_name = None - timestamp = None - timestamp_type = None - for entry in entries: - if entry.key == 'test': - test_name = entry.value_string - if entry.key == 'timestamp': - timestamp = entry.value_long - if entry.key == 'start-timestamp': - timestamp_type = START_TIMESTAMP - if entry.key == 'end-timestamp': - timestamp_type = END_TIMESTAMP - if test_name and timestamp and timestamp_type: - timestamps[test_name][timestamp_type] = timestamp - return timestamps diff --git a/acts/framework/acts/test_utils/instrumentation/power/__init__.py b/acts/framework/acts/test_utils/instrumentation/power/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/power/__init__.py +++ /dev/null diff --git a/acts/framework/acts/test_utils/instrumentation/power/instrumentation_power_test.py b/acts/framework/acts/test_utils/instrumentation/power/instrumentation_power_test.py deleted file mode 100644 index 92b9ad70e3..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/power/instrumentation_power_test.py +++ /dev/null @@ -1,486 +0,0 @@ -#!/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 os -import shutil -import tempfile -import time - -import tzlocal -from acts.controllers.android_device import SL4A_APK_NAME -from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger -from acts.test_utils.instrumentation import instrumentation_proto_parser \ - as proto_parser -from acts.test_utils.instrumentation.device.apps.app_installer import \ - AppInstaller -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceGServices -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetprop -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetting -from acts.test_utils.instrumentation.device.command.adb_commands import common -from acts.test_utils.instrumentation.device.command.adb_commands import goog -from acts.test_utils.instrumentation.device.command.instrumentation_command_builder \ - import DEFAULT_NOHUP_LOG -from acts.test_utils.instrumentation.device.command.instrumentation_command_builder \ - import InstrumentationTestCommandBuilder -from acts.test_utils.instrumentation.instrumentation_base_test \ - import InstrumentationBaseTest -from acts.test_utils.instrumentation.instrumentation_base_test \ - import InstrumentationTestError -from acts.test_utils.instrumentation.instrumentation_proto_parser import \ - DEFAULT_INST_LOG_DIR -from acts.test_utils.instrumentation.power.power_metrics import Measurement -from acts.test_utils.instrumentation.power.power_metrics import PowerMetrics -from acts.test_utils.instrumentation.device.apps.permissions import PermissionsUtil - -from acts import asserts -from acts import context - -ACCEPTANCE_THRESHOLD = 'acceptance_threshold' -AUTOTESTER_LOG = 'autotester.log' -DEFAULT_PUSH_FILE_TIMEOUT = 180 -DISCONNECT_USB_FILE = 'disconnectusb.log' -POLLING_INTERVAL = 0.5 - - -class InstrumentationPowerTest(InstrumentationBaseTest): - """Instrumentation test for measuring and validating power metrics. - - Params: - metric_logger: Blackbox metric logger used to store test metrics. - _instr_cmd_builder: Builder for the instrumentation command - """ - - def __init__(self, configs): - super().__init__(configs) - - self.metric_logger = BlackboxMappedMetricLogger.for_test_case() - self._test_apk = None - self._sl4a_apk = None - self._instr_cmd_builder = None - self._power_metrics = None - - def setup_class(self): - super().setup_class() - self.monsoon = self.monsoons[0] - self._setup_monsoon() - - def setup_test(self): - """Test setup""" - super().setup_test() - self._prepare_device() - self._instr_cmd_builder = self.power_instrumentation_command_builder() - return True - - def _prepare_device(self): - """Prepares the device for power testing.""" - super()._prepare_device() - self._cleanup_test_files() - self._permissions_util = PermissionsUtil( - self.ad_dut, - self.get_file_from_config('permissions_apk')) - self._permissions_util.grant_all() - self._install_test_apk() - - def _cleanup_device(self): - """Clean up device after power testing.""" - if self._test_apk: - self._test_apk.uninstall() - self._permissions_util.close() - self._cleanup_test_files() - - def base_device_configuration(self): - """Run the base setup commands for power testing.""" - self.log.info('Running base device setup commands.') - - self.ad_dut.adb.ensure_root() - self.adb_run(common.dismiss_keyguard) - self.ad_dut.ensure_screen_on() - - # Test harness flag - self.adb_run(common.test_harness.toggle(True)) - - # Calling - self.adb_run(common.disable_dialing.toggle(True)) - - # Screen - self.adb_run(common.screen_always_on.toggle(True)) - self.adb_run(common.screen_adaptive_brightness.toggle(False)) - - brightness_level = None - if 'brightness_level' in self._instrumentation_config: - brightness_level = self._instrumentation_config['brightness_level'] - - if brightness_level is None: - raise ValueError('no brightness level defined (or left as None) ' - 'and it is needed.') - - self.adb_run(common.screen_brightness.set_value(brightness_level)) - self.adb_run(common.screen_timeout_ms.set_value(1800000)) - self.adb_run(common.notification_led.toggle(False)) - self.adb_run(common.screensaver.toggle(False)) - self.adb_run(common.wake_gesture.toggle(False)) - self.adb_run(common.doze_mode.toggle(False)) - self.adb_run(common.doze_always_on.toggle(False)) - - # Sensors - self.adb_run(common.auto_rotate.toggle(False)) - self.adb_run(common.disable_sensors) - self.adb_run(common.ambient_eq.toggle(False)) - - if self.file_exists(common.MOISTURE_DETECTION_SETTING_FILE): - self.adb_run(common.disable_moisture_detection) - - # Time - self.adb_run(common.auto_time.toggle(False)) - self.adb_run(common.auto_timezone.toggle(False)) - self.adb_run(common.timezone.set_value(str(tzlocal.get_localzone()))) - - # Location - self.adb_run(common.location_gps.toggle(False)) - self.adb_run(common.location_network.toggle(False)) - - # Power - self.adb_run(common.battery_saver_mode.toggle(False)) - self.adb_run(common.battery_saver_trigger.set_value(0)) - self.adb_run(common.enable_full_batterystats_history) - self.adb_run(common.disable_doze) - - # Camera - self.adb_run(DeviceSetprop( - 'camera.optbar.hdr', 'true', 'false').toggle(True)) - - # Gestures - gestures = { - 'doze_pulse_on_pick_up': False, - 'doze_pulse_on_double_tap': False, - 'camera_double_tap_power_gesture_disabled': True, - 'camera_double_twist_to_flip_enabled': False, - 'assist_gesture_enabled': False, - 'assist_gesture_silence_alerts_enabled': False, - 'assist_gesture_wake_enabled': False, - 'system_navigation_keys_enabled': False, - 'camera_lift_trigger_enabled': False, - 'doze_always_on': False, - 'aware_enabled': False, - 'doze_wake_screen_gesture': False, - 'skip_gesture': False, - 'silence_gesture': False - } - self.adb_run( - [DeviceSetting(common.SECURE, k).toggle(v) - for k, v in gestures.items()]) - - # GServices - self.adb_run(goog.location_collection.toggle(False)) - self.adb_run(goog.cast_broadcast.toggle(False)) - self.adb_run(DeviceGServices( - 'location:compact_log_enabled').toggle(True)) - self.adb_run(DeviceGServices('gms:magictether:enable').toggle(False)) - self.adb_run(DeviceGServices('ocr.cc_ocr_enabled').toggle(False)) - self.adb_run(DeviceGServices( - 'gms:phenotype:phenotype_flag:debug_bypass_phenotype').toggle(True)) - self.adb_run(DeviceGServices( - 'gms_icing_extension_download_enabled').toggle(False)) - - # Comms - self.adb_run(common.wifi.toggle(False)) - self.adb_run(common.bluetooth.toggle(False)) - self.adb_run(common.airplane_mode.toggle(True)) - - # Misc. Google features - self.adb_run(goog.disable_playstore) - self.adb_run(goog.disable_volta) - self.adb_run(goog.disable_chre) - self.adb_run(goog.disable_musiciq) - self.adb_run(goog.disable_hotword) - - # Enable clock dump info - self.adb_run('echo 1 > /d/clk/debug_suspend') - - def _setup_monsoon(self): - """Set up the Monsoon controller for this testclass/testcase.""" - self.log.info('Setting up Monsoon %s' % self.monsoon.serial) - monsoon_config = self._get_merged_config('Monsoon') - self._monsoon_voltage = monsoon_config.get_numeric('voltage', 4.2) - self.monsoon.set_voltage_safe(self._monsoon_voltage) - if 'max_current' in monsoon_config: - self.monsoon.set_max_current( - monsoon_config.get_numeric('max_current')) - - self.monsoon.usb('on') - self.monsoon.set_on_disconnect(self._on_disconnect) - self.monsoon.set_on_reconnect(self._on_reconnect) - - self._disconnect_usb_timeout = monsoon_config.get_numeric( - 'usb_disconnection_timeout', 240) - - self._measurement_args = dict( - duration=monsoon_config.get_numeric('duration'), - hz=monsoon_config.get_numeric('frequency'), - measure_after_seconds=monsoon_config.get_numeric('delay') - ) - - def _on_disconnect(self): - """Callback invoked by device disconnection from the Monsoon.""" - self.ad_dut.log.info('Disconnecting device.') - self.ad_dut.stop_services() - # Uninstall SL4A - self._sl4a_apk = AppInstaller.pull_from_device( - self.ad_dut, SL4A_APK_NAME, tempfile.mkdtemp(prefix='sl4a')) - self._sl4a_apk.uninstall() - time.sleep(1) - - def _on_reconnect(self): - """Callback invoked by device reconnection to the Monsoon""" - # Reinstall SL4A - if not self.ad_dut.is_sl4a_installed() and self._sl4a_apk: - self._sl4a_apk.install() - shutil.rmtree(os.path.dirname(self._sl4a_apk.apk_path)) - self._sl4a_apk = None - self.ad_dut.start_services() - # Release wake lock to put device into sleep. - self.ad_dut.droid.goToSleepNow() - self.ad_dut.log.info('Device reconnected.') - - def _install_test_apk(self): - """Installs test apk on the device.""" - test_apk_file = self.get_file_from_config('test_apk') - self._test_apk = AppInstaller(self.ad_dut, test_apk_file) - self._test_apk.install('-g') - if not self._test_apk.is_installed(): - raise InstrumentationTestError('Failed to install test APK.') - - def _cleanup_test_files(self): - """Remove test-generated files from the device.""" - self.ad_dut.log.info('Cleaning up test generated files.') - for file_name in [DISCONNECT_USB_FILE, DEFAULT_INST_LOG_DIR, - DEFAULT_NOHUP_LOG, AUTOTESTER_LOG]: - path = os.path.join(self.ad_dut.external_storage_path, file_name) - self.adb_run('rm -rf %s' % path) - - def trigger_scan_on_external_storage(self): - cmd = 'am broadcast -a android.intent.action.MEDIA_MOUNTED ' - cmd = cmd + '-d file://%s ' % self.ad_dut.external_storage_path - cmd = cmd + '--receiver-include-background' - return self.adb_run(cmd) - - def file_exists(self, file_path): - cmd = '(test -f %s && echo yes) || echo no' % file_path - result = self.adb_run(cmd) - if result[cmd] == 'yes': - return True - elif result[cmd] == 'no': - return False - raise ValueError('Couldn\'t determine if %s exists. ' - 'Expected yes/no, got %s' % (file_path, result[cmd])) - - def push_to_external_storage(self, file_path, dest=None, - timeout=DEFAULT_PUSH_FILE_TIMEOUT): - """Pushes a file to {$EXTERNAL_STORAGE} and returns its final location. - - Args: - file_path: The file to be pushed. - dest: Where within {$EXTERNAL_STORAGE} it should be pushed. - timeout: Float number of seconds to wait for the file to be pushed. - - Returns: The absolute path where the file was pushed. - """ - if dest is None: - dest = os.path.basename(file_path) - - dest_path = os.path.join(self.ad_dut.external_storage_path, dest) - self.log.info('clearing %s before pushing %s' % (dest_path, file_path)) - self.ad_dut.adb.shell('rm -rf %s', dest_path) - self.log.info('pushing file %s to %s' % (file_path, dest_path)) - self.ad_dut.adb.push(file_path, dest_path, timeout=timeout) - return dest_path - - # Test runtime utils - - def power_instrumentation_command_builder(self): - """Return the default command builder for power tests""" - builder = InstrumentationTestCommandBuilder.default() - builder.set_manifest_package(self._test_apk.pkg_name) - builder.set_nohup() - return builder - - def _wait_for_disconnect_signal(self): - """Poll the device for a disconnect USB signal file. This will indicate - to the Monsoon that the device is ready to be disconnected. - """ - self.log.info('Waiting for USB disconnect signal') - disconnect_file = os.path.join( - self.ad_dut.external_storage_path, DISCONNECT_USB_FILE) - start_time = time.time() - while time.time() < start_time + self._disconnect_usb_timeout: - if self.ad_dut.adb.shell('ls %s' % disconnect_file): - return - time.sleep(POLLING_INTERVAL) - raise InstrumentationTestError('Timeout while waiting for USB ' - 'disconnect signal.') - - def measure_power(self): - """Measures power consumption with the Monsoon. See monsoon_lib API for - details. - """ - if not hasattr(self, '_measurement_args'): - raise InstrumentationTestError('Missing Monsoon measurement args.') - - # Start measurement after receiving disconnect signal - self._wait_for_disconnect_signal() - power_data_path = os.path.join( - context.get_current_context().get_full_output_path(), 'power_data') - self.log.info('Starting Monsoon measurement.') - self.monsoon.usb('auto') - measure_start_time = time.time() - result = self.monsoon.measure_power( - **self._measurement_args, output_path=power_data_path) - self.monsoon.usb('on') - self.log.info('Monsoon measurement complete.') - - # Gather relevant metrics from measurements - session = self.dump_instrumentation_result_proto() - self._power_metrics = PowerMetrics(self._monsoon_voltage, - start_time=measure_start_time) - self._power_metrics.generate_test_metrics( - PowerMetrics.import_raw_data(power_data_path), - proto_parser.get_test_timestamps(session)) - self._log_metrics() - return result - - def run_and_measure(self, instr_class, instr_method=None, req_params=None, - extra_params=None): - """Convenience method for setting up the instrumentation test command, - running it on the device, and starting the Monsoon measurement. - - Args: - instr_class: Fully qualified name of the instrumentation test class - instr_method: Name of the instrumentation test method - req_params: List of required parameter names - extra_params: List of ad-hoc parameters to be passed defined as - tuples of size 2. - - Returns: summary of Monsoon measurement - """ - if instr_method: - self._instr_cmd_builder.add_test_method(instr_class, instr_method) - else: - self._instr_cmd_builder.add_test_class(instr_class) - params = {} - instr_call_config = self._get_merged_config('instrumentation_call') - # Add required parameters - for param_name in req_params or []: - params[param_name] = instr_call_config.get( - param_name, verify_fn=lambda x: x is not None, - failure_msg='%s is a required parameter.' % param_name) - # Add all other parameters - params.update(instr_call_config) - for name, value in params.items(): - self._instr_cmd_builder.add_key_value_param(name, value) - - if extra_params: - for name, value in extra_params: - self._instr_cmd_builder.add_key_value_param(name, value) - - instr_cmd = self._instr_cmd_builder.build() - self.log.info('Running instrumentation call: %s' % instr_cmd) - self.adb_run_async(instr_cmd) - return self.measure_power() - - def _log_metrics(self): - """Record the collected metrics with the metric logger.""" - self.log.info('Obtained metrics summaries:') - for k, m in self._power_metrics.test_metrics.items(): - self.log.info('%s %s' % (k, str(m.summary))) - - for metric_name in PowerMetrics.ALL_METRICS: - for instr_test_name in self._power_metrics.test_metrics: - metric_value = getattr( - self._power_metrics.test_metrics[instr_test_name], - metric_name).value - # TODO: Refactor this into instr_test_name.metric_name - self.metric_logger.add_metric( - '%s__%s' % (metric_name, instr_test_name), metric_value) - - def validate_power_results(self, *instr_test_names): - """Compare power measurements with target values and set the test result - accordingly. - - Args: - instr_test_names: Name(s) of the instrumentation test method. - If none specified, defaults to all test methods run. - - Raises: - signals.TestFailure if one or more metrics do not satisfy threshold - """ - summaries = {} - failure = False - all_thresholds = self._get_merged_config(ACCEPTANCE_THRESHOLD) - - if not instr_test_names: - instr_test_names = all_thresholds.keys() - - for instr_test_name in instr_test_names: - try: - test_metrics = self._power_metrics.test_metrics[instr_test_name] - except KeyError: - raise InstrumentationTestError( - 'Unable to find test method %s in instrumentation output. ' - 'Check instrumentation call results in ' - 'instrumentation_proto.txt.' - % instr_test_name) - - summaries[instr_test_name] = {} - test_thresholds = all_thresholds.get_config(instr_test_name) - for metric_name, metric in test_thresholds.items(): - try: - actual_result = getattr(test_metrics, metric_name) - except AttributeError: - continue - - if 'unit_type' not in metric or 'unit' not in metric: - continue - unit_type = metric['unit_type'] - unit = metric['unit'] - - lower_value = metric.get_numeric('lower_limit', float('-inf')) - upper_value = metric.get_numeric('upper_limit', float('inf')) - if 'expected_value' in metric and 'percent_deviation' in metric: - expected_value = metric.get_numeric('expected_value') - percent_deviation = metric.get_numeric('percent_deviation') - lower_value = expected_value * (1 - percent_deviation / 100) - upper_value = expected_value * (1 + percent_deviation / 100) - - lower_bound = Measurement(lower_value, unit_type, unit) - upper_bound = Measurement(upper_value, unit_type, unit) - summary_entry = { - 'expected': '[%s, %s]' % (lower_bound, upper_bound), - 'actual': str(actual_result.to_unit(unit)) - } - summaries[instr_test_name][metric_name] = summary_entry - if not lower_bound <= actual_result <= upper_bound: - failure = True - self.log.info('Summary of measurements: %s' % summaries) - asserts.assert_false( - failure, - msg='One or more measurements do not meet the specified criteria', - extras=summaries) - asserts.explicit_pass( - msg='All measurements meet the criteria', - extras=summaries) diff --git a/acts/framework/acts/test_utils/instrumentation/power/power_metrics.py b/acts/framework/acts/test_utils/instrumentation/power/power_metrics.py deleted file mode 100644 index b41ae61741..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/power/power_metrics.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/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 math - -from acts.test_utils.instrumentation import instrumentation_proto_parser \ - as parser -from acts.test_utils.instrumentation.instrumentation_base_test \ - import InstrumentationTestError - -# Unit type constants -CURRENT = 'current' -POWER = 'power' -TIME = 'time' - -# Unit constants -MILLIAMP = 'mA' -AMP = 'A' -AMPERE = AMP -MILLIWATT = 'mW' -WATT = 'W' -MILLISECOND = 'ms' -SECOND = 's' -MINUTE = 'm' -HOUR = 'h' - -CONVERSION_TABLES = { - CURRENT: { - MILLIAMP: 0.001, - AMP: 1 - }, - POWER: { - MILLIWATT: 0.001, - WATT: 1 - }, - TIME: { - MILLISECOND: 0.001, - SECOND: 1, - MINUTE: 60, - HOUR: 3600 - } -} - - -class Measurement(object): - """Base class for describing power measurement values. Each object contains - an value and a unit. Enables some basic arithmetic operations with other - measurements of the same unit type. - - Attributes: - _value: Numeric value of the measurement - _unit_type: Unit type of the measurement (e.g. current, power) - _unit: Unit of the measurement (e.g. W, mA) - """ - - def __init__(self, value, unit_type, unit): - if unit_type not in CONVERSION_TABLES: - raise TypeError('%s is not a valid unit type' % unit_type) - self._value = value - self._unit_type = unit_type - self._unit = unit - - # Convenience constructor methods - @staticmethod - def amps(amps): - """Create a new current measurement, in amps.""" - return Measurement(amps, CURRENT, AMP) - - @staticmethod - def watts(watts): - """Create a new power measurement, in watts.""" - return Measurement(watts, POWER, WATT) - - @staticmethod - def seconds(seconds): - """Create a new time measurement, in seconds.""" - return Measurement(seconds, TIME, SECOND) - - # Comparison methods - - def __eq__(self, other): - return self.value == other.to_unit(self._unit).value - - def __lt__(self, other): - return self.value < other.to_unit(self._unit).value - - def __le__(self, other): - return self == other or self < other - - # Addition and subtraction with other measurements - - def __add__(self, other): - """Adds measurements of compatible unit types. The result will be in the - same units as self. - """ - return Measurement(self.value + other.to_unit(self._unit).value, - self._unit_type, self._unit) - - def __sub__(self, other): - """Subtracts measurements of compatible unit types. The result will be - in the same units as self. - """ - return Measurement(self.value - other.to_unit(self._unit).value, - self._unit_type, self._unit) - - # String representation - - def __str__(self): - return '%g%s' % (self._value, self._unit) - - def __repr__(self): - return str(self) - - @property - def unit(self): - return self._unit - - @property - def value(self): - return self._value - - def to_unit(self, new_unit): - """Create an equivalent measurement under a different unit. - e.g. 0.5W -> 500mW - - Args: - new_unit: Target unit. Must be compatible with current unit. - - Returns: A new measurement with the converted value and unit. - """ - try: - new_value = self._value * ( - CONVERSION_TABLES[self._unit_type][self._unit] / - CONVERSION_TABLES[self._unit_type][new_unit]) - except KeyError: - raise TypeError('Incompatible units: %s, %s' % - (self._unit, new_unit)) - return Measurement(new_value, self._unit_type, new_unit) - - -class PowerMetrics(object): - """Class for processing raw power metrics generated by Monsoon measurements. - Provides useful metrics such as average current, max current, and average - power. Can generate individual test metrics. - - See section "Numeric metrics" below for available metrics. - """ - - def __init__(self, voltage, start_time=0): - """Create a PowerMetrics. - - Args: - voltage: Voltage of the measurement - start_time: Start time of the measurement. Used for generating - test-specific metrics. - """ - self._voltage = voltage - self._start_time = start_time - self._num_samples = 0 - self._sum_currents = 0 - self._sum_squares = 0 - self._max_current = None - self._min_current = None - self.test_metrics = {} - - @staticmethod - def import_raw_data(path): - """Create a generator from a Monsoon data file. - - Args: - path: path to raw data file - - Returns: generator that yields (timestamp, sample) per line - """ - with open(path, 'r') as f: - for line in f: - time, sample = line.split() - yield float(time[:-1]), float(sample) - - def update_metrics(self, sample): - """Update the running metrics with the current sample. - - Args: - sample: A current sample in Amps. - """ - self._num_samples += 1 - self._sum_currents += sample - self._sum_squares += sample ** 2 - if self._max_current is None or sample > self._max_current: - self._max_current = sample - if self._min_current is None or sample < self._min_current: - self._min_current = sample - - def generate_test_metrics(self, raw_data, test_timestamps=None): - """Split the data into individual test metrics, based on the timestamps - given as a dict. - - Args: - raw_data: raw data as list or generator of (timestamp, sample) - test_timestamps: dict following the output format of - instrumentation_proto_parser.get_test_timestamps() - """ - - # Initialize metrics for each test - if test_timestamps is None: - test_timestamps = {} - test_starts = {} - test_ends = {} - for test_name, times in test_timestamps.items(): - self.test_metrics[test_name] = PowerMetrics( - self._voltage, self._start_time) - try: - test_starts[test_name] = Measurement( - times[parser.START_TIMESTAMP], TIME, MILLISECOND) \ - .to_unit(SECOND).value - self._start_time - except KeyError: - raise InstrumentationTestError( - 'Missing start timestamp for test scenario "%s". Refer to ' - 'instrumentation_proto.txt for details.' % test_name) - try: - test_ends[test_name] = Measurement( - times[parser.END_TIMESTAMP], TIME, MILLISECOND) \ - .to_unit(SECOND).value - self._start_time - except KeyError: - raise InstrumentationTestError( - 'Missing end timestamp for test scenario "%s". Test ' - 'scenario may have terminated with errors. Refer to ' - 'instrumentation_proto.txt for details.' % test_name) - - # Assign data to tests based on timestamps - for timestamp, sample in raw_data: - self.update_metrics(sample) - for test_name in test_timestamps: - if test_starts[test_name] <= timestamp <= test_ends[test_name]: - self.test_metrics[test_name].update_metrics(sample) - - # Numeric metrics - - ALL_METRICS = ('avg_current', 'max_current', 'min_current', 'stdev_current', - 'avg_power') - - @property - def avg_current(self): - """Average current, in milliamps.""" - if not self._num_samples: - return Measurement.amps(0).to_unit(MILLIAMP) - return (Measurement.amps(self._sum_currents / self._num_samples) - .to_unit(MILLIAMP)) - - @property - def max_current(self): - """Max current, in milliamps.""" - return Measurement.amps(self._max_current or 0).to_unit(MILLIAMP) - - @property - def min_current(self): - """Min current, in milliamps.""" - return Measurement.amps(self._min_current or 0).to_unit(MILLIAMP) - - @property - def stdev_current(self): - """Standard deviation of current values, in milliamps.""" - if self._num_samples < 2: - return Measurement.amps(0).to_unit(MILLIAMP) - stdev = math.sqrt( - (self._sum_squares - ( - self._num_samples * self.avg_current.to_unit(AMP).value ** 2)) - / (self._num_samples - 1)) - return Measurement.amps(stdev).to_unit(MILLIAMP) - - def current_to_power(self, current): - """Converts a current value to a power value.""" - return (Measurement.watts(current.to_unit(AMP).value * self._voltage)) - - @property - def avg_power(self): - """Average power, in milliwatts.""" - return self.current_to_power(self.avg_current).to_unit(MILLIWATT) - - @property - def summary(self): - """A summary of test metrics""" - return {'average_current': str(self.avg_current), - 'max_current': str(self.max_current), - 'average_power': str(self.avg_power)} diff --git a/acts/framework/acts/test_utils/instrumentation/proto/gen/instrumentation_data_pb2.py b/acts/framework/acts/test_utils/instrumentation/proto/gen/instrumentation_data_pb2.py deleted file mode 100644 index 783cd22b09..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/proto/gen/instrumentation_data_pb2.py +++ /dev/null @@ -1,345 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: instrumentation_data.proto - -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) -from google.protobuf.internal import enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='instrumentation_data.proto', - package='android.am', - syntax='proto2', - serialized_pb=_b('\n\x1ainstrumentation_data.proto\x12\nandroid.am\"\xcf\x01\n\x12ResultsBundleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x14\n\x0cvalue_string\x18\x02 \x01(\t\x12\x11\n\tvalue_int\x18\x03 \x01(\x11\x12\x13\n\x0bvalue_float\x18\x04 \x01(\x02\x12\x14\n\x0cvalue_double\x18\x05 \x01(\x01\x12\x12\n\nvalue_long\x18\x06 \x01(\x12\x12/\n\x0cvalue_bundle\x18\x07 \x01(\x0b\x32\x19.android.am.ResultsBundle\x12\x13\n\x0bvalue_bytes\x18\x08 \x01(\x0c\"@\n\rResultsBundle\x12/\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x1e.android.am.ResultsBundleEntry\"M\n\nTestStatus\x12\x13\n\x0bresult_code\x18\x03 \x01(\x11\x12*\n\x07results\x18\x04 \x01(\x0b\x32\x19.android.am.ResultsBundle\"\x98\x01\n\rSessionStatus\x12\x32\n\x0bstatus_code\x18\x01 \x01(\x0e\x32\x1d.android.am.SessionStatusCode\x12\x12\n\nerror_text\x18\x02 \x01(\t\x12\x13\n\x0bresult_code\x18\x03 \x01(\x11\x12*\n\x07results\x18\x04 \x01(\x0b\x32\x19.android.am.ResultsBundle\"i\n\x07Session\x12+\n\x0btest_status\x18\x01 \x03(\x0b\x32\x16.android.am.TestStatus\x12\x31\n\x0esession_status\x18\x02 \x01(\x0b\x32\x19.android.am.SessionStatus*>\n\x11SessionStatusCode\x12\x14\n\x10SESSION_FINISHED\x10\x00\x12\x13\n\x0fSESSION_ABORTED\x10\x01\x42\x19\n\x17\x63om.android.commands.am') -) -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -_SESSIONSTATUSCODE = _descriptor.EnumDescriptor( - name='SessionStatusCode', - full_name='android.am.SessionStatusCode', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='SESSION_FINISHED', index=0, number=0, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='SESSION_ABORTED', index=1, number=1, - options=None, - type=None), - ], - containing_type=None, - options=None, - serialized_start=659, - serialized_end=721, -) -_sym_db.RegisterEnumDescriptor(_SESSIONSTATUSCODE) - -SessionStatusCode = enum_type_wrapper.EnumTypeWrapper(_SESSIONSTATUSCODE) -SESSION_FINISHED = 0 -SESSION_ABORTED = 1 - - - -_RESULTSBUNDLEENTRY = _descriptor.Descriptor( - name='ResultsBundleEntry', - full_name='android.am.ResultsBundleEntry', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='key', full_name='android.am.ResultsBundleEntry.key', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_string', full_name='android.am.ResultsBundleEntry.value_string', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_int', full_name='android.am.ResultsBundleEntry.value_int', index=2, - number=3, type=17, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_float', full_name='android.am.ResultsBundleEntry.value_float', index=3, - number=4, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_double', full_name='android.am.ResultsBundleEntry.value_double', index=4, - number=5, type=1, cpp_type=5, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_long', full_name='android.am.ResultsBundleEntry.value_long', index=5, - number=6, type=18, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_bundle', full_name='android.am.ResultsBundleEntry.value_bundle', index=6, - number=7, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='value_bytes', full_name='android.am.ResultsBundleEntry.value_bytes', index=7, - number=8, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=43, - serialized_end=250, -) - - -_RESULTSBUNDLE = _descriptor.Descriptor( - name='ResultsBundle', - full_name='android.am.ResultsBundle', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='entries', full_name='android.am.ResultsBundle.entries', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=252, - serialized_end=316, -) - - -_TESTSTATUS = _descriptor.Descriptor( - name='TestStatus', - full_name='android.am.TestStatus', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='result_code', full_name='android.am.TestStatus.result_code', index=0, - number=3, type=17, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='results', full_name='android.am.TestStatus.results', index=1, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=318, - serialized_end=395, -) - - -_SESSIONSTATUS = _descriptor.Descriptor( - name='SessionStatus', - full_name='android.am.SessionStatus', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='status_code', full_name='android.am.SessionStatus.status_code', index=0, - number=1, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='error_text', full_name='android.am.SessionStatus.error_text', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='result_code', full_name='android.am.SessionStatus.result_code', index=2, - number=3, type=17, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='results', full_name='android.am.SessionStatus.results', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=398, - serialized_end=550, -) - - -_SESSION = _descriptor.Descriptor( - name='Session', - full_name='android.am.Session', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='test_status', full_name='android.am.Session.test_status', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='session_status', full_name='android.am.Session.session_status', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=552, - serialized_end=657, -) - -_RESULTSBUNDLEENTRY.fields_by_name['value_bundle'].message_type = _RESULTSBUNDLE -_RESULTSBUNDLE.fields_by_name['entries'].message_type = _RESULTSBUNDLEENTRY -_TESTSTATUS.fields_by_name['results'].message_type = _RESULTSBUNDLE -_SESSIONSTATUS.fields_by_name['status_code'].enum_type = _SESSIONSTATUSCODE -_SESSIONSTATUS.fields_by_name['results'].message_type = _RESULTSBUNDLE -_SESSION.fields_by_name['test_status'].message_type = _TESTSTATUS -_SESSION.fields_by_name['session_status'].message_type = _SESSIONSTATUS -DESCRIPTOR.message_types_by_name['ResultsBundleEntry'] = _RESULTSBUNDLEENTRY -DESCRIPTOR.message_types_by_name['ResultsBundle'] = _RESULTSBUNDLE -DESCRIPTOR.message_types_by_name['TestStatus'] = _TESTSTATUS -DESCRIPTOR.message_types_by_name['SessionStatus'] = _SESSIONSTATUS -DESCRIPTOR.message_types_by_name['Session'] = _SESSION -DESCRIPTOR.enum_types_by_name['SessionStatusCode'] = _SESSIONSTATUSCODE - -ResultsBundleEntry = _reflection.GeneratedProtocolMessageType('ResultsBundleEntry', (_message.Message,), dict( - DESCRIPTOR = _RESULTSBUNDLEENTRY, - __module__ = 'instrumentation_data_pb2' - # @@protoc_insertion_point(class_scope:android.am.ResultsBundleEntry) - )) -_sym_db.RegisterMessage(ResultsBundleEntry) - -ResultsBundle = _reflection.GeneratedProtocolMessageType('ResultsBundle', (_message.Message,), dict( - DESCRIPTOR = _RESULTSBUNDLE, - __module__ = 'instrumentation_data_pb2' - # @@protoc_insertion_point(class_scope:android.am.ResultsBundle) - )) -_sym_db.RegisterMessage(ResultsBundle) - -TestStatus = _reflection.GeneratedProtocolMessageType('TestStatus', (_message.Message,), dict( - DESCRIPTOR = _TESTSTATUS, - __module__ = 'instrumentation_data_pb2' - # @@protoc_insertion_point(class_scope:android.am.TestStatus) - )) -_sym_db.RegisterMessage(TestStatus) - -SessionStatus = _reflection.GeneratedProtocolMessageType('SessionStatus', (_message.Message,), dict( - DESCRIPTOR = _SESSIONSTATUS, - __module__ = 'instrumentation_data_pb2' - # @@protoc_insertion_point(class_scope:android.am.SessionStatus) - )) -_sym_db.RegisterMessage(SessionStatus) - -Session = _reflection.GeneratedProtocolMessageType('Session', (_message.Message,), dict( - DESCRIPTOR = _SESSION, - __module__ = 'instrumentation_data_pb2' - # @@protoc_insertion_point(class_scope:android.am.Session) - )) -_sym_db.RegisterMessage(Session) - - -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\027com.android.commands.am')) -# @@protoc_insertion_point(module_scope) diff --git a/acts/framework/acts/test_utils/instrumentation/proto/instrumentation_data.proto b/acts/framework/acts/test_utils/instrumentation/proto/instrumentation_data.proto deleted file mode 100644 index 8e29f96455..0000000000 --- a/acts/framework/acts/test_utils/instrumentation/proto/instrumentation_data.proto +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -syntax = "proto2"; -package android.am; - -option java_package = "com.android.commands.am"; - -message ResultsBundleEntry { - optional string key = 1; - - optional string value_string = 2; - optional sint32 value_int = 3; - optional float value_float = 4; - optional double value_double = 5; - optional sint64 value_long = 6; - optional ResultsBundle value_bundle = 7; - optional bytes value_bytes = 8; -} - -message ResultsBundle { - repeated ResultsBundleEntry entries = 1; -} - -message TestStatus { - optional sint32 result_code = 3; - optional ResultsBundle results = 4; -} - -enum SessionStatusCode { - /** - * The command ran successfully. This does not imply that the tests passed. - */ - SESSION_FINISHED = 0; - - /** - * There was an unrecoverable error running the tests. - */ - SESSION_ABORTED = 1; -} - -message SessionStatus { - optional SessionStatusCode status_code = 1; - optional string error_text = 2; - optional sint32 result_code = 3; - optional ResultsBundle results = 4; -} - -message Session { - repeated TestStatus test_status = 1; - optional SessionStatus session_status = 2; -} - - diff --git a/acts/framework/acts/test_utils/tel/anritsu_utils.py b/acts/framework/acts/test_utils/tel/anritsu_utils.py index a06fd99350..4ffdd8b883 100644 --- a/acts/framework/acts/test_utils/tel/anritsu_utils.py +++ b/acts/framework/acts/test_utils/tel/anritsu_utils.py @@ -18,6 +18,7 @@ import time from queue import Empty from datetime import datetime +from acts.controllers.anritsu_lib import band_constants from acts.controllers.anritsu_lib._anritsu_utils import AnritsuUtils from acts.controllers.anritsu_lib.md8475a import BtsNumber from acts.controllers.anritsu_lib.md8475a import BtsNwNameEnable @@ -145,22 +146,6 @@ Fi_CSCF_IPV6_ADDR_IMS = "2001:0:0:1::3" Fi_CSCF_IPV4_ADDR_911 = "192.168.1.12" Fi_CSCF_IPV6_ADDR_911 = "2001:0:0:2::2" -# GSM BAND constants -GSM_BAND_GSM450 = "GSM450" -GSM_BAND_GSM480 = "GSM480" -GSM_BAND_GSM850 = "GSM850" -GSM_BAND_PGSM900 = "P-GSM900" -GSM_BAND_EGSM900 = "E-GSM900" -GSM_BAND_RGSM900 = "R-GSM900" -GSM_BAND_DCS1800 = "DCS1800" -GSM_BAND_PCS1900 = "PCS1900" - -LTE_BAND_2 = 2 -LTE_BAND_4 = 4 -LTE_BAND_12 = 12 -WCDMA_BAND_1 = 1 -WCDMA_BAND_2 = 2 - # Default Cell Parameters DEFAULT_OUTPUT_LEVEL = -30 DEFAULT_1X_OUTPUT_LEVEL = -35 @@ -169,10 +154,10 @@ DEFAULT_LTE_BAND = [2, 4] Fi_LTE_TMO_BAND = [4] Fi_LTE_SPR_BAND = [25] Fi_LTE_USCC_BAND = [12] -Fi_GSM_TMO_BAND = GSM_BAND_PGSM900 +Fi_GSM_TMO_BAND = band_constants.GSM_BAND_PGSM900 DEFAULT_WCDMA_BAND = 1 DEFAULT_WCDMA_PACKET_RATE = BtsPacketRate.WCDMA_DLHSAUTO_REL7_ULHSAUTO -DEFAULT_GSM_BAND = GSM_BAND_GSM850 +DEFAULT_GSM_BAND = band_constants.GSM_BAND_GSM850 #Google Fi CDMA Bands 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 1666e63e70..324d9db0cd 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 @@ -719,12 +719,12 @@ def get_iperf_arg_string(duration, if ipv6: iperf_args = iperf_args + '-6 ' if traffic_type.upper() == 'UDP': - iperf_args = iperf_args + '-u -b {} -l 1400 -P {}'.format( + iperf_args = iperf_args + '-u -b {} -l 1400 -P {} '.format( udp_throughput, num_processes) elif traffic_type.upper() == 'TCP': - iperf_args = iperf_args + '-P {}'.format(num_processes) + iperf_args = iperf_args + '-P {} '.format(num_processes) if socket_size: - iperf_args = iperf_args + '-w {}'.format(socket_size) + iperf_args = iperf_args + '-w {} '.format(socket_size) if reverse_direction: iperf_args = iperf_args + ' -R' return iperf_args diff --git a/acts/framework/tests/acts_import_unit_test.py b/acts/framework/tests/acts_import_unit_test.py index 93ac80f81e..1d1ac7542c 100755 --- a/acts/framework/tests/acts_import_unit_test.py +++ b/acts/framework/tests/acts_import_unit_test.py @@ -62,6 +62,7 @@ DENYLIST = [ 'acts/test_utils/tel/twilio_client.py', 'tests/google/ble/beacon_tests/BeaconSwarmTest.py', 'tests/google/bt/pts/BtCmdLineTest.py', + 'tests/google/bt/performance/BtA2dpOtaRangeTest.py', 'tests/google/bt/headphone_automation/SineWaveQualityTest.py', 'tests/google/bt/audio_lab/BtChameleonTest.py', 'tests/google/native/bt/BtNativeTest.py', diff --git a/acts/framework/tests/test_utils/instrumentation/config_wrapper_test.py b/acts/framework/tests/test_utils/instrumentation/config_wrapper_test.py deleted file mode 100755 index 18a420fed0..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/config_wrapper_test.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/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 mock -import unittest - -from acts.test_utils.instrumentation.config_wrapper import ConfigWrapper -from acts.test_utils.instrumentation.config_wrapper import InvalidParamError - - -REAL_PATHS = ['realpath/1', 'realpath/2'] -MOCK_CONFIG = { - 'big_int': 50000, - 'small_int': 5, - 'float': 7.77, - 'string': 'insert text here', - 'real_paths_only': REAL_PATHS, - 'real_and_fake_paths': [ - 'realpath/1', 'fakepath/0' - ], - 'inner_config': { - 'inner_val': 16 - } -} - - -class ConfigWrapperTest(unittest.TestCase): - """Unit tests for the Config Wrapper.""" - def setUp(self): - self.mock_config = ConfigWrapper(MOCK_CONFIG) - - def test_get_returns_correct_value(self): - """Test that get() returns the correct param value.""" - self.assertEqual(self.mock_config.get('big_int'), - MOCK_CONFIG['big_int']) - - def test_get_missing_param_returns_default(self): - """Test that get() returns the default value if no param with the - requested name is found. - """ - default_val = 17 - self.assertEqual(self.mock_config.get('missing', default=default_val), - default_val) - - def test_get_with_custom_verification_method(self): - """Test that get() verifies the param with the user-provided test - function. - """ - verifier = lambda i: i > 100 - msg = 'Value too small' - self.assertEqual(self.mock_config.get('big_int', verify_fn=verifier, - failure_msg=msg), - MOCK_CONFIG['big_int']) - with self.assertRaisesRegex(InvalidParamError, msg): - self.mock_config.get('small_int', verify_fn=verifier, - failure_msg=msg) - - def test_get_config(self): - """Test that get_config() returns an empty ConfigWrapper if no - sub-config exists with the given name. - """ - ret = self.mock_config.get_config('missing') - self.assertIsInstance(ret, ConfigWrapper) - self.assertFalse(ret) - - def test_get_int(self): - """Test that get_int() returns the value if it is an int, and raises - an exception if it isn't. - """ - self.assertEqual(self.mock_config.get_int('small_int'), - MOCK_CONFIG['small_int']) - with self.assertRaisesRegex(InvalidParamError, 'of type int'): - self.mock_config.get_int('float') - - def test_get_numeric(self): - """Test that get_numeric() returns the value if it is an int or float, - and raises an exception if it isn't. - """ - self.assertEqual(self.mock_config.get_numeric('small_int'), - MOCK_CONFIG['small_int']) - self.assertEqual(self.mock_config.get_numeric('float'), - MOCK_CONFIG['float']) - with self.assertRaisesRegex(InvalidParamError, 'of type int or float'): - self.mock_config.get_numeric('string') - - def test_config_wrapper_wraps_recursively(self): - """Test that dict values within the input config get transformed into - ConfigWrapper objects themselves. - """ - self.assertTrue( - isinstance(self.mock_config.get('inner_config'), ConfigWrapper)) - self.assertEqual( - self.mock_config.get('inner_config').get_int('inner_val'), 16) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/data/sample.instrumentation_data_proto b/acts/framework/tests/test_utils/instrumentation/data/sample.instrumentation_data_proto deleted file mode 100644 index 42892d5f08..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/data/sample.instrumentation_data_proto +++ /dev/null @@ -1,6 +0,0 @@ -a]INSTRUMENTATION_FAILED: com.google.android.powertests/androidx.test.runner.AndroidJUnitRunner -¬"§ -† -Error}Unable to find instrumentation info for: ComponentInfo{com.google.android.powertests/androidx.test.runner.AndroidJUnitRunner} - -idActivityManagerService
\ No newline at end of file diff --git a/acts/framework/tests/test_utils/instrumentation/data/sample_instrumentation_proto.txt b/acts/framework/tests/test_utils/instrumentation/data/sample_instrumentation_proto.txt deleted file mode 100644 index 6de10d7e0e..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/data/sample_instrumentation_proto.txt +++ /dev/null @@ -1,17 +0,0 @@ -test_status { - result_code: -1 - results { - entries { - key: "Error" - value_string: "Unable to find instrumentation info for: ComponentInfo{com.google.android.powertests/androidx.test.runner.AndroidJUnitRunner}" - } - entries { - key: "id" - value_string: "ActivityManagerService" - } - } -} -session_status { - status_code: SESSION_ABORTED - error_text: "INSTRUMENTATION_FAILED: com.google.android.powertests/androidx.test.runner.AndroidJUnitRunner" -} diff --git a/acts/framework/tests/test_utils/instrumentation/data/sample_monsoon_data b/acts/framework/tests/test_utils/instrumentation/data/sample_monsoon_data deleted file mode 100644 index 2a70273694..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/data/sample_monsoon_data +++ /dev/null @@ -1,10 +0,0 @@ -0s 3.67 -1s 3.69 -2s 0.95 -3s 3.06 -4s 2.17 -5s 1.62 -6s 3.95 -7s 2.47 -8s 1.11 -9s 0.47 diff --git a/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp.instrumentation_data_proto b/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp.instrumentation_data_proto deleted file mode 100644 index ecc75a50c7..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp.instrumentation_data_proto +++ /dev/null @@ -1,94 +0,0 @@ - -Æ"Á -6 -class-com.google.android.powertests.PartialWakelock - -current - -idAndroidJUnitRunner - -numtests -9 -stream/ -com.google.android.powertests.PartialWakelock: - -testpartialWakelock -À#"Ž -6 -class-com.google.android.powertests.PartialWakelock - -start-timestamp - -testpartialWakelock - - timestamp0Ôá—¤›[ - -timestamps-message*¬"--------- beginning of main -08-28 15:05:16.598 10178 7664 7664 I MonitoringInstr: Activities that are still in CREATED to STOPPED: 0 -08-28 15:05:16.601 10178 7664 7696 D com.google.android.powertests.PartialWakelock: fixture setup -08-28 15:05:16.601 10178 7664 7696 I com.android.test.power.utils.Screen: Setting Screen Off -08-28 15:05:16.684 10117 2426 7573 I ChromeSync: [Persistence,AffiliationManager] Fetching affiliations from the server. -08-28 15:05:16.721 10117 2426 7573 E ChromeSync: [Sync,SyncIntentOperation] Error handling the intent: Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.google.android.powertests flg=0x4000010 cmp=com.google.android.gms/.chimera.GmsIntentOperationService (has extras) }. -08-28 15:05:16.736 10117 2426 31227 I Icing : IndexChimeraService.getServiceInterface callingPackage=com.google.android.gms componentName=AppsCorpus serviceId=32 -08-28 15:05:16.737 10117 2426 16984 I Icing : IndexChimeraService.getServiceInterface callingPackage=com.google.android.gms componentName=AppsCorpus serviceId=36 ---------- beginning of system -08-28 15:05:16.774 1000 940 2043 W ProcessStats: Tracking association SourceState{7e3b0a1 com.google.android.gms.persistent/10117 ImpFg #71619} whose proc state 2 is better than process ProcessState{55175ae com.google.android.gms/10117 pkg=com.google.android.gms} proc state 3 (73 skipped) -08-28 15:05:16.808 10117 2426 6018 I Icing : Usage reports ok 0, Failed Usage reports 0, indexed 0, rejected 0 -08-28 15:05:16.840 1000 940 2512 I ActivityManager: Force stopping com.googlecode.android_scripting appid=1000 user=0: from pid 7728 -08-28 15:05:16.841 1000 940 2512 I ActivityManager: Killing 6654:com.googlecode.android_scripting/1000 (adj 965): stop com.googlecode.android_scripting -08-28 15:05:16.824 10117 2426 6018 I chatty : uid=10117(com.google.android.gms) lowpool[42] identical 1 line -08-28 15:05:16.846 10117 2426 6018 I Icing : Usage reports ok 0, Failed Usage reports 0, indexed 0, rejected 0 -08-28 15:05:16.852 radio 1559 1559 E PhoneInterfaceManager: [PhoneIntfMgr] getCarrierPackageNamesForIntent: No UICC -08-28 15:05:16.852 radio 1559 1559 D CarrierSvcBindHelper: No carrier app for: 0 -08-28 15:05:16.859 nfc 2452 2452 D RegisteredNfcFServicesCache: Service unchanged, not updating -08-28 15:05:16.863 media 796 905 D NuPlayerDriver: reset(0xe199b100) at state 4 -08-28 15:05:16.865 root 629 629 I Zygote : Process 6654 exited due to signal 9 (Killed) -08-28 15:05:16.865 media 796 6689 D NuPlayerDriver: notifyResetComplete(0xe199b100) -08-28 15:05:16.873 10117 2426 6018 I Icing : Usage reports ok 0, Failed Usage reports 0, indexed 0, rejected 0 -08-28 15:05:16.887 1000 940 1069 I libprocessgroup: Successfully killed process cgroup uid 1000 pid 6654 in 44ms -08-28 15:05:17.172 1000 647 647 I /vendor/bin/hw/android.hardware.health@2.0-service.marlin: SRAM data: 2812000 -08-28 15:05:17.668 1000 647 647 I chatty : uid=1000(system) health@2.0-serv identical 20 lines -08-28 15:05:17.672 1000 647 647 I /vendor/bin/hw/android.hardware.health@2.0-service.marlin: SRAM data: 2812000 -08-28 15:05:17.697 10117 2426 28502 I Icing : Indexing com.google.android.gms-apps from com.google.android.gms -08-28 15:05:17.717 1000 647 647 I /vendor/bin/hw/android.hardware.health@2.0-service.marlin: SRAM data: 2812000 -08-28 15:05:17.769 1000 647 647 I chatty : uid=1000(system) health@2.0-serv identical 2 lines -08-28 15:05:17.773 1000 647 647 I /vendor/bin/hw/android.hardware.health@2.0-service.marlin: SRAM data: 2812000 -08-28 15:05:17.775 10117 2426 28502 I Icing : Indexing done com.google.android.gms-apps -08-28 15:05:17.778 1000 647 647 I /vendor/bin/hw/android.hardware.health@2.0-service.marlin: SRAM data: 2812000 -08-28 15:05:17.786 1000 940 2043 I WindowManager: sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON) -08-28 15:05:17.787 1000 940 2043 I PowerManagerService: Going to sleep due to sleep_button (uid 1000)... -08-28 15:05:17.788 1000 940 940 W UsageStatsService: Event reported without a package name, eventType:16 -08-28 15:05:17.802 10178 7664 7696 D com.google.android.powertests.PartialWakelock: before -08-28 15:05:17.839 1000 940 1115 V DisplayPowerController: Brightness [131] reason changing to: 'manual', previous reason: 'manual [ dim ]'. - -"Œ -6 -class-com.google.android.powertests.PartialWakelock - -
end-timestamp - -testpartialWakelock - - timestamp0žÍ™¤›[ - -timestamps-message -–"“ -6 -class-com.google.android.powertests.PartialWakelock - -current - -idAndroidJUnitRunner - -numtests - -stream. - -testpartialWakelock-") -' -stream - -Time: 16.333 - -OK (1 test) - diff --git a/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp_proto.txt b/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp_proto.txt deleted file mode 100644 index 5ac75cd3aa..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/data/sample_timestamp_proto.txt +++ /dev/null @@ -1,110 +0,0 @@ -test_status { - result_code: 1 - results { - entries { - key: "class" - value_string: "com.google.android.powertests.PartialWakelock" - } - entries { - key: "current" - value_int: 1 - } - entries { - key: "id" - value_string: "AndroidJUnitRunner" - } - entries { - key: "numtests" - value_int: 1 - } - entries { - key: "stream" - value_string: "\ncom.google.android.powertests.PartialWakelock:" - } - entries { - key: "test" - value_string: "partialWakelock" - } - } -} -test_status { - results { - entries { - key: "class" - value_string: "com.google.android.powertests.PartialWakelock" - } - entries { - key: "start-timestamp" - } - entries { - key: "test" - value_string: "partialWakelock" - } - entries { - key: "timestamp" - value_long: 1567029917802 - } - entries { - key: "timestamps-message" - } - } -} -test_status { - results { - entries { - key: "class" - value_string: "com.google.android.powertests.PartialWakelock" - } - entries { - key: "end-timestamp" - } - entries { - key: "test" - value_string: "partialWakelock" - } - entries { - key: "timestamp" - value_long: 1567029932879 - } - entries { - key: "timestamps-message" - } - } -} -test_status { - results { - entries { - key: "class" - value_string: "com.google.android.powertests.PartialWakelock" - } - entries { - key: "current" - value_int: 1 - } - entries { - key: "id" - value_string: "AndroidJUnitRunner" - } - entries { - key: "numtests" - value_int: 1 - } - entries { - key: "stream" - value_string: "." - } - entries { - key: "test" - value_string: "partialWakelock" - } - } -} -session_status { - result_code: -1 - results { - entries { - key: "stream" - value_string: "\n\nTime: 16.333\n\nOK (1 test)\n\n" - } - } -} diff --git a/acts/framework/tests/test_utils/instrumentation/device/apps/__init__.py b/acts/framework/tests/test_utils/instrumentation/device/apps/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/apps/__init__.py +++ /dev/null diff --git a/acts/framework/tests/test_utils/instrumentation/device/apps/dismiss_dialogs_test.py b/acts/framework/tests/test_utils/instrumentation/device/apps/dismiss_dialogs_test.py deleted file mode 100644 index 3b362747a2..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/apps/dismiss_dialogs_test.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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 unittest - -import mock -from acts.test_utils.instrumentation.device.apps.dismiss_dialogs import \ - DialogDismissalUtil - - -class MockDialogDismissalUtil(DialogDismissalUtil): - """Mock DialogDismissalUtil for unit testing""" - def __init__(self): - self._dut = mock.MagicMock() - self._dismiss_dialogs_apk = mock.MagicMock() - self._dismiss_dialogs_apk.pkg_name = 'dismiss.dialogs' - - -class DialogDismissalUtilTest(unittest.TestCase): - def setUp(self): - self._dismiss_dialogs_util = MockDialogDismissalUtil() - - def test_dismiss_dialog_zero_apps(self): - """Test that no command is run if the apps arg is empty.""" - apps = [] - self._dismiss_dialogs_util.dismiss_dialogs(apps) - self._dismiss_dialogs_util._dut.adb.shell.assert_not_called() - - def test_dismiss_dialog_single_app(self): - """ - Test that the correct command is run when a single app is specified. - """ - apps = ['sample.app.one'] - self._dismiss_dialogs_util.dismiss_dialogs(apps) - expected_cmd = ( - 'am instrument -w -f -e apps sample.app.one ' - 'dismiss.dialogs/.DismissDialogsInstrumentation ' - '-e screenshots true -e quitOnError true' - ) - self._dismiss_dialogs_util._dut.adb.shell.assert_called_with( - expected_cmd) - - def test_dismiss_dialog_multiple_apps(self): - """ - Test that the correct command is run when multiple apps are specified. - """ - apps = ['sample.app.one', 'sample.app.two'] - self._dismiss_dialogs_util.dismiss_dialogs(apps) - expected_cmd = ( - 'am instrument -w -f -e apps sample.app.one,sample.app.two ' - 'dismiss.dialogs/.DismissDialogsInstrumentation ' - '-e screenshots true -e quitOnError true' - ) - self._dismiss_dialogs_util._dut.adb.shell.assert_called_with( - expected_cmd) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/device/apps/hotword_model_extractor_test.py b/acts/framework/tests/test_utils/instrumentation/device/apps/hotword_model_extractor_test.py deleted file mode 100644 index 053da31291..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/apps/hotword_model_extractor_test.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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 os -import unittest - -import mock -from acts.test_utils.instrumentation.device.apps.hotword_model_extractor import \ - HotwordModelExtractor -from acts.test_utils.instrumentation.device.apps.hotword_model_extractor import \ - MODEL_DIR - -GOOD_PACKAGE = 'good_package' -GOOD_MODEL = 'good_model' -BAD_PACKAGE = 'bad_package' -BAD_MODEL = 'bad_model' - - -def mock_pull_from_device(_, hotword_pkg, __): - """Mocks the AppInstaller.pull_from_device method.""" - return mock.MagicMock() if hotword_pkg == GOOD_PACKAGE else None - - -class MockZipFile(object): - """Class for mocking zipfile.ZipFile""" - def extract(self, path, _): - if path == os.path.join(MODEL_DIR, GOOD_MODEL): - return path - raise KeyError - - def __enter__(self): - return self - - def __exit__(self, *_): - pass - - -@mock.patch('acts.test_utils.instrumentation.device.apps.app_installer.' - 'AppInstaller.pull_from_device', side_effect=mock_pull_from_device) -@mock.patch('zipfile.ZipFile', return_value=MockZipFile()) -class HotwordModelExtractorTest(unittest.TestCase): - """Unit tests for HotwordModelExtractor.""" - def setUp(self): - self.extractor = HotwordModelExtractor(mock.MagicMock()) - - def test_package_not_installed(self, *_): - result = self.extractor._extract(BAD_PACKAGE, GOOD_MODEL, '') - self.assertIsNone(result) - - def test_voice_model_not_found(self, *_): - result = self.extractor._extract(GOOD_PACKAGE, BAD_MODEL, '') - self.assertIsNone(result) - - def test_extract_model(self, *_): - result = self.extractor._extract(GOOD_PACKAGE, GOOD_MODEL, '') - self.assertEqual(result, 'res/raw/good_model') - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py b/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py deleted file mode 100644 index ec4ebc7b9c..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/apps/permissions_test.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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 unittest - -import mock -from acts.test_utils.instrumentation.device.apps.permissions import \ - PermissionsUtil - - -class MockPermissionsUtil(PermissionsUtil): - """Mock PermissionsUtil for unit testing""" - def __init__(self): - self._dut = mock.MagicMock() - self._permissions_apk = mock.MagicMock() - self._permissions_apk.pkg_name = 'permissions.util' - - -class PermissionsUtilTest(unittest.TestCase): - def setUp(self): - self._permissions_util = MockPermissionsUtil() - - def test_grant_all(self): - """Test the grant-all command.""" - self._permissions_util.grant_all() - expected_cmd = ( - 'am instrument -w -r -f -e command grant-all ' - 'permissions.util/.PermissionInstrumentation' - ) - self._permissions_util._dut.adb.shell.assert_called_with( - expected_cmd) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/device/command/adb_command_types_test.py b/acts/framework/tests/test_utils/instrumentation/device/command/adb_command_types_test.py deleted file mode 100755 index 127575bd8d..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/command/adb_command_types_test.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/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 unittest - -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceBinaryCommandSeries -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceGServices -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetprop -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceSetting -from acts.test_utils.instrumentation.device.command.adb_command_types import \ - DeviceState - - -class AdbCommandTypesTest(unittest.TestCase): - - def test_device_state(self): - """Tests that DeviceState returns the correct ADB command with - set_value. - """ - base_cmd = 'run command with vals' - val1 = 15 - val2 = 24 - device_state = DeviceState(base_cmd) - self.assertEqual(device_state.set_value(val1, val2), - 'run command with vals 15 24') - - def test_device_state_with_base_cmd_as_format_string(self): - """Tests that DeviceState returns the correct ADB command if the base - command is given as a format string. - """ - base_cmd = 'echo %s > /test/data' - val = 23 - device_state = DeviceState(base_cmd) - self.assertEqual(device_state.set_value(val), 'echo 23 > /test/data') - - def test_device_binary_state(self): - """Tests that DeviceState returns the correct ADB commands with toggle. - """ - on_cmd = 'enable this service' - off_cmd = 'disable the service' - device_binary_state = DeviceState('', on_cmd, off_cmd) - self.assertEqual(device_binary_state.toggle(True), on_cmd) - self.assertEqual(device_binary_state.toggle(False), off_cmd) - - def test_device_setprop(self): - """Tests that DeviceSetprop returns the correct ADB command with - set_value. - """ - prop = 'some.property' - val = 3 - device_setprop = DeviceSetprop(prop) - self.assertEqual(device_setprop.set_value(val), - 'setprop some.property 3') - - def test_device_binary_setprop(self): - """Tests that DeviceSetprop returns the correct ADB commands with - toggle. - """ - prop = 'some.other.property' - on_val = True - off_val = False - device_binary_setprop = DeviceSetprop(prop, on_val, off_val) - self.assertEqual(device_binary_setprop.toggle(True), - 'setprop some.other.property True') - self.assertEqual(device_binary_setprop.toggle(False), - 'setprop some.other.property False') - - def test_device_setting(self): - """Tests that DeviceSetting returns the correct ADB command with - set_value. - """ - namespace = 'global' - setting = 'some_new_setting' - val = 10 - device_setting = DeviceSetting(namespace, setting) - self.assertEqual(device_setting.set_value(val), - 'settings put global some_new_setting 10') - - def test_device_binary_setting(self): - """Tests that DeviceSetting returns the correct ADB commands with - toggle. - """ - namespace = 'system' - setting = 'some_other_setting' - on_val = 'on' - off_val = 'off' - device_binary_setting = DeviceSetting( - namespace, setting, on_val, off_val) - self.assertEqual( - device_binary_setting.toggle(True), - 'settings put system some_other_setting on') - self.assertEqual( - device_binary_setting.toggle(False), - 'settings put system some_other_setting off') - - def test_device_gservices(self): - """Tests that DeviceGServices returns the correct ADB command with - set_value. - """ - setting = 'some_gservice' - val = 22 - device_gservices = DeviceGServices(setting) - self.assertEqual( - device_gservices.set_value(val), - 'am broadcast -a ' - 'com.google.gservices.intent.action.GSERVICES_OVERRIDE ' - '--ei some_gservice 22') - - def test_device_binary_command_series(self): - """Tests that DeviceBinaryCommandSuite returns the correct ADB - commands. - """ - on_cmds = [ - 'settings put global test_setting on', - 'setprop test.prop 1', - 'svc test_svc enable' - ] - off_cmds = [ - 'settings put global test_setting off', - 'setprop test.prop 0', - 'svc test_svc disable' - ] - device_binary_command_series = DeviceBinaryCommandSeries( - [ - DeviceSetting('global', 'test_setting', 'on', 'off'), - DeviceSetprop('test.prop'), - DeviceState('svc test_svc', 'enable', 'disable') - ] - ) - self.assertEqual(device_binary_command_series.toggle(True), on_cmds) - self.assertEqual(device_binary_command_series.toggle(False), off_cmds) - - -if __name__ == "__main__": - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/device/command/intent_builder_test.py b/acts/framework/tests/test_utils/instrumentation/device/command/intent_builder_test.py deleted file mode 100644 index e69b1a237d..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/device/command/intent_builder_test.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/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 unittest - -from acts.test_utils.instrumentation.device.command.intent_builder import \ - IntentBuilder - - -class IntentBuilderTest(unittest.TestCase): - """Unit tests for IntentBuilder""" - - def test_set_action(self): - """Test that a set action yields the correct intent call""" - builder = IntentBuilder('am start') - builder.set_action('android.intent.action.SOME_ACTION') - self.assertEqual(builder.build(), - 'am start -a android.intent.action.SOME_ACTION') - - def test_set_component_with_package_only(self): - """Test that the intent call is built properly with only the package - name specified. - """ - builder = IntentBuilder('am broadcast') - builder.set_component('android.package.name') - self.assertEqual(builder.build(), - 'am broadcast -n android.package.name') - - def test_set_component_with_package_and_component(self): - """Test that the intent call is built properly with both the package - and component name specified. - """ - builder = IntentBuilder('am start') - builder.set_component('android.package.name', '.AndroidComponent') - self.assertEqual( - builder.build(), - 'am start -n android.package.name/.AndroidComponent') - - def test_set_data_uri(self): - """Test that a set data URI yields the correct intent call""" - builder = IntentBuilder() - builder.set_data_uri('file://path/to/file') - self.assertEqual(builder.build(), '-d file://path/to/file') - - def test_add_flag(self): - """Test that additional flags are added properly""" - builder = IntentBuilder('am start') - builder.add_flag('--flag-numero-uno') - builder.add_flag('--flag-numero-dos') - self.assertEqual( - builder.build(), 'am start --flag-numero-uno --flag-numero-dos') - - def test_add_key_value_with_empty_value(self): - """Test that a param with an empty value is added properly.""" - builder = IntentBuilder('am broadcast') - builder.add_key_value_param('empty_param') - self.assertEqual(builder.build(), 'am broadcast --esn empty_param') - - def test_add_key_value_with_nonempty_values(self): - """Test that a param with various non-empty values is added properly.""" - builder = IntentBuilder('am start') - builder.add_key_value_param('bool_param', False) - builder.add_key_value_param('string_param', 'enabled') - builder.add_key_value_param('int_param', 5) - builder.add_key_value_param('float_param', 12.1) - self.assertEqual( - builder.build(), - 'am start --ez bool_param false --es string_param enabled ' - '--ei int_param 5 --ef float_param 12.1') - - def test_full_intent_command(self): - """Test a full intent command with all possible components.""" - builder = IntentBuilder('am broadcast') - builder.set_action('android.intent.action.TEST_ACTION') - builder.set_component('package.name', '.ComponentName') - builder.set_data_uri('file://path/to/file') - builder.add_key_value_param('empty') - builder.add_key_value_param('numeric_param', 11.6) - builder.add_key_value_param('bool_param', True) - builder.add_flag('--unit-test') - self.assertEqual( - builder.build(), - 'am broadcast -a android.intent.action.TEST_ACTION ' - '-n package.name/.ComponentName -d file://path/to/file --unit-test ' - '--esn empty --ef numeric_param 11.6 --ez bool_param true') - - -if __name__ == '__main__': - unittest.main() 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 deleted file mode 100755 index ab982c1bd6..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/instrumentation_base_test_test.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/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 copy -import unittest - -from acts.test_utils.instrumentation.config_wrapper import ConfigWrapper -from acts.test_utils.instrumentation.instrumentation_base_test import \ - InstrumentationBaseTest - -MOCK_INSTRUMENTATION_CONFIG = { - 'MockController': { - 'param1': 1, - 'param2': 4 - }, - 'MockInstrumentationBaseTest': { - 'MockController': { - 'param2': 2, - 'param3': 5 - }, - 'test_case': { - 'MockController': { - 'param3': 3 - } - } - } -} - - -class MockInstrumentationBaseTest(InstrumentationBaseTest): - """Mock test class to initialize required attributes.""" - def __init__(self): - self.current_test_name = None - self._instrumentation_config = ConfigWrapper( - MOCK_INSTRUMENTATION_CONFIG) - self._class_config = self._instrumentation_config.get_config( - self.__class__.__name__) - - -class InstrumentationBaseTestTest(unittest.TestCase): - def setUp(self): - self.instrumentation_test = MockInstrumentationBaseTest() - - def test_get_controller_config_for_test_case(self): - """Test that _get_controller_config returns the corresponding - controller config for the current test case. - """ - self.instrumentation_test.current_test_name = 'test_case' - config = self.instrumentation_test._get_merged_config( - 'MockController') - 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_merged_config( - 'MockController') - self.assertEqual(config.get('param1'), 1) - self.assertEqual(config.get('param2'), 2) - self.assertEqual(config.get('param3'), 5) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/instrumentation_proto_parser_test.py b/acts/framework/tests/test_utils/instrumentation/instrumentation_proto_parser_test.py deleted file mode 100644 index c276fc5c2d..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/instrumentation_proto_parser_test.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/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 os -import unittest - -import mock -from acts.test_utils.instrumentation import instrumentation_proto_parser \ - as parser -from acts.test_utils.instrumentation.instrumentation_proto_parser import \ - ProtoParserError -from acts.test_utils.instrumentation.proto.gen import instrumentation_data_pb2 - - -DEST_DIR = 'dest/proto_dir' -SOURCE_PATH = 'source/proto/protofile' -SAMPLE_PROTO = 'data/sample.instrumentation_data_proto' -SAMPLE_TIMESTAMP_PROTO = 'data/sample_timestamp.instrumentation_data_proto' - - -class InstrumentationProtoParserTest(unittest.TestCase): - """Unit tests for instrumentation proto parser.""" - - def setUp(self): - self.ad = mock.MagicMock() - self.ad.external_storage_path = '' - - @mock.patch('os.path.exists', return_value=True) - def test_pull_proto_returns_correct_path_given_source(self, *_): - self.assertEqual(parser.pull_proto(self.ad, DEST_DIR, SOURCE_PATH), - 'dest/proto_dir/protofile') - - @mock.patch('os.path.exists', return_value=True) - def test_pull_proto_returns_correct_path_from_default_location(self, *_): - self.ad.adb.shell.return_value = 'default' - self.assertEqual(parser.pull_proto(self.ad, DEST_DIR), - 'dest/proto_dir/default') - - def test_pull_proto_fails_if_no_default_proto_found(self, *_): - self.ad.adb.shell.return_value = None - with self.assertRaisesRegex( - ProtoParserError, 'No instrumentation result'): - parser.pull_proto(self.ad, DEST_DIR) - - @mock.patch('os.path.exists', return_value=False) - def test_pull_proto_fails_if_adb_pull_fails(self, *_): - with self.assertRaisesRegex(ProtoParserError, 'Failed to pull'): - parser.pull_proto(self.ad, DEST_DIR, SOURCE_PATH) - - def test_parser_converts_valid_proto(self): - proto_file = os.path.join(os.path.dirname(__file__), SAMPLE_PROTO) - self.assertIsInstance(parser.get_session_from_local_file(proto_file), - instrumentation_data_pb2.Session) - - def test_get_test_timestamps(self): - proto_file = os.path.join(os.path.dirname(__file__), - SAMPLE_TIMESTAMP_PROTO) - session = parser.get_session_from_local_file(proto_file) - timestamps = parser.get_test_timestamps(session) - self.assertEqual( - timestamps['partialWakelock'][parser.START_TIMESTAMP], - 1567029917802) - self.assertEqual( - timestamps['partialWakelock'][parser.END_TIMESTAMP], 1567029932879) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/power/__init__.py b/acts/framework/tests/test_utils/instrumentation/power/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/power/__init__.py +++ /dev/null diff --git a/acts/framework/tests/test_utils/instrumentation/power/instrumentation_power_test_test.py b/acts/framework/tests/test_utils/instrumentation/power/instrumentation_power_test_test.py deleted file mode 100644 index 3a617e2bef..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/power/instrumentation_power_test_test.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/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 unittest - -import mock -from acts.test_utils.instrumentation.config_wrapper import ConfigWrapper -from acts.test_utils.instrumentation.power.instrumentation_power_test \ - import ACCEPTANCE_THRESHOLD -from acts.test_utils.instrumentation.power.instrumentation_power_test \ - import InstrumentationPowerTest -from acts.test_utils.instrumentation.power.power_metrics import PowerMetrics - -from acts import signals - - -class MockInstrumentationPowerTest(InstrumentationPowerTest): - """Mock test class to initialize required attributes.""" - - # avg: 2.214, stdev: 1.358, max: 4.78, min: 0.61 - SAMPLE_DATA = [1.64, 2.98, 1.72, 3.45, 1.31, 4.78, 3.43, 0.61, 1.19, 1.03] - - def __init__(self): - self.log = mock.Mock() - self.metric_logger = mock.Mock() - self.current_test_name = 'test_case' - self._power_metrics = PowerMetrics(4.2) - self._power_metrics.test_metrics = { - 'instrTest1': PowerMetrics(4.2), - 'instrTest2': PowerMetrics(4.2) - } - self._power_metrics.test_metrics['instrTest1'].generate_test_metrics( - list(zip(range(10), self.SAMPLE_DATA)) - ) - self._power_metrics.test_metrics['instrTest2'].generate_test_metrics( - list(zip(range(10), self.SAMPLE_DATA)) - ) - self._instrumentation_config = ConfigWrapper() - self._class_config = ConfigWrapper( - { - self.current_test_name: { - ACCEPTANCE_THRESHOLD: {} - } - } - ) - - def set_criteria(self, criteria): - """Set the acceptance criteria for metrics validation.""" - test_config = self._class_config[self.current_test_name] - test_config[ACCEPTANCE_THRESHOLD] = ConfigWrapper(criteria) - - -class InstrumentationPowerTestTest(unittest.TestCase): - """Unit tests for InstrumentationPowerTest.""" - def setUp(self): - self.instrumentation_power_test = MockInstrumentationPowerTest() - - def test_validate_power_results_lower_and_upper_limit_accept(self): - """Test that validate_power_results accept passing measurements - given a lower and upper limit. - """ - criteria_accept = { - 'instrTest1': { - 'avg_current': { - 'unit_type': 'current', - 'unit': 'A', - 'lower_limit': 1.5, - 'upper_limit': 2.5 - }, - 'max_current': { - 'unit_type': 'current', - 'unit': 'mA', - 'upper_limit': 5000 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_accept) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_lower_and_upper_limit_reject(self): - """Test that validate_power_results reject failing measurements - given a lower and upper limit. - """ - criteria_reject = { - 'instrTest1': { - 'avg_current': { - 'unit_type': 'current', - 'unit': 'A', - 'lower_limit': 1.5, - 'upper_limit': 2 - }, - 'max_current': { - 'unit_type': 'current', - 'unit': 'mA', - 'upper_limit': 4000 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_reject) - with self.assertRaises(signals.TestFailure): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_expected_value_and_deviation_accept(self): - """Test that validate_power_results accept passing measurements - given an expected value and percent deviation. - """ - criteria_accept = { - 'instrTest1': { - 'stdev_current': { - 'unit_type': 'current', - 'unit': 'A', - 'expected_value': 1.5, - 'percent_deviation': 20 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_accept) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_expected_value_and_deviation_reject(self): - """Test that validate_power_results reject failing measurements - given an expected value and percent deviation. - """ - criteria_reject = { - 'instrTest1': { - 'min_current': { - 'unit_type': 'current', - 'unit': 'mA', - 'expected_value': 500, - 'percent_deviation': 10 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_reject) - with self.assertRaises(signals.TestFailure): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_no_such_test(self): - """Test that validate_power_results skip validation if there are no - criteria matching the specified instrumentation test name. - """ - criteria_wrong_test = { - 'instrTest2': { - 'min_current': { - 'unit_type': 'current', - 'unit': 'A', - 'expected_value': 2, - 'percent_deviation': 20 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_wrong_test) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_no_such_metric(self): - """Test that validate_power_results skip validation if the specified - metric is invalid. - """ - criteria_invalid_metric = { - 'instrTest1': { - 'no_such_metric': { - 'unit_type': 'current', - 'unit': 'A', - 'lower_limit': 5, - 'upper_limit': 7 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_invalid_metric) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_criteria_missing_params(self): - """Test that validate_power_results skip validation if the specified - metric has missing parameters. - """ - criteria_missing_params = { - 'instrTest1': { - 'avg_current': { - 'unit': 'A', - 'lower_limit': 1, - 'upper_limit': 2 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_missing_params) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results('instrTest1') - - def test_validate_power_results_pass_if_all_tests_accept(self): - """Test that validate_power_results succeeds if it accepts the results - of all instrumentation tests. - """ - criteria_multi_test_accept = { - 'instrTest1': { - 'avg_current': { - 'unit_type': 'current', - 'unit': 'A', - 'lower_limit': 2 - }, - 'stdev_current': { - 'unit_type': 'current', - 'unit': 'mA', - 'expected_value': 1250, - 'percent_deviation': 30 - } - }, - 'instrTest2': { - 'max_current': { - 'unit_type': 'current', - 'unit': 'A', - 'upper_limit': 5 - }, - 'avg_power': { - 'unit_type': 'power', - 'unit': 'W', - 'upper_limit': 10 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_multi_test_accept) - with self.assertRaises(signals.TestPass): - self.instrumentation_power_test.validate_power_results( - 'instrTest1', 'instrTest2') - - def test_validate_power_results_fail_if_at_least_one_test_rejects(self): - """Test that validate_power_results fails if it rejects the results - of at least one instrumentation test. - """ - criteria_multi_test_reject = { - 'instrTest1': { - 'avg_current': { - 'unit_type': 'current', - 'unit': 'A', - 'lower_limit': 2 - }, - 'stdev_current': { - 'unit_type': 'current', - 'unit': 'mA', - 'expected_value': 1250, - 'percent_deviation': 30 - } - }, - 'instrTest2': { - 'max_current': { - 'unit_type': 'current', - 'unit': 'A', - 'upper_limit': 5 - }, - 'avg_power': { - 'unit_type': 'power', - 'unit': 'W', - 'upper_limit': 8 - } - } - } - self.instrumentation_power_test.set_criteria(criteria_multi_test_reject) - with self.assertRaises(signals.TestFailure): - self.instrumentation_power_test.validate_power_results( - 'instrTest1', 'instrTest2') - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/framework/tests/test_utils/instrumentation/power/power_metrics_test.py b/acts/framework/tests/test_utils/instrumentation/power/power_metrics_test.py deleted file mode 100644 index 38441d136d..0000000000 --- a/acts/framework/tests/test_utils/instrumentation/power/power_metrics_test.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/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 os -import statistics -import unittest - -from acts.test_utils.instrumentation import instrumentation_proto_parser \ - as parser -from acts.test_utils.instrumentation.power.power_metrics import CURRENT -from acts.test_utils.instrumentation.power.power_metrics import HOUR -from acts.test_utils.instrumentation.power.power_metrics import MILLIAMP -from acts.test_utils.instrumentation.power.power_metrics import MINUTE -from acts.test_utils.instrumentation.power.power_metrics import Measurement -from acts.test_utils.instrumentation.power.power_metrics import PowerMetrics -from acts.test_utils.instrumentation.power.power_metrics import TIME -from acts.test_utils.instrumentation.power.power_metrics import WATT - -FAKE_UNIT_TYPE = 'fake_unit' -FAKE_UNIT = 'F' - - -class MeasurementTest(unittest.TestCase): - """Unit tests for the Measurement class.""" - - def test_init_with_valid_unit_type(self): - """Test that a Measurement is properly initialized given a valid unit - type. - """ - measurement = Measurement(2, CURRENT, MILLIAMP) - self.assertEqual(measurement.value, 2) - self.assertEqual(measurement._unit, MILLIAMP) - - def test_init_with_invalid_unit_type(self): - """Test that __init__ raises an error if given an invalid unit type.""" - with self.assertRaisesRegex(TypeError, 'valid unit type'): - measurement = Measurement(2, FAKE_UNIT_TYPE, FAKE_UNIT) - - def test_unit_conversion(self): - """Test that to_unit correctly converts value and unit.""" - ratio = 1000 - current_amps = Measurement.amps(15) - current_milliamps = current_amps.to_unit(MILLIAMP) - self.assertEqual(current_milliamps.value / current_amps.value, ratio) - - def test_unit_conversion_with_wrong_type(self): - """Test that to_unit raises and error if incompatible unit type is - specified. - """ - current_amps = Measurement.amps(3.4) - with self.assertRaisesRegex(TypeError, 'Incompatible units'): - power_watts = current_amps.to_unit(WATT) - - def test_comparison_operators(self): - """Test that the comparison operators work as intended.""" - # time_a == time_b < time_c - time_a = Measurement.seconds(120) - time_b = Measurement(2, TIME, MINUTE) - time_c = Measurement(0.1, TIME, HOUR) - - self.assertEqual(time_a, time_b) - self.assertEqual(time_b, time_a) - self.assertLessEqual(time_a, time_b) - self.assertGreaterEqual(time_a, time_b) - - self.assertNotEqual(time_a, time_c) - self.assertNotEqual(time_c, time_a) - self.assertLess(time_a, time_c) - self.assertLessEqual(time_a, time_c) - self.assertGreater(time_c, time_a) - self.assertGreaterEqual(time_c, time_a) - - def test_arithmetic_operators(self): - """Test that the addition and subtraction operators work as intended""" - time_a = Measurement(3, TIME, HOUR) - time_b = Measurement(90, TIME, MINUTE) - - sum_ = time_a + time_b - self.assertEqual(sum_.value, 4.5) - self.assertEqual(sum_._unit, HOUR) - - sum_reversed = time_b + time_a - self.assertEqual(sum_reversed.value, 270) - self.assertEqual(sum_reversed._unit, MINUTE) - - diff = time_a - time_b - self.assertEqual(diff.value, 1.5) - self.assertEqual(diff._unit, HOUR) - - diff_reversed = time_b - time_a - self.assertEqual(diff_reversed.value, -90) - self.assertEqual(diff_reversed._unit, MINUTE) - - -class PowerMetricsTest(unittest.TestCase): - """Unit tests for the PowerMetrics class.""" - - SAMPLES = [0.13, 0.95, 0.32, 4.84, 2.48, 4.11, 4.85, 4.88, 4.22, 2.2] - RAW_DATA = list(zip(range(10), SAMPLES)) - VOLTAGE = 4.2 - START_TIME = 5 - - def setUp(self): - self.power_metrics = PowerMetrics(self.VOLTAGE, self.START_TIME) - - def test_import_raw_data(self): - """Test that power metrics can be loaded from file. Simply ensure that - the number of samples is correct.""" - - imported_data = PowerMetrics.import_raw_data( - os.path.join(os.path.dirname(__file__), - '../data/sample_monsoon_data') - ) - self.power_metrics.generate_test_metrics(imported_data) - self.assertEqual(self.power_metrics._num_samples, 10) - - def test_split_by_test_with_timestamps(self): - """Test that given test timestamps, a power metric is generated from - a subset of samples corresponding to the test.""" - sample_test = 'sample_test' - test_start = 8500 - test_end = 13500 - test_timestamps = {sample_test: {parser.START_TIMESTAMP: test_start, - parser.END_TIMESTAMP: test_end}} - self.power_metrics.generate_test_metrics(self.RAW_DATA, test_timestamps) - test_metrics = self.power_metrics.test_metrics[sample_test] - self.assertEqual(test_metrics._num_samples, 5) - - def test_numeric_metrics(self): - """Test that the numeric metrics have correct values.""" - self.power_metrics.generate_test_metrics(self.RAW_DATA) - self.assertAlmostEqual(self.power_metrics.avg_current.value, - statistics.mean(self.SAMPLES) * 1000) - self.assertAlmostEqual(self.power_metrics.max_current.value, - max(self.SAMPLES) * 1000) - self.assertAlmostEqual(self.power_metrics.min_current.value, - min(self.SAMPLES) * 1000) - self.assertAlmostEqual(self.power_metrics.stdev_current.value, - statistics.stdev(self.SAMPLES) * 1000) - self.assertAlmostEqual( - self.power_metrics.avg_power.value, - self.power_metrics.avg_current.value * self.VOLTAGE) - - -if __name__ == '__main__': - unittest.main() diff --git a/acts/tests/google/instrumentation/power/camera/CapturePhotosTest.py b/acts/tests/google/instrumentation/power/camera/CapturePhotosTest.py deleted file mode 100644 index a99fd5d539..0000000000 --- a/acts/tests/google/instrumentation/power/camera/CapturePhotosTest.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/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.test_utils.instrumentation.power import instrumentation_power_test -from acts.test_utils.instrumentation.device.apps.dismiss_dialogs import \ - DialogDismissalUtil - - -class ImageCaptureTest(instrumentation_power_test.InstrumentationPowerTest): - """ - Test class for running instrumentation test CameraTests#testImageCapture. - """ - - def _prepare_device(self): - super()._prepare_device() - self.mode_airplane() - self.base_device_configuration() - self._dialog_util = DialogDismissalUtil( - self.ad_dut, - self.get_file_from_config('dismiss_dialogs_apk') - ) - self._dialog_util.dismiss_dialogs('GoogleCamera') - - def _cleanup_device(self): - self._dialog_util.close() - super()._cleanup_device() - - def test_capture_photos(self): - """Measures power during photo capture.""" - self.run_and_measure( - 'com.google.android.platform.powertests.CameraTests', - 'testImageCapture', req_params=['hdr_mode']) - self.validate_power_results() diff --git a/acts/tests/google/instrumentation/power/idle/DisplayAlwaysOnTest.py b/acts/tests/google/instrumentation/power/idle/DisplayAlwaysOnTest.py deleted file mode 100644 index b891b0cc45..0000000000 --- a/acts/tests/google/instrumentation/power/idle/DisplayAlwaysOnTest.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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.test_utils.instrumentation.power import instrumentation_power_test -from acts.test_utils.instrumentation.device.command.adb_commands import common - - -class DisplayAlwaysOnTest(instrumentation_power_test.InstrumentationPowerTest): - """Test class for running instrumentation test DisplayAlwaysOn.""" - - def _prepare_device(self): - super()._prepare_device() - self.base_device_configuration() - self.adb_run(common.doze_mode.toggle(True)) - self.adb_run(common.doze_always_on.toggle(True)) - self.adb_run(common.disable_sensors) - - def test_display_always_on(self): - """Measures power when the device is rock bottom state plus display - always on (known as doze mode).""" - - self.run_and_measure( - 'com.google.android.platform.powertests.IdleTestCase', - 'testIdleScreenOff') - - self.validate_power_results() diff --git a/acts/tests/google/instrumentation/power/idle/PartialWakeLockTest.py b/acts/tests/google/instrumentation/power/idle/PartialWakeLockTest.py deleted file mode 100644 index 973c0f9828..0000000000 --- a/acts/tests/google/instrumentation/power/idle/PartialWakeLockTest.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/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.test_utils.instrumentation.power import instrumentation_power_test - - -class PartialWakeLockTest(instrumentation_power_test.InstrumentationPowerTest): - """Test class for running instrumentation test PartialWakeLock.""" - - def _prepare_device(self): - super()._prepare_device() - self.base_device_configuration() - - def test_partial_wake_lock(self): - """Measures power when the device is idle with a partial wake lock.""" - self.run_and_measure( - 'com.google.android.platform.powertests.IdleTestCase', - 'testPartialWakelock') - self.validate_power_results() diff --git a/acts/tests/google/instrumentation/power/idle/RockBottomTest.py b/acts/tests/google/instrumentation/power/idle/RockBottomTest.py deleted file mode 100644 index 43dd9f1a4c..0000000000 --- a/acts/tests/google/instrumentation/power/idle/RockBottomTest.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/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.test_utils.instrumentation.power import instrumentation_power_test - - -class RockBottomTest(instrumentation_power_test.InstrumentationPowerTest): - """Test class for running instrumentation test RockBottom.""" - - def _prepare_device(self): - super()._prepare_device() - self.base_device_configuration() - - def test_rock_bottom(self): - """Measures power when the device is in a rock bottom state.""" - self.run_and_measure( - 'com.google.android.platform.powertests.IdleTestCase', - 'testIdleScreenOff') - self.validate_power_results() diff --git a/acts/tests/google/instrumentation/power/media/VideoPlaybackTest.py b/acts/tests/google/instrumentation/power/media/VideoPlaybackTest.py deleted file mode 100644 index 9541f460d0..0000000000 --- a/acts/tests/google/instrumentation/power/media/VideoPlaybackTest.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2020 - 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.test_utils.instrumentation.power import instrumentation_power_test - -BIG_FILE_PUSH_TIMEOUT = 600 - - -class VideoPlaybackTest( - instrumentation_power_test.InstrumentationPowerTest): - """Test class for running instrumentation tests - VideoPlaybackHighBitRateTest.""" - - def _prepare_device(self): - super()._prepare_device() - self.base_device_configuration() - - def test_playback_high_bit_rate(self): - """Measures power when the device is in a rock bottom state.""" - video_location = self.push_to_external_storage( - self.get_file_from_config('high_bit_rate_video'), - timeout=BIG_FILE_PUSH_TIMEOUT) - self.trigger_scan_on_external_storage() - - self.run_and_measure( - 'com.google.android.platform.powertests.PhotosTests', - 'testVideoPlaybackThroughIntent', - extra_params=[('video_file_path', video_location)]) - - self.validate_power_results() diff --git a/acts_tests/tests/google/bt/performance/BtA2dpOtaRangeTest.py b/acts_tests/tests/google/bt/performance/BtA2dpOtaRangeTest.py new file mode 100755 index 0000000000..e0a7962788 --- /dev/null +++ b/acts_tests/tests/google/bt/performance/BtA2dpOtaRangeTest.py @@ -0,0 +1,554 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Jul 16 22:58:03 2020 + +@author: qijiang +""" + +import os +import pyvisa +import time +import acts.test_utils.coex.audio_test_utils as atu +import acts.test_utils.bt.bt_test_utils as btutils +import pandas as pd +from acts import asserts +from acts.test_utils.abstract_devices.bluetooth_handsfree_abstract_device import BluetoothHandsfreeAbstractDeviceFactory as bt_factory +from acts.test_utils.bt.A2dpBaseTest import A2dpBaseTest +from acts.test_utils.power.PowerBTBaseTest import ramp_attenuation + +PHONE_MUSIC_FILE_DIRECTORY = '/sdcard/Music' + + +class RPIAxis(object): + def __init__(self, VisaConnectString): + """Constructor. + Create a Visa connection + + """ + rm = pyvisa.ResourceManager() + self.instrument = rm.open_resource(VisaConnectString) + self.instrument.read_termination = "\n" # make sure we look for newline at the end of strings we read + + def __getattr__(self, attr): + return getattr(self.instrument, attr) # Delegate all other attrs + + +class RPIAxis_card(RPIAxis): + """ RPIAxis_card() + Create an axis + + """ + def __init__(self, axis_object): + # create an object to communicate to an RPI2 (remote positioner instrument) axis + self.axis = axis_object # store pyvisa instrument connection + + def __getattr__(self, attr): + return getattr(self.axis, attr) # Delegate all other attrs + + def moveTo(self, where): + """ moveTo + move to a given position and make sure you arrived at the target. + """ + # max travale time in seconds. adjust this if you have a really slow positioner! + MAXTRAVELTIME = 150 + t0 = time.time() + self.axis.write("SK %d\n" % where) + done = False + while (not done): + if (time.time() - t0) > MAXTRAVELTIME: + print("looks like we are stuck!\n") + return False + response = self.axis.query("*opc?\n") + if (response == '1'): + return True + else: + response = self.axis.query("CP?\n") + + # stop the positioner + def Stop(self): + t0 = time.time() + done = False + self.axis.write("ST\n") + while (not done): + if (time.time() - t0) > 2: + print("Runaway positioner!\n") + return False + response = self.axis.query("*opc?\n") + if (response == '1'): + return True + + # set continuous rotation mode + def SetContinuousRotationMode(self): + self.axis.write("CR\n") + + # set non continuous rotation mode + def SetNonContinuousRotationMode(self): + self.axis.write("NCR\n") + + +class BtA2dpOtaRangeTest(A2dpBaseTest): + def setup_class(self): + + #'audio_params' is a dict, contains the audio device type, audio streaming + #settings such as volume, duration, audio recording parameters such as + #channel, sampling rate/width, and thdn parameters for audio processing + req_params = [ + 'audio_params', 'positioner', 'dut_config', 'attenuation_vector' + ] + opt_params = ['music_files'] + self.unpack_userparams(req_params) + if len(self.android_devices) > 1: + self.dut = self.android_devices[1] + self.unpack_userparams(opt_params) + music_src = self.music_files[0] + music_dest = PHONE_MUSIC_FILE_DIRECTORY + success = self.dut.push_system_file(music_src, music_dest) + if success: + self.music_file = os.path.join(PHONE_MUSIC_FILE_DIRECTORY, + os.path.basename(music_src)) + # Initialize media_control class + self.media = btutils.MediaControlOverSl4a(self.dut, + self.music_file) + # Set attenuator to minimum attenuation + self.attenuator = self.attenuators[0] + self.attenuator.set_atten(self.attenuation_vector['min']) + # Create the BTOE(Bluetooth-Other-End) device object + bt_devices = self.user_params.get('bt_devices', []) + attr, idx = bt_devices.split(':') + self.bt_device_controller = getattr(self, attr)[int(idx)] + self.bt_device = bt_factory().generate(self.bt_device_controller) + btutils.enable_bqr(self.bt_device_controller) + + #Setup positioner + self.PhiAxisAddress = "TCPIP0::{}::{}::SOCKET".format( + self.positioner["server_ip"], self.positioner["phi_axis_port"]) + self.ThetaAxisAddress = "TCPIP0::{}::{}::SOCKET".format( + self.positioner["server_ip"], self.positioner["theta_axis_port"]) + self.phi_axis = RPIAxis(self.PhiAxisAddress) + self.phi_card = RPIAxis_card(self.phi_axis) + self.log.info("*IDN? response: {}".format( + self.phi_card.query("*idn?\n"))) + self.theta_axis = RPIAxis(self.ThetaAxisAddress) + self.theta_card = RPIAxis_card(self.theta_axis) + self.log.info("*IDN? response: {}".format( + self.theta_card.query("*idn?\n"))) + self.phi_card.Stop() + self.theta_card.Stop() + + def teardown_class(self): + + if hasattr(self, 'media'): + self.media.stop() + if hasattr(self, 'attenuator'): + self.attenuator.set_atten(self.attenuation_vector['min']) + if hasattr(self, 'dut'): + self.dut.droid.bluetoothFactoryReset() + btutils.disable_bluetooth(self.dut.droid) + self.bt_device.reset() + self.bt_device.power_off() + self.phi_card.moveTo(0) + self.theta_card.moveTo(0) + + def setup_test(self): + + # Reset headset + self.bt_device.reset() + # Initialize audio capture devices + self.audio_device = atu.get_audio_capture_device( + self.bt_device_controller, self.audio_params) + # Connect BT link + connected = self.establish_bt_connection() + asserts.assert_true(connected, 'BT connection failed') + # Output file + file_name = 'OTA_Range_Over_Angle_{}_{}.csv'.format( + self.dut_config['model'], self.dut_config['screen_placement']) + self.file_output = os.path.join(self.log_path, file_name) + + def teardown_test(self): + + if hasattr(self, 'media'): + self.media.stop() + if hasattr(self, 'attenuator'): + self.attenuator.set_atten(self.attenuation_vector['min']) + if hasattr(self, 'dut'): + self.dut.droid.bluetoothFactoryReset() + btutils.disable_bluetooth(self.dut.droid) + self.bt_device.reset() + self.bt_device.power_off() + self.phi_card.moveTo(0) + self.theta_card.moveTo(0) + + def a2dp_play(self): + + if hasattr(self, 'dut'): + vol = self.dut.droid.getMaxMediaVolume( + ) * self.audio_params['volume'] + self.dut.droid.setMediaVolume(vol) + self.media.play() + else: + vol = self.bt_device_controller.droid.getMaxMediaVolume( + ) * self.audio_params['volume'] + self.bt_device_controller.droid.setMediaVolume(vol) + self.bt_device.previous_track() + self.bt_device.play() + + def a2dp_stop(self): + + if hasattr(self, 'dut'): + self.media.stop() + else: + self.bt_device.pause() + + def establish_bt_connection(self): + + if hasattr(self, 'dut'): + self.dut.droid.bluetoothFactoryReset() + self.bt_device.reset() + self.bt_device.power_on() + btutils.enable_bluetooth(self.dut.droid, self.dut.ed) + connected = btutils.connect_phone_to_headset( + self.dut, self.bt_device, 60) + vol = self.dut.droid.getMaxMediaVolume( + ) * self.audio_params['volume'] + self.dut.droid.setMediaVolume(0) + time.sleep(1) + self.dut.droid.setMediaVolume(int(vol)) + self.media.play() + return connected + + elif len(self.bt_device_controller.droid. + bluetoothA2dpSinkGetConnectedDevices()) == 0: + self.log.warning('Need manual intervention to connect BT link') + os.system( + 'spd-say "Please manually connect BT and start playback"') + input('Once fixed, please press ENTER to resume the test') + return 1 + + def run_thdn_analysis(self, audio_captured): + """Calculate Total Harmonic Distortion plus Noise for latest recording. + + Args: + audio_captured: the captured audio file + Returns: + thdn: thdn value in a list + """ + # Calculate Total Harmonic Distortion + Noise + audio_result = atu.AudioCaptureResult(audio_captured, + self.audio_params) + thdn = audio_result.THDN(**self.audio_params['thdn_params']) + return thdn + + def record_audio_and_analyze_thdn(self): + + self.a2dp_play() + time.sleep(1) + self.audio_device.start() + time.sleep(self.audio_params['duration']) + audio_captured = self.audio_device.stop() + audio_result = atu.AudioCaptureResult(audio_captured, + self.audio_params) + thdn = audio_result.THDN(**self.audio_params['thdn_params']) + self.log.info('THDN is {}'.format(thdn[0])) + + self.a2dp_stop() + + return thdn[0] + + def recover_bt_link(self): + """Recover BT link during test. + + Recover BT link from the a2dp sink device + + Returns: + connected: signal whether bt link is restored + """ + #Try to connect from the sink device + if len(self.bt_device_controller.droid.bluetoothGetConnectedDevices() + ) == 0: + self.log.warning('Try to recover BT link') + self.attenuator.set_atten(self.attenuation_vector['min']) + + if hasattr(self, 'dut'): + connected = self.establish_bt_connection() + return connected + else: + device_bonded = self.bt_device_controller.droid.bluetoothGetBondedDevices( + )[0]['address'] + trial_count = 0 + trial_limit = 3 + self.log.info('Try to reconnect from the sink device') + while trial_count < trial_limit: + #Connect master device from the sink device + time_start = time.time() + while time.time() < time_start + 5: + try: + self.bt_device_controller.droid.bluetoothConnectBonded( + device_bonded) + break + except: + pass + time.sleep(2) + if len(self.bt_device_controller.droid. + bluetoothA2dpSinkGetConnectedDevices()) > 0: + vol = self.bt_device_controller.droid.getMaxMediaVolume( + ) * self.audio_params['volume'] + self.bt_device_controller.droid.setMediaVolume(0) + time.sleep(1) + self.bt_device_controller.droid.setMediaVolume( + int(vol)) + return 1 + trial_count += 1 + #Automated reconnect from sink device doesn't work, start fresh connection + if trial_count >= trial_limit: + self.log.info( + 'Need manual intervention on the master device side') + connected = self.establish_bt_connection() + return connected + else: + return 1 + + def find_bt_max_range_bisection_search(self): + + #First linear search to narrow the bisection search + atten_min = self.attenuation_vector['min'] + atten_max = self.attenuation_vector['max'] + atten_step = self.attenuation_vector['step_bisection'] + #Start from initial attenuation + atten_left = atten_min + atten_right = atten_min + while atten_left == atten_right and atten_left < atten_max: + atten_now = self.attenuator.get_atten() + connected = self.recover_bt_link() + if connected == 0: + self.log.warning("Skip this angle as BT connection failed") + max_range = atten_max + return max_range + else: + self.log.info('Connection restored') + ramp_attenuation(self.attenuator, atten_now) + self.log.info("Attenuation set to {}".format(atten_now)) + time.sleep(2) + + thdn = self.record_audio_and_analyze_thdn() + if thdn > self.audio_params['thdn_threshold'] or thdn == 0: + #Hit the right limit for bisection search + if atten_right == atten_min: + self.log.warning('Link breaks at the minimum attenuation') + max_range = atten_min + return max_range + else: + atten_right = atten_now + self.log.info( + 'Right limit found at {} dB'.format(atten_right)) + else: + atten_left = atten_now + atten_right = atten_left + atten_next = min(atten_now + atten_step, atten_max) + ramp_attenuation(self.attenuator, atten_next) + if atten_left == atten_right: + self.log.warning('Could not reach max range') + max_range = atten_max + return max_range + + #Start the bisection search + self.log.info('Start bisection search between {} dB and {} dB'.format( + atten_left, atten_right)) + while atten_right - atten_left > 1: + connected = self.recover_bt_link() + if connected == 0: + self.log.warning("Skip this angle as BT connection failed") + max_range = atten_max + return max_range + else: + self.log.info('Connection restored') + + atten_mid = round((atten_left + atten_right) / 2) + ramp_attenuation(self.attenuator, atten_mid) + atten_now = self.attenuator.get_atten() + self.log.info("Attenuation set to {}".format(atten_now)) + time.sleep(5) + thdn = self.record_audio_and_analyze_thdn() + if thdn > self.audio_params['thdn_threshold'] or thdn == 0: + atten_right = atten_mid + max_range = atten_right - 1 + else: + atten_left = atten_mid + max_range = atten_left + self.log.info('Max range reached at {} dB'.format(max_range)) + return max_range + + def find_bt_max_range_linear_fine_search(self): + + thdn = 0.03 + atten_now = self.attenuator.get_atten() + + while thdn < self.audio_params[ + 'thdn_threshold'] and thdn != 0 and atten_now < self.attenuation_vector[ + 'max']: + atten_now = self.attenuator.get_atten() + self.log.info("Attenuation set to {}".format(atten_now)) + thdn = self.record_audio_and_analyze_thdn() + self.log.info("THDN is {}".format(thdn)) + self.attenuator.set_atten(atten_now + + self.attenuation_vector['step_fine']) + max_range = self.attenuator.get_atten( + ) - self.attenuation_vector['step_fine'] * 2 + if thdn == 0: + self.log.warning( + "Music play stopped, link might get lost, max range reached at {} dB" + .format(max_range)) + else: + self.log.info("Max range reached at {}".format(max_range)) + if atten_now == self.attenuation_vector['max']: + self.log.warning("Fail to reach max range") + return max_range + + def test_bisection_search_max(self): + + #Find the BT max range under each angle using bisection search + max_range_all = [] + + for phi in self.positioner['phi_range']: + + succeed = self.phi_card.moveTo(phi) + if succeed: + self.log.info("Phi positioner moved to {} degree".format(phi)) + else: + self.log.warning( + "Fail to move phi positioner to {} degree".format(phi)) + self.log.info("Phi positioner moved to {} degree".format(phi)) + max_ranges = [phi] + + for theta in self.positioner['theta_range']: + + succeed = self.theta_card.moveTo(theta) + if succeed: + self.log.info( + "Theta positioner moved to {} degree".format(theta)) + else: + self.log.warning( + "Failed to move theta positioner to {} degree".format( + theta)) + self.log.info( + "Theta positioner moved to {} degree".format(theta)) + + ramp_attenuation(self.attenuator, + self.attenuation_vector['min']) + time.sleep(2) + max_range = self.find_bt_max_range_bisection_search() + max_ranges.append(max_range) + max_range_all.append(max_ranges) + columns = ['Phi/Theta'] + columns.extend(self.positioner['theta_range']) + df = pd.DataFrame(max_range_all, columns=columns) + df.to_csv(self.file_output, index=False) + + def test_coarse_search(self): + + #Coarse search to find the highest minimum attenuation can be set to + #be a starting point for all angles + thdn = 0.03 + max_atten_reached = 0 + ramp_attenuation(self.attenuator, + self.attenuation_vector['start_coarse']) + self.log.info('Start attenuation at {} dB'.format( + self.attenuator.get_atten())) + while True: + atten_now = self.attenuator.get_atten() + if atten_now == self.attenuation_vector['max']: + if max_atten_reached > 1: + self.log.warning( + 'Can not reach to the highest minimum, attenuator is already set to be max, need to add more attenuation' + ) + break + for phi in self.positioner['phi_range']: + if thdn == 0 or thdn >= self.audio_params["thdn_threshold"]: + break + succeed = self.phi_card.moveTo(phi) + if succeed: + self.log.info( + "Phi positioner moved to {} degree".format(phi)) + else: + self.log.warning( + "Fail to move phi positioner to {} degree".format(phi)) + self.log.info("Phi positioner moved to {} degree".format(phi)) + + for theta in self.positioner['theta_range']: + + succeed = self.theta_card.moveTo(theta) + if succeed: + self.log.info( + "Theta positioner moved to {} degree".format( + theta)) + else: + self.log.warning( + "Failed to move theta positioner to {} degree". + format(theta)) + self.log.info( + "Theta positioner moved to {} degree".format(theta)) + + thdn = self.record_audio_and_analyze_thdn() + self.log.info( + 'THDN at thea {} degree, phi {} degree is {}'.format( + theta, phi, thdn)) + if thdn == 0 or thdn >= self.audio_params["thdn_threshold"]: + break + if thdn == 0 or thdn >= self.audio_params["thdn_threshold"]: + highest_max = self.attenuator.get_atten( + ) - self.attenuation_vector['step_coarse'] + self.log.info( + 'Highest minimum attenuation is {} dB, fine search can start from there' + .format(highest_max)) + break + atten_new = min(atten_now + self.attenuation_vector['step_coarse'], + self.attenuation_vector['max']) + if atten_new == self.attenuation_vector['max']: + max_atten_reached += 1 + self.attenuator.set_atten(atten_new) + self.log.info('\nSetting attenuator to {} dB'.format( + self.attenuator.get_atten())) + + def test_finestep_search_max(self): + + #Find the BT max range under each angle with a finer step search + max_range_all = [] + for phi in self.positioner['phi_range']: + + succeed = self.phi_card.moveTo(phi) + if succeed: + self.log.info("Phi positioner moved to {} degree".format(phi)) + else: + self.log.warning( + "Fail to move phi positioner to {} degree".format(phi)) + self.log.info("Phi positioner moved to {} degree".format(phi)) + max_ranges = [phi] + + for theta in self.positioner['theta_range']: + + succeed = self.theta_card.moveTo(theta) + if succeed: + self.log.info( + "Theta positioner moved to {} degree".format(theta)) + else: + self.log.warning( + "Failed to move theta positioner to {} degree".format( + theta)) + self.log.info( + "Theta positioner moved to {} degree".format(theta)) + connected = self.recover_bt_link() + if connected == 0: + self.log.warning("Skip this angle as BT connection failed") + max_range = self.attenuation_vector['max'] + return max_range + else: + self.log.info('Connection restored') + ramp_attenuation(self.attenuator, + self.attenuation_vector['start_fine']) + max_range = self.find_bt_max_range_linear_fine_search() + max_ranges.append(max_range) + max_range_all.append(max_ranges) + columns = ['Phi/Theta'] + columns.extend(self.positioner['theta_range']) + df_range = pd.DataFrame(max_range_all, columns=columns) + df_range.to_csv(self.file_output, index=False) diff --git a/acts_tests/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py b/acts_tests/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py index 7d3ba45c23..2f2e666a8a 100644 --- a/acts_tests/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py +++ b/acts_tests/tests/google/fuchsia/bt/gatt/GattConnectionStressTest.py @@ -39,7 +39,7 @@ class GattConnectionStressTest(BaseTestClass): gatt_connect_err_message = "Gatt connection failed with: {}" gatt_disconnect_err_message = "Gatt disconnection failed with: {}" ble_advertise_interval = 50 - scan_timeout_seconds = 10 + scan_timeout_seconds = 60 default_iterations = 1000 def setup_class(self): @@ -49,6 +49,10 @@ class GattConnectionStressTest(BaseTestClass): self.default_iterations = self.user_params.get( "gatt_connect_stress_test_iterations", self.default_iterations) + def on_fail(self, test_name, begin_time): + for fd in self.fuchsia_devices: + fd.take_bug_report(test_name, begin_time) + def _orchestrate_single_connect_disconnect(self): adv_name = generate_id_by_size(10) adv_data = { diff --git a/acts_tests/tests/google/tel/live/TelLiveDataTest.py b/acts_tests/tests/google/tel/live/TelLiveDataTest.py index a2493ed299..2b0b3e714f 100755 --- a/acts_tests/tests/google/tel/live/TelLiveDataTest.py +++ b/acts_tests/tests/google/tel/live/TelLiveDataTest.py @@ -21,6 +21,7 @@ import collections import random import time import os +from queue import Empty from acts import signals from acts.test_decorators import test_tracker_info @@ -36,18 +37,19 @@ from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED from acts.test_utils.tel.tel_defines import DATA_STATE_CONNECTED from acts.test_utils.tel.tel_defines import FAKE_DATE_TIME from acts.test_utils.tel.tel_defines import FAKE_YEAR +from acts.test_utils.tel.tel_defines import EventNetworkCallback +from acts.test_utils.tel.tel_defines import NetworkCallbackCapabilitiesChanged +from acts.test_utils.tel.tel_defines import NetworkCallbackLost from acts.test_utils.tel.tel_defines import GEN_2G from acts.test_utils.tel.tel_defines import GEN_3G from acts.test_utils.tel.tel_defines import GEN_4G from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA -from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE from acts.test_utils.tel.tel_defines import RAT_2G from acts.test_utils.tel.tel_defines import RAT_3G from acts.test_utils.tel.tel_defines import RAT_4G from acts.test_utils.tel.tel_defines import RAT_5G from acts.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY from acts.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA -from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE from acts.test_utils.tel.tel_defines import SIM1_SLOT_INDEX from acts.test_utils.tel.tel_defines import SIM2_SLOT_INDEX from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION @@ -55,7 +57,7 @@ from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_ from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WIFI_CONNECTION from acts.test_utils.tel.tel_defines import TETHERING_MODE_WIFI from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT -from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_MODE_CHANGE +from acts.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA from acts.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL @@ -81,14 +83,11 @@ from acts.test_utils.tel.tel_test_utils import \ from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected from acts.test_utils.tel.tel_test_utils import get_mobile_data_usage from acts.test_utils.tel.tel_test_utils import get_slot_index_from_subid -from acts.test_utils.tel.tel_test_utils import get_network_rat_for_subscription from acts.test_utils.tel.tel_test_utils import hangup_call from acts.test_utils.tel.tel_test_utils import multithread_func from acts.test_utils.tel.tel_test_utils import reboot_device from acts.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit -from acts.test_utils.tel.tel_test_utils import set_call_state_listen_level from acts.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit -from acts.test_utils.tel.tel_test_utils import setup_sim from acts.test_utils.tel.tel_test_utils import stop_wifi_tethering from acts.test_utils.tel.tel_test_utils import start_wifi_tethering from acts.test_utils.tel.tel_test_utils import is_current_network_5g_nsa @@ -96,7 +95,6 @@ from acts.test_utils.tel.tel_test_utils import set_preferred_mode_for_5g from acts.test_utils.tel.tel_test_utils import get_current_override_network_type from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb -from acts.test_utils.tel.tel_test_utils import toggle_volte from acts.test_utils.tel.tel_test_utils import verify_internet_connection from acts.test_utils.tel.tel_test_utils import verify_http_connection from acts.test_utils.tel.tel_test_utils import verify_incall_state @@ -114,7 +112,6 @@ from acts.test_utils.tel.tel_test_utils import wifi_toggle_state from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G from acts.test_utils.tel.tel_test_utils import WIFI_SSID_KEY -from acts.test_utils.tel.tel_test_utils import bring_up_sl4a from acts.test_utils.tel.tel_test_utils import check_data_stall_detection from acts.test_utils.tel.tel_test_utils import check_network_validation_fail from acts.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port @@ -142,7 +139,6 @@ from acts.utils import enable_doze from acts.utils import rand_ascii_str from acts.utils import adb_shell_ping - class TelLiveDataTest(TelephonyBaseTest): def setup_class(self): super().setup_class() @@ -159,6 +155,43 @@ class TelLiveDataTest(TelephonyBaseTest): TelephonyBaseTest.teardown_class(self) + def _listen_for_network_callback(self, ad, event, apm_mode=False): + """Verify network callback for Meteredness + + Args: + ad: DUT to get the network callback for + event: Network callback event + + Returns: + True: if the expected network callback found, False if not + """ + key = ad.droid.connectivityRegisterDefaultNetworkCallback() + ad.droid.connectivityNetworkCallbackStartListeningForEvent(key, event) + if apm_mode: + ad.log.info("Turn on Airplane Mode") + toggle_airplane_mode(ad.log, ad, True) + curr_time = time.time() + status = False + while time.time() < curr_time + MAX_WAIT_TIME_USER_PLANE_DATA: + try: + nc_event = ad.ed.pop_event(EventNetworkCallback) + ad.log.info("Received: %s" % + nc_event["data"]["networkCallbackEvent"]) + if nc_event["data"]["networkCallbackEvent"] == event: + status = nc_event["data"]["metered"] + ad.log.info("Current state of Meteredness is %s", status) + break + except Empty: + pass + + ad.droid.connectivityNetworkCallbackStopListeningForEvent(key, event) + ad.droid.connectivityUnregisterNetworkCallback(key) + if apm_mode: + ad.log.info("Turn off Airplane Mode") + toggle_airplane_mode(ad.log, ad, False) + time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK) + return status + """ Tests Begin """ @@ -441,6 +474,91 @@ class TelLiveDataTest(TelephonyBaseTest): return result + @test_tracker_info(uuid="754810e8-cd93-48e2-9c70-9d951ea416fe") + @TelephonyBaseTest.tel_test_wrap + def test_5g_nsa_metered_cellular(self): + """ Verifies 5G Meteredness API + + Set Mode to 5G + Wait for 5G attached on NSA + Register for Connectivity callback + Verify value of metered flag + + Returns: + True if pass; False if fail. + """ + try: + ad = self.android_devices[0] + wifi_toggle_state(ad.log, ad, False) + toggle_airplane_mode(ad.log, ad, False) + set_preferred_mode_for_5g(ad) + if not is_current_network_5g_nsa(ad): + ad.log.error("Phone not attached on 5G NSA") + return False + return self._listen_for_network_callback(ad, + NetworkCallbackCapabilitiesChanged) + except Exception as e: + ad.log.error(e) + return False + + + @test_tracker_info(uuid="5596d166-5543-4c55-8f65-84234ecb5ba7") + @TelephonyBaseTest.tel_test_wrap + def test_5g_nsa_metered_airplane(self): + """ Verifies 5G Meteredness API + + Set Mode to 5G, Turn on Airplane mode + Register for Connectivity callback + Verify value of metered flag + + Returns: + True if pass; False if fail. + """ + try: + ad = self.android_devices[0] + wifi_toggle_state(ad.log, ad, False) + set_preferred_mode_for_5g(ad) + return self._listen_for_network_callback(ad, + NetworkCallbackLost, apm_mode=True) + except Exception as e: + ad.log.error(e) + toggle_airplane_mode(ad.log, ad, False) + time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK) + return False + + @test_tracker_info(uuid="8fb6c4db-9424-4041-be28-5f4552b2afbf") + @TelephonyBaseTest.tel_test_wrap + def test_5g_nsa_metered_wifi(self): + """ Verifies 5G Meteredness API + + Set Mode to 5G, Wifi Connected + Register for Connectivity callback + Verify value of metered flag + + Returns: + True if pass; False if fail. + """ + ad = self.android_devices[0] + try: + toggle_airplane_mode(ad.log, ad, False) + set_preferred_mode_for_5g(ad) + if not is_current_network_5g_nsa(ad): + ad.log.error("Phone not attached on 5G NSA") + wifi_toggle_state(ad.log, ad, True) + if not ensure_wifi_connected(ad.log, ad, + self.wifi_network_ssid, + self.wifi_network_pass): + ad.log.error("WiFi connect fail.") + return False + return self._listen_for_network_callback(ad, + NetworkCallbackCapabilitiesChanged) + except Exception as e: + ad.log.error(e) + return False + finally: + wifi_toggle_state(ad.log, ad, False) + + @test_tracker_info(uuid="1b0354f3-8668-4a28-90a5-3b3d2b2756d3") @TelephonyBaseTest.tel_test_wrap def test_airplane_mode(self): diff --git a/tools/create_virtualenv.sh b/tools/create_virtualenv.sh index 3746ba2936..197282a306 100755 --- a/tools/create_virtualenv.sh +++ b/tools/create_virtualenv.sh @@ -10,8 +10,11 @@ fi virtualenv='/tmp/acts_preupload_virtualenv' -python3 -m virtualenv -p python3 $virtualenv +echo "preparing virtual env" > "${virtualenv}.log" +python3 -m virtualenv -p python3 $virtualenv &>> "${virtualenv}.log" cp -r acts/framework $virtualenv/ cd $virtualenv/framework -$virtualenv/bin/python3 setup.py develop +echo "installing acts in virtual env" >> "${virtualenv}.log" +$virtualenv/bin/python3 setup.py develop &>> "${virtualenv}.log" cd - +echo "done" >> "${virtualenv}.log" |