xref: /aosp_15_r20/external/autotest/server/site_tests/tast/testdata/fake_tast.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/python3
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Fake implementation of tast executable used by tast_unittest.py.
7
8In unit tests, this file is executed instead of the real tast executable by the
9tast.py server test. It:
10
11- reads a config.json file installed alongside this script,
12- parses command-line arguments passed by tast.py,
13- checks that the arguments included all required args specified by the config
14  file for the given command (e.g. 'list', 'run' etc.), and
15- performs actions specified by the config file.
16"""
17
18from __future__ import print_function
19
20import argparse
21import json
22import os
23import six
24import sys
25
26
27def main():
28    # pylint: disable=missing-docstring
29
30    # The config file is written by TastTest._run_test in tast_unittest.py and
31    # consists of a dict from command names (e.g. 'list', 'run', etc.) to
32    # command definition dicts (see TastCommand in tast_unittest.py).
33    path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
34                        'config.json')
35    with open(path) as f:
36        cfg = json.load(f)
37
38    args = parse_args()
39    cmd = cfg.get(args.command)
40    if not cmd:
41        raise RuntimeError('Unexpected command "%s"' % args.command)
42
43    # If patterns is ("group:none"), this is a warm-up run, so skip checking
44    # arguments.
45    if args.patterns != [['("group:none")']]:
46        for arg in cmd.get('required_args', []):
47            name, expected_value = arg.split('=', 1)
48            # argparse puts the repeated "pattern" args into a list of lists
49            # instead of a single list. Pull the args back out in this case.
50            val = getattr(args, name)
51            if isinstance(val, list) and len(val) == 1 and isinstance(
52                    val[0], list):
53                val = val[0]
54            actual_value = str(val)
55            if actual_value != expected_value:
56                raise RuntimeError('Got arg %s with value "%s"; want "%s"' %
57                                   (name, actual_value, expected_value))
58
59    if cmd.get('stdout'):
60        sys.stdout.write(cmd['stdout'])
61    if cmd.get('stderr'):
62        sys.stderr.write(cmd['stderr'])
63
64    if cmd.get('files_to_write'):
65        for path, data in six.iteritems(cmd['files_to_write']):
66            dirname = os.path.dirname(path)
67            if not os.path.exists(dirname):
68                os.makedirs(dirname, 0o755)
69            with open(path, 'w') as f:
70                f.write(data)
71
72    sys.exit(cmd.get('status'))
73
74
75def parse_args():
76    """Parses command-line arguments.
77
78    @returns: argparse.Namespace object containing parsed attributes.
79    """
80    def to_bool(v):
81        """Converts a boolean flag's value to a Python bool value."""
82        if v == 'true' or v == '':
83            return True
84        if v == 'false':
85            return False
86        raise argparse.ArgumentTypeError('"true" or "false" expected')
87
88    parser = argparse.ArgumentParser()
89    parser.add_argument('-logtime', type=to_bool, default=False, nargs='?')
90    parser.add_argument('-verbose', type=to_bool, default=False, nargs='?')
91    parser.add_argument('-version', action='version', version='1.0')
92
93    subparsers = parser.add_subparsers(dest='command')
94
95    def add_common_args(subparser):
96        """Adds arguments shared between tast's 'list' and 'run' subcommands."""
97        subparser.add_argument('-build', type=to_bool, default=True, nargs='?')
98        subparser.add_argument('-buildbundle', default='cros')
99        subparser.add_argument('-checkbuilddeps', type=to_bool, default=True,
100                               nargs='?')
101        subparser.add_argument('-downloadprivatebundles', type=to_bool,
102                               default=False, nargs='?')
103        subparser.add_argument('-devservers')
104        subparser.add_argument('-remotebundledir')
105        subparser.add_argument('-remotedatadir')
106        subparser.add_argument('-remoterunner')
107        subparser.add_argument('-sshretries')
108        subparser.add_argument('-downloaddata')
109        subparser.add_argument('-totalshards')
110        subparser.add_argument('-shardindex')
111        subparser.add_argument('target')
112        subparser.add_argument('patterns', action='append', nargs='*')
113
114    list_parser = subparsers.add_parser('list')
115    add_common_args(list_parser)
116    list_parser.add_argument('-json', type=to_bool, default=False, nargs='?')
117
118    run_parser = subparsers.add_parser('run')
119    add_common_args(run_parser)
120    run_parser.add_argument('-resultsdir')
121    run_parser.add_argument('-waituntilready')
122    run_parser.add_argument('-timeout')
123    run_parser.add_argument('-continueafterfailure', type=to_bool,
124                            default=False, nargs='?')
125    run_parser.add_argument('-var', action='append', default=[])
126    run_parser.add_argument('-defaultvarsdir')
127    run_parser.add_argument('-varsfile', action='append', default=[])
128    run_parser.add_argument('-companiondut', action='append', default=[])
129    run_parser.add_argument('-buildartifactsurl')
130    run_parser.add_argument('-maybemissingvars')
131    run_parser.add_argument('-testfilterfile', action='append', default=[])
132
133    return parser.parse_args()
134
135
136if __name__ == '__main__':
137    main()
138