1# Copyright 2018, The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""
16SUITE Tradefed test runner class.
17"""
18
19import copy
20import logging
21
22import constants
23
24from metrics import metrics
25from test_runners import atest_tf_test_runner
26
27class SuitePlanTestRunner(atest_tf_test_runner.AtestTradefedTestRunner):
28    """Suite Plan Test Runner class."""
29    NAME = 'SuitePlanTestRunner'
30    EXECUTABLE = '%s-tradefed'
31    _RUN_CMD = ('{exe} run commandAndExit {test} {args}')
32
33    def __init__(self, results_dir, **kwargs):
34        """Init stuff for suite tradefed runner class."""
35        super().__init__(results_dir, **kwargs)
36        self.run_cmd_dict = {'exe': '',
37                             'test': '',
38                             'args': ''}
39
40    def get_test_runner_build_reqs(self):
41        """Return the build requirements.
42
43        Returns:
44            Set of build targets.
45        """
46        build_req = set()
47        build_req |= super().get_test_runner_build_reqs()
48        return build_req
49
50    def run_tests(self, test_infos, extra_args, reporter):
51        """Run the list of test_infos.
52        Args:
53            test_infos: List of TestInfo.
54            extra_args: Dict of extra args to add to test run.
55            reporter: An instance of result_report.ResultReporter.
56
57        Returns:
58            Return code of the process for running tests.
59        """
60        reporter.register_unsupported_runner(self.NAME)
61        run_cmds = self.generate_run_commands(test_infos, extra_args)
62        ret_code = constants.EXIT_CODE_SUCCESS
63        for run_cmd in run_cmds:
64            proc = super().run(run_cmd, output_to_stdout=True)
65            ret_code |= self.wait_for_subprocess(proc)
66        return ret_code
67
68    def _parse_extra_args(self, extra_args):
69        """Convert the extra args into something *ts-tf can understand.
70
71        We want to transform the top-level args from atest into specific args
72        that *ts-tradefed supports. The only arg we take as is
73        EXTRA_ARG since that is what the user intentionally wants to pass to
74        the test runner.
75
76        Args:
77            extra_args: Dict of args
78
79        Returns:
80            List of args to append.
81        """
82        args_to_append = []
83        args_not_supported = []
84        for arg in extra_args:
85            if constants.SERIAL == arg:
86                args_to_append.append('--serial')
87                args_to_append.append(extra_args[arg])
88                continue
89            if constants.CUSTOM_ARGS == arg:
90                args_to_append.extend(extra_args[arg])
91                continue
92            if constants.DRY_RUN == arg:
93                continue
94            args_not_supported.append(arg)
95        if args_not_supported:
96            logging.info('%s does not support the following args: %s',
97                         self.EXECUTABLE, args_not_supported)
98        return args_to_append
99
100    # pylint: disable=arguments-differ
101    def generate_run_commands(self, test_infos, extra_args):
102        """Generate a list of run commands from TestInfos.
103
104        Args:
105            test_infos: List of TestInfo tests to run.
106            extra_args: Dict of extra args to add to test run.
107
108        Returns:
109            A List of strings that contains the run command
110            which *ts-tradefed supports.
111        """
112        cmds = []
113        args = []
114        args.extend(self._parse_extra_args(extra_args))
115        # TODO(b/183069337): Enable result server args after suite ready.
116        #args.extend(atest_utils.get_result_server_args())
117        for test_info in test_infos:
118            cmd_dict = copy.deepcopy(self.run_cmd_dict)
119            cmd_dict['test'] = test_info.test_name
120            cmd_dict['args'] = ' '.join(args)
121            cmd_dict['exe'] = self.EXECUTABLE % test_info.suite
122            cmds.append(self._RUN_CMD.format(**cmd_dict))
123            if constants.DETECT_TYPE_XTS_SUITE:
124                xts_detect_type = constants.DETECT_TYPE_XTS_SUITE.get(
125                    test_info.suite, '')
126                if xts_detect_type:
127                    metrics.LocalDetectEvent(
128                        detect_type=xts_detect_type,
129                        result=1)
130        return cmds
131