xref: /aosp_15_r20/external/autotest/site_utils/seed_test_attr.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/python3
2*9c5db199SXin Li
3*9c5db199SXin Li# Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
4*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
5*9c5db199SXin Li# found in the LICENSE file.
6*9c5db199SXin Li
7*9c5db199SXin Li"""Method to add or modify ATTRIBUTES in the test control files whose
8*9c5db199SXin LiATTRIBUTES either not match to SUITE or not in the attribute allowlist."""
9*9c5db199SXin Li
10*9c5db199SXin Liimport argparse
11*9c5db199SXin Liimport logging
12*9c5db199SXin Liimport os
13*9c5db199SXin Liimport sys
14*9c5db199SXin Li
15*9c5db199SXin Liimport common
16*9c5db199SXin Lifrom autotest_lib.client.common_lib import control_data
17*9c5db199SXin Lifrom autotest_lib.server.cros.dynamic_suite.suite import Suite
18*9c5db199SXin Li
19*9c5db199SXin Li
20*9c5db199SXin Lidef main(argv):
21*9c5db199SXin Li    """main scripts to seed attributes in test control files.
22*9c5db199SXin Li
23*9c5db199SXin Li  Args:
24*9c5db199SXin Li    @param argv: Command line arguments including `sys.argv[0]`.
25*9c5db199SXin Li  """
26*9c5db199SXin Li    # Parse execution cmd
27*9c5db199SXin Li    parser = argparse.ArgumentParser(
28*9c5db199SXin Li            description='Seed ATTRIBUTES in test control files.')
29*9c5db199SXin Li    parser.add_argument('--execute',
30*9c5db199SXin Li                        action='store_true',
31*9c5db199SXin Li                        default=False,
32*9c5db199SXin Li                        help='Execute the script to seed attributes in all '
33*9c5db199SXin Li                        'test control files.')
34*9c5db199SXin Li    args = parser.parse_args(argv)
35*9c5db199SXin Li
36*9c5db199SXin Li    # When execute is True, run the script to seed attributes in control files.
37*9c5db199SXin Li    if args.execute:
38*9c5db199SXin Li        # Get the allowlist path, hardcode the path currently
39*9c5db199SXin Li        path_allowlist = os.path.join(common.autotest_dir,
40*9c5db199SXin Li                                      'site_utils/attribute_allowlist.txt')
41*9c5db199SXin Li
42*9c5db199SXin Li        # Go through all control file, check whether attribute matches suite. Return
43*9c5db199SXin Li        # a changelist which contains the paths to the control files not match.
44*9c5db199SXin Li        fs_getter = Suite.create_fs_getter(common.autotest_dir)
45*9c5db199SXin Li        changelist = AttrSuiteMatch(fs_getter.get_control_file_list(),
46*9c5db199SXin Li                                    path_allowlist)
47*9c5db199SXin Li        count = len(changelist)
48*9c5db199SXin Li
49*9c5db199SXin Li        logging.info('Starting to seed attributes in %d control files...',
50*9c5db199SXin Li                     count)
51*9c5db199SXin Li        # Modify attributes based on suite for the control files not match.
52*9c5db199SXin Li        for path in changelist:
53*9c5db199SXin Li            logging.info('Seeding ATTRIBUTES in %s', path)
54*9c5db199SXin Li            count = count - 1
55*9c5db199SXin Li            logging.info('%d files remaining...', count)
56*9c5db199SXin Li            SeedAttributes(path)
57*9c5db199SXin Li
58*9c5db199SXin Li        logging.info('Finished seeding attributes.')
59*9c5db199SXin Li
60*9c5db199SXin Li    # When not specify 'execute' in cmd, not modify control files.
61*9c5db199SXin Li    else:
62*9c5db199SXin Li        logging.info(
63*9c5db199SXin Li                'No files are modified. To seed attributes in control files, '
64*9c5db199SXin Li                'please add \'--execute\' argument when run the script.')
65*9c5db199SXin Li
66*9c5db199SXin Li
67*9c5db199SXin Lidef AttrSuiteMatch(path_list, path_allowlist):
68*9c5db199SXin Li    """Check whether attributes are in the attribute allowlist and match with the
69*9c5db199SXin Li  suites in the control files.
70*9c5db199SXin Li
71*9c5db199SXin Li  Args:
72*9c5db199SXin Li    @param path_list: a list of path to the control files to be checked.
73*9c5db199SXin Li    @param path_allowlist: path to the attribute allowlist.
74*9c5db199SXin Li
75*9c5db199SXin Li  Returns:
76*9c5db199SXin Li    A list of paths to the control files that failed at checking.
77*9c5db199SXin Li  """
78*9c5db199SXin Li    unmatch_pathlist = []
79*9c5db199SXin Li
80*9c5db199SXin Li    # Read the allowlist to a set, if path is invalid, throw IOError.
81*9c5db199SXin Li    with open(path_allowlist, 'r') as f:
82*9c5db199SXin Li        allowlist = {line.strip() for line in f.readlines() if line.strip()}
83*9c5db199SXin Li
84*9c5db199SXin Li    # Read the attr in the control files, check with allowlist and suite.
85*9c5db199SXin Li    for path in path_list:
86*9c5db199SXin Li        cd = control_data.parse_control(path, True)
87*9c5db199SXin Li        cd_attrs = cd.attributes
88*9c5db199SXin Li
89*9c5db199SXin Li        # Test whether attributes in the allowlist
90*9c5db199SXin Li        if not (allowlist >= cd_attrs):
91*9c5db199SXin Li            unmatch_pathlist.append(path)
92*9c5db199SXin Li        # Test when suite exists, whether attributes match suites
93*9c5db199SXin Li        if hasattr(cd, 'suite'):
94*9c5db199SXin Li            target_attrs = set('suite:' + x.strip()
95*9c5db199SXin Li                               for x in cd.suite.split(',') if x.strip())
96*9c5db199SXin Li            if cd_attrs != target_attrs:
97*9c5db199SXin Li                unmatch_pathlist.append(path)
98*9c5db199SXin Li        # Test when suite not exists, whether attributes is empty
99*9c5db199SXin Li        elif not hasattr(cd, 'suite') and cd_attrs:
100*9c5db199SXin Li            unmatch_pathlist.append(path)
101*9c5db199SXin Li
102*9c5db199SXin Li    return unmatch_pathlist
103*9c5db199SXin Li
104*9c5db199SXin Li
105*9c5db199SXin Lidef SeedAttributes(path_controlfile):
106*9c5db199SXin Li    """Seed attributes in a control file.
107*9c5db199SXin Li
108*9c5db199SXin Li  Read and re-write a control file with modified contents with attributes added.
109*9c5db199SXin Li
110*9c5db199SXin Li  Args:
111*9c5db199SXin Li    @param path_controlfile: path to control file
112*9c5db199SXin Li
113*9c5db199SXin Li  Returns:
114*9c5db199SXin Li    None
115*9c5db199SXin Li  """
116*9c5db199SXin Li    # Parse attribute from suite, and prepare ATTRIBUTES line.
117*9c5db199SXin Li    cd = control_data.parse_control(path_controlfile, True)
118*9c5db199SXin Li    suite = cd.suite
119*9c5db199SXin Li
120*9c5db199SXin Li    attr_items = set('suite:' + x.strip() for x in suite.split(',')
121*9c5db199SXin Li                     if x.strip())
122*9c5db199SXin Li    attr_items = list(attr_items)
123*9c5db199SXin Li    attr_items.sort(key=str.lower)
124*9c5db199SXin Li    attr_line = ', '.join(attr_items)
125*9c5db199SXin Li    attr_line = 'ATTRIBUTES = \"' + attr_line + '\"\n'
126*9c5db199SXin Li
127*9c5db199SXin Li    # Read control file and modify the suite line with attribute added.
128*9c5db199SXin Li    with open(path_controlfile, 'r') as f:
129*9c5db199SXin Li        lines = f.readlines()
130*9c5db199SXin Li        index = [
131*9c5db199SXin Li                i for i, val in enumerate(lines)
132*9c5db199SXin Li                if val.startswith('SUITE =') or val.startswith('SUITE=')
133*9c5db199SXin Li        ][0]
134*9c5db199SXin Li        suite_line = lines[index]
135*9c5db199SXin Li        lines[index] = attr_line + suite_line
136*9c5db199SXin Li
137*9c5db199SXin Li    # Write the modified contents back to file
138*9c5db199SXin Li    with open(path_controlfile, 'w') as f:
139*9c5db199SXin Li        f.writelines(lines)
140*9c5db199SXin Li
141*9c5db199SXin Li
142*9c5db199SXin Liif __name__ == '__main__':
143*9c5db199SXin Li    sys.exit(main(sys.argv[1:]))
144