blob: ee8d3477ac679a93645a81e0c07471231205d483 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 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.
import argparse
import os
import re
import signal
import sys
import traceback
from builtins import str
from mobly import config_parser as mobly_config_parser
from acts import config_parser
from acts import keys
from acts import signals
from acts import test_runner
from acts import utils
from acts.config_parser import ActsConfigError
def _run_test(parsed_config, test_identifiers, repeat=1):
"""Instantiate and runs test_runner.TestRunner.
This is the function to start separate processes with.
Args:
parsed_config: A mobly.config_parser.TestRunConfig that is a set of
configs for one test_runner.TestRunner.
test_identifiers: A list of tuples, each identifies what test case to
run on what test class.
repeat: Number of times to iterate the specified tests.
Returns:
True if all tests passed without any error, False otherwise.
"""
runner = _create_test_runner(parsed_config, test_identifiers)
try:
for i in range(repeat):
runner.run()
return runner.results.is_all_pass
except signals.TestAbortAll:
return True
except:
print("Exception when executing %s, iteration %s." %
(runner.testbed_name, i))
print(traceback.format_exc())
finally:
runner.stop()
def _create_test_runner(parsed_config, test_identifiers):
"""Instantiates one test_runner.TestRunner object and register termination
signal handlers that properly shut down the test_runner.TestRunner run.
Args:
parsed_config: A mobly.config_parser.TestRunConfig that is a set of
configs for one test_runner.TestRunner.
test_identifiers: A list of tuples, each identifies what test case to
run on what test class.
Returns:
A test_runner.TestRunner object.
"""
try:
t = test_runner.TestRunner(parsed_config, test_identifiers)
except:
print("Failed to instantiate test runner, abort.")
print(traceback.format_exc())
sys.exit(1)
# Register handler for termination signals.
handler = config_parser.gen_term_signal_handler([t])
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGINT, handler)
return t
def _run_tests(parsed_configs, test_identifiers, repeat):
"""Executes requested tests sequentially.
Requested test runs will commence one after another according to the order
of their corresponding configs.
Args:
parsed_configs: A list of mobly.config_parser.TestRunConfig, each is a
set of configs for one test_runner.TestRunner.
test_identifiers: A list of tuples, each identifies what test case to
run on what test class.
repeat: Number of times to iterate the specified tests.
Returns:
True if all test runs executed successfully, False otherwise.
"""
ok = True
for c in parsed_configs:
try:
ret = _run_test(c, test_identifiers, repeat)
ok = ok and ret
except Exception as e:
print("Exception occurred when executing test bed %s. %s" %
(c.testbed_name, e))
return ok
def main():
"""This is the default implementation of a cli entry point for ACTS test
execution.
Or you could implement your own cli entry point using acts.config_parser
functions and acts.test_runner.execute_one_test_class.
"""
parser = argparse.ArgumentParser(
description=("Specify tests to run. If nothing specified, "
"run all test cases found."))
parser.add_argument('-c',
'--config',
type=str,
required=True,
metavar="<PATH>",
help="Path to the test configuration file.")
parser.add_argument(
'-ci',
'--campaign_iterations',
metavar="<CAMPAIGN_ITERATIONS>",
nargs='?',
type=int,
const=1,
default=1,
help="Number of times to run the campaign or a group of test cases.")
parser.add_argument('-tb',
'--testbed',
nargs='+',
type=str,
metavar="[<TEST BED NAME1> <TEST BED NAME2> ...]",
help="Specify which test beds to run tests on.")
parser.add_argument('-lp',
'--logpath',
type=str,
metavar="<PATH>",
help="Root path under which all logs will be placed.")
parser.add_argument(
'-tp',
'--testpaths',
nargs='*',
type=str,
metavar="<PATH> <PATH>",
help="One or more non-recursive test class search paths.")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-tc',
'--testclass',
nargs='+',
type=str,
metavar="[TestClass1 TestClass2:test_xxx ...]",
help="A list of test classes/cases to run.")
group.add_argument(
'-tf',
'--testfile',
nargs=1,
type=str,
metavar="<PATH>",
help=("Path to a file containing a comma delimited list of test "
"classes to run."))
parser.add_argument('-ti',
'--test_case_iterations',
metavar="<TEST_CASE_ITERATIONS>",
nargs='?',
type=int,
help="Number of times to run every test case.")
args = parser.parse_args(sys.argv[1:])
test_list = None
if args.testfile:
test_list = config_parser.parse_test_file(args.testfile[0])
elif args.testclass:
test_list = args.testclass
if re.search(r'\.ya?ml$', args.config):
parsed_configs = mobly_config_parser.load_test_config_file(
args.config, args.testbed)
else:
parsed_configs = config_parser.load_test_config_file(
args.config, args.testbed)
for test_run_config in parsed_configs:
if args.testpaths:
tp_key = keys.Config.key_test_paths.value
test_run_config.controller_configs[tp_key] = args.testpaths
if args.logpath:
test_run_config.log_path = args.logpath
if args.test_case_iterations:
ti_key = keys.Config.key_test_case_iterations.value
test_run_config.user_params[ti_key] = args.test_case_iterations
# Sets the --testpaths flag to the default test directory if left unset.
testpath_key = keys.Config.key_test_paths.value
if (testpath_key not in test_run_config.controller_configs
or test_run_config.controller_configs[testpath_key] is None):
test_run_config.controller_configs[testpath_key] = utils.abs_path(
utils.os.path.join(os.path.dirname(__file__),
'../../../../acts_tests/tests/'))
# TODO(markdr): Find a way to merge this with the validation done in
# Mobly's load_test_config_file.
if not test_run_config.log_path:
raise ActsConfigError("Required key %s missing in test config." %
keys.Config.key_log_path.value)
test_run_config.log_path = utils.abs_path(test_run_config.log_path)
# Prepare args for test runs
test_identifiers = config_parser.parse_test_list(test_list)
exec_result = _run_tests(parsed_configs, test_identifiers,
args.campaign_iterations)
if exec_result is False:
# return 1 upon test failure.
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()