| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import logging |
| import re |
| |
| import common |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib import global_config |
| from autotest_lib.client.common_lib.cros import dev_server |
| from autotest_lib.server import test |
| from autotest_lib.server.hosts import adb_host |
| from autotest_lib.server.hosts import host_info |
| from autotest_lib.site_utils import acts_lib |
| from server.cros import dnsname_mangler |
| |
| CONFIG = global_config.global_config |
| |
| CONFIG_FOLDER_LOCATION = global_config.global_config.get_config_value( |
| 'ACTS', 'acts_config_folder', default='') |
| |
| TEST_CONFIG_FILE_FOLDER = os.path.join(CONFIG_FOLDER_LOCATION, |
| 'autotest_config') |
| |
| TEST_CAMPAIGN_FILE_FOLDER = os.path.join(CONFIG_FOLDER_LOCATION, |
| 'autotest_campaign') |
| DEFAULT_TEST_RELATIVE_LOG_PATH = 'results/logs' |
| |
| |
| def get_global_config_value_regex(section, regex): |
| """Get config values from global config based on regex of the key. |
| |
| @param section: Section of the config, e.g., CLIENT. |
| @param regex: Regular expression of the key pattern. |
| |
| @return: A dictionary of all config values matching the regex. Value is |
| assumed to be comma separated, and is converted to a list. |
| """ |
| configs = CONFIG.get_config_value_regex(section, regex) |
| result = {} |
| for key, value in configs.items(): |
| match = re.match(regex, key) |
| result[match.group(1)] = [v.strip() for v in value.split(',') |
| if v.strip()] |
| return result |
| |
| |
| class android_ACTS(test.test): |
| """Run an Android CTS test case. |
| |
| Component relationship: |
| Workstation ----(ssh)---> TestStation -----(adb)-----> Android DUT |
| This code runs on Workstation. |
| """ |
| version = 1 |
| |
| BRANCH_ALIAS_PATTERN = 'acts_branch_alias_(.*)' |
| aliases_map = get_global_config_value_regex('ACTS', BRANCH_ALIAS_PATTERN) |
| |
| def run_once(self, |
| testbed=None, |
| config_file=None, |
| testbed_name=None, |
| test_case=None, |
| test_file=None, |
| additional_configs=[], |
| additional_apks=[], |
| override_build_url=None, |
| override_build=None, |
| override_acts_zip=None, |
| override_internal_acts_dir=None, |
| override_python_bin='python', |
| acts_timeout=7200, |
| perma_path=None, |
| additional_cmd_line_params=None, |
| branch_mappings={}, |
| valid_job_urls_only=False, |
| testtracker_project_id=None, |
| testtracker_extra_env=None, |
| testtracker_owner=None): |
| """Runs an acts test case. |
| |
| @param testbed: The testbed to test on. |
| @config_file: The main config file to use for running the test. This |
| should be relative to the autotest_config folder. |
| @param test_case: The test case to run. Should be None when test_file |
| is given. |
| @param test_file: The campaign file to run. Should be None when |
| test_case is given. This should be relative to the |
| autotest_campaign folder. If multiple are given, |
| multiple test cases will be run. |
| @param additional_configs: Any additional config files to use. |
| These should be relative to the |
| autotest_config folder. |
| @param additional_apks: An array of apk info dictionaries. |
| apk = Name of the apk (eg. sl4a.apk) |
| package = Name of the package (eg. test.tools) |
| artifact = Name of the artifact, if not given |
| package is used. |
| @param override_build_url: Deprecated, use override_build instead. |
| @param override_build: The android build to fetch test artifacts from. |
| If not provided a default is selected from one |
| of the devices. |
| @param override_acts_zip: If given a zip file on the drone is used |
| rather than pulling a build. |
| @param override_internal_acts_dir: The directory within the artifact |
| where the acts framework folder |
| lives. |
| @param override_python_bin: Overrides the default python binary that |
| is used. |
| @param acts_timeout: How long to wait for acts to finish. |
| @param valid_job_urls_only: Apps and resources will be downloaded and |
| installed only on devices that have valid |
| job urls. |
| @param perma_path: If given a permantent path will be used rather than |
| a temp path. |
| @para branch_mappings: A dictionary of branch names to branch names. |
| When pulling test resources, if the current |
| branch is found in the mapping it will use |
| the mapped branch instead. |
| @param testtracker_project_id: ID to use for test tracker project. |
| @param testtracker_extra_env: Extra environment info to publish |
| with the results. |
| """ |
| hostname = testbed.hostname |
| if not testbed_name: |
| if dnsname_mangler.is_ip_address(hostname): |
| testbed_name = hostname |
| else: |
| testbed_name = hostname.split('.')[0] |
| |
| logging.info('Using testbed name %s', testbed_name) |
| |
| if not override_build: |
| override_build = override_build_url |
| |
| valid_hosts = [] |
| if valid_job_urls_only: |
| for v in testbed.get_adb_devices().values(): |
| try: |
| info = v.host_info_store.get() |
| except host_info.StoreError: |
| pass |
| else: |
| if v.job_repo_url_attribute in info.attributes: |
| valid_hosts.append(v) |
| else: |
| valid_hosts = list(testbed.get_adb_devices().values()) |
| |
| if not valid_hosts: |
| raise error.TestError('No valid hosts defined for this test, cannot' |
| ' determine build to grab artifact from.') |
| |
| primary_host = valid_hosts[0] |
| |
| info = primary_host.host_info_store.get() |
| job_repo_url = info.attributes.get(primary_host.job_repo_url_attribute, |
| '') |
| test_station = testbed.teststation |
| if not perma_path: |
| ts_tempfolder = test_station.get_tmp_dir() |
| else: |
| test_station.run('rm -fr "%s"' % perma_path) |
| test_station.run('mkdir "%s"' % perma_path) |
| ts_tempfolder = perma_path |
| target_zip = os.path.join(ts_tempfolder, 'acts.zip') |
| |
| if override_build: |
| build_pieces = override_build.split('/') |
| job_build_branch = build_pieces[0] |
| job_build_target = build_pieces[1] |
| job_build_id = build_pieces[2] |
| else: |
| job_build_info = adb_host.ADBHost.get_build_info_from_build_url( |
| job_repo_url) |
| job_build_branch = job_build_info['branch'] |
| job_build_target = job_build_info['target'] |
| job_build_id = job_build_info['build_id'] |
| |
| if not override_build_url: |
| branch_mapping_pieces = None |
| if job_build_branch in branch_mappings: |
| logging.info('Replacing branch %s -> %s', |
| job_build_branch, |
| branch_mappings[job_build_branch].strip()) |
| branch_mapping_pieces = branch_mappings[ |
| job_build_branch].strip().split('/') |
| elif job_build_branch in self.aliases_map: |
| logging.info('Replacing branch %s -> %s', |
| job_build_branch, |
| self.aliases_map[job_build_branch][0].strip()) |
| branch_mapping_pieces = self.aliases_map[job_build_branch][ |
| 0].strip().split('/') |
| |
| if branch_mapping_pieces: |
| job_build_branch = branch_mapping_pieces[0] |
| |
| if len(branch_mapping_pieces) > 1: |
| job_build_target = branch_mapping_pieces[1] |
| |
| if len(branch_mapping_pieces) > 2: |
| job_build_id = branch_mapping_pieces[2] |
| else: |
| job_build_id = "LATEST" |
| |
| build_name = '%s/%s/%s' % (job_build_branch, |
| job_build_target, |
| job_build_id) |
| devserver = dev_server.AndroidBuildServer.resolve(build_name, |
| primary_host.hostname) |
| build_name = devserver.translate(build_name) |
| build_branch, build_target, build_id = build_name.split('/') |
| |
| logging.info('Using build info BRANCH:%s, TARGET:%s, BUILD_ID:%s', |
| build_branch, build_target, build_id) |
| |
| if override_acts_zip: |
| package = acts_lib.create_acts_package_from_zip(test_station, |
| override_acts_zip, |
| target_zip) |
| else: |
| package = acts_lib.create_acts_package_from_artifact(test_station, |
| build_branch, |
| build_target, |
| build_id, |
| devserver, |
| target_zip) |
| |
| test_env = package.create_environment( |
| container_directory=ts_tempfolder, |
| testbed_name=testbed_name, |
| devices=valid_hosts, |
| internal_acts_directory=override_internal_acts_dir) |
| |
| test_env.install_sl4a_apk() |
| |
| for apk in additional_apks: |
| test_env.install_apk(apk) |
| |
| test_env.setup_enviroment(python_bin=override_python_bin) |
| |
| test_env.upload_config(config_file) |
| |
| if additional_configs: |
| for additional_config in additional_configs: |
| test_env.upload_config(additional_config) |
| |
| if test_file: |
| test_env.upload_campaign(test_file) |
| |
| results = test_env.run_test( |
| config_file, |
| campaign=test_file, |
| test_case=test_case, |
| python_bin=override_python_bin, |
| timeout=acts_timeout, |
| additional_cmd_line_params=additional_cmd_line_params) |
| |
| results.log_output() |
| results.report_to_autotest(self) |
| results.save_test_info(self) |
| results.rethrow_exception() |