• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython3
2# Copyright 2021 The ANGLE Project 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"""Script to generate the test spec JSON files. Calls Chromium's generate_buildbot_json.
6
7=== NOTE: DO NOT RUN THIS SCRIPT DIRECTLY. ===
8Run scripts/run_code_generation.py instead to update necessary hashes.
9
10"""
11
12import os
13import pprint
14import sys
15import subprocess
16import tempfile
17
18d = os.path.dirname
19THIS_DIR = d(os.path.abspath(__file__))
20TESTING_BBOT_DIR = os.path.join(d(d(THIS_DIR)), 'testing', 'buildbot')
21sys.path.insert(0, TESTING_BBOT_DIR)
22
23import generate_buildbot_json
24
25# Add custom mixins here.
26ADDITIONAL_MIXINS = {
27    'angle_skia_gold_test': {
28        'args': [
29            '--git-revision=${got_angle_revision}',
30            # BREAK GLASS IN CASE OF EMERGENCY
31            # Uncommenting this argument will bypass all interactions with Skia
32            # Gold in any tests that use it. This is meant as a temporary
33            # emergency stop in case of a Gold outage that's affecting the bots.
34            # '--bypass-skia-gold-functionality',
35        ],
36        'precommit_args': [
37            '--gerrit-issue=${patch_issue}',
38            '--gerrit-patchset=${patch_set}',
39            '--buildbucket-id=${buildbucket_build_id}',
40            # This normally evaluates to "0", but will evaluate to "1" if
41            # "Use-Permissive-Angle-Pixel-Comparison: True" is present as a
42            # CL footer.
43            '--use-permissive-pixel-comparison=${use_permissive_angle_pixel_comparison}',
44        ],
45    },
46    'timeout_120m': {
47        'swarming': {
48            'hard_timeout': 7200,
49            'io_timeout': 300
50        }
51    },
52}
53
54MIXIN_FILE_NAME = os.path.join(THIS_DIR, 'mixins.pyl')
55MIXINS_PYL_TEMPLATE = """\
56# GENERATED FILE - DO NOT EDIT.
57# Generated by {script_name} using data from {data_source}
58#
59# Copyright 2021 The ANGLE Project Authors. All rights reserved.
60# Use of this source code is governed by a BSD-style license that can be
61# found in the LICENSE file.
62#
63# This is a .pyl, or "Python Literal", file. You can treat it just like a
64# .json file, with the following exceptions:
65# * all keys must be quoted (use single quotes, please);
66# * comments are allowed, using '#' syntax; and
67# * trailing commas are allowed.
68#
69# For more info see Chromium's mixins.pyl in testing/buildbot.
70
71{mixin_data}
72"""
73
74
75def main():
76    if len(sys.argv) > 1:
77        gen_bb_json = os.path.join(TESTING_BBOT_DIR, 'generate_buildbot_json.py')
78        mixins_pyl = os.path.join(TESTING_BBOT_DIR, 'mixins.pyl')
79        inputs = [
80            'test_suite_exceptions.pyl', 'test_suites.pyl', 'variants.pyl', 'waterfalls.pyl',
81            gen_bb_json, mixins_pyl
82        ]
83        outputs = ['angle.json', 'mixins.pyl']
84        if sys.argv[1] == 'inputs':
85            print(','.join(inputs))
86            return 0
87        if sys.argv[1] == 'outputs':
88            print(','.join(outputs))
89            return 0
90
91    # --verify-only enables dirty checks without relying on checked in hashes.
92    # Compares the content of the existing file with the generated content.
93    verify_only = '--verify-only' in sys.argv
94
95    if verify_only:
96        with tempfile.TemporaryDirectory() as temp_dir:
97            return run_generator(verify_only, temp_dir)
98    else:
99        return run_generator(verify_only, None)
100
101
102def write_or_verify_file(filename, content, verify_only):
103    if verify_only:
104        try:
105            with open(filename) as f:
106                # Note: .gitattributes "* text=auto" handles LF <-> CRLF on Windows
107                return f.read() == content
108        except FileNotFoundError:
109            return False
110    else:
111        with open(filename, 'w') as fout:
112            fout.write(content)
113            return True
114
115
116def run_generator(verify_only, temp_dir):
117    chromium_args = generate_buildbot_json.BBJSONGenerator.parse_args([])
118    chromium_generator = generate_buildbot_json.BBJSONGenerator(chromium_args)
119    chromium_generator.load_configuration_files()
120
121    override_args = ['--pyl-files-dir', THIS_DIR]
122    if verify_only:
123        override_args += ['--output-dir', temp_dir]
124    angle_args = generate_buildbot_json.BBJSONGenerator.parse_args(override_args)
125    angle_generator = generate_buildbot_json.BBJSONGenerator(angle_args)
126    angle_generator.load_configuration_files()
127    angle_generator.resolve_configuration_files()
128
129    seen_mixins = set()
130    for waterfall in angle_generator.waterfalls:
131        seen_mixins = seen_mixins.union(waterfall.get('mixins', set()))
132        for bot_name, tester in waterfall['machines'].items():
133            seen_mixins = seen_mixins.union(tester.get('mixins', set()))
134    for suite in angle_generator.test_suites.values():
135        if isinstance(suite, list):
136            # Don't care about this, it's a composition, which shouldn't include a
137            # swarming mixin.
138            continue
139        for test in suite.values():
140            assert isinstance(test, dict)
141            seen_mixins = seen_mixins.union(test.get('mixins', set()))
142
143    found_mixins = ADDITIONAL_MIXINS.copy()
144    for mixin in seen_mixins:
145        if mixin in found_mixins:
146            continue
147        assert (mixin in chromium_generator.mixins), 'Error with %s mixin' % mixin
148        found_mixins[mixin] = chromium_generator.mixins[mixin]
149
150    pp = pprint.PrettyPrinter(indent=2)
151
152    format_data = {
153        'script_name': os.path.basename(__file__),
154        'data_source': 'waterfall.pyl and Chromium\'s mixins.pyl',
155        'mixin_data': pp.pformat(found_mixins),
156    }
157    generated_mixin_pyl = MIXINS_PYL_TEMPLATE.format(**format_data)
158
159    if not write_or_verify_file(MIXIN_FILE_NAME, generated_mixin_pyl, verify_only):
160        print('infra/specs/mixins.pyl dirty')
161        return 1
162
163    if angle_generator.main() != 0:
164        print('buildbot (pyl to json) generation failed')
165        return 1
166
167    if verify_only:
168        for waterfall in angle_generator.waterfalls:
169            filename = waterfall['name'] + '.json'  # angle.json, might have more in future
170            with open(os.path.join(temp_dir, filename)) as f:
171                content = f.read()
172            angle_filename = os.path.join(THIS_DIR, filename)
173            if not write_or_verify_file(angle_filename, content, True):
174                print('infra/specs/%s dirty' % filename)
175                return 1
176
177    return 0
178
179
180if __name__ == '__main__':  # pragma: no cover
181    sys.exit(main())
182