Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 1 | #!/usr/bin/env vpython3 |
iannucci | d5935d9 | 2014-07-26 01:08:21 | [diff] [blame] | 2 | # Copyright 2014 The Chromium 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. |
Philippe Gervais | eeb839c | 2015-02-03 23:19:50 | [diff] [blame] | 5 | """Convenience script for expect_tests""" |
iannucci | d5935d9 | 2014-07-26 01:08:21 | [diff] [blame] | 6 | |
Andrew Chang | 6e83149 | 2020-09-16 23:21:52 | [diff] [blame] | 7 | from __future__ import absolute_import |
| 8 | from __future__ import print_function |
iannucci | d5935d9 | 2014-07-26 01:08:21 | [diff] [blame] | 9 | assert __name__ == '__main__' |
| 10 | |
| 11 | import os |
eseidel | c35bb7f | 2014-09-02 22:36:03 | [diff] [blame] | 12 | import subprocess |
Philippe Gervais | eeb839c | 2015-02-03 23:19:50 | [diff] [blame] | 13 | import sys |
iannucci | d5935d9 | 2014-07-26 01:08:21 | [diff] [blame] | 14 | |
eseidel | bda3235 | 2014-09-04 23:08:47 | [diff] [blame] | 15 | |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 16 | INFRA_ROOT = os.path.dirname(os.path.abspath(__file__)) |
| 17 | |
| 18 | |
Gregory Nisbet | 2c366ec | 2022-03-30 03:43:46 | [diff] [blame] | 19 | # Allowlist of packages to test on Windows. |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 20 | WIN_ENABLED_PACKAGES = [ |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 21 | 'packages/infra_libs/infra_libs/infra_types', |
| 22 | 'packages/infra_libs/infra_libs/logs', |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 23 | 'packages/infra_libs/infra_libs/ts_mon', |
| 24 | ] |
| 25 | |
Brian Ryner | f1ccfdb | 2024-02-15 02:34:22 | [diff] [blame] | 26 | WIN_ENABLED_PACKAGES_PY3_ONLY = [ |
| 27 | 'infra/libs/decorators', |
| 28 | 'infra/libs/service_utils', |
| 29 | ] |
| 30 | |
Brian Ryner | aee4d42 | 2024-02-14 22:24:27 | [diff] [blame] | 31 | # Test shared GAE code and individual GAE apps only on 64-bit Posix. This |
| 32 | # matches GAE environment. |
| 33 | TEST_GAE = sys.platform != 'win32' and sys.maxsize == (2**63) - 1 |
| 34 | |
Brian Ryner | c7b2a20 | 2024-01-02 07:02:54 | [diff] [blame] | 35 | # Tests to run under vpython3. These should not be part of any |
| 36 | # of the py2 modules listed below, and must contain their own |
| 37 | # __main__ implementation. |
| 38 | VPYTHON3_TESTS = [ |
| 39 | 'infra/tools/dockerbuild/test/smoke_test.py', |
| 40 | ] |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 41 | |
Brian Ryner | aee4d42 | 2024-02-14 22:24:27 | [diff] [blame] | 42 | if TEST_GAE and os.path.isdir(os.path.join(INFRA_ROOT, 'appengine_module')): |
| 43 | VPYTHON3_TESTS += [ |
| 44 | 'appengine_module/gae_ts_mon/test/test.py', |
| 45 | ] |
| 46 | |
| 47 | |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 48 | def usage(): |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 49 | print("""\nUsage: %s <action> [--py3] [<test names>] [<expect_tests options>] |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 50 | |
| 51 | where <action> is one of: list, test, train, debug. |
| 52 | |
| 53 | Examples: |
| 54 | Run all tests: |
| 55 | ./test.py test |
Aaron Gable | 56f4df6 | 2016-10-13 18:04:25 | [diff] [blame] | 56 | Run all tests in the given package: |
Philippe Gervais | ff601c3 | 2014-12-02 00:49:29 | [diff] [blame] | 57 | ./test.py test infra |
Aaron Gable | 56f4df6 | 2016-10-13 18:04:25 | [diff] [blame] | 58 | ./test.py test appengine/cr-buildbucket |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 59 | Run all tests and generate an HTML report: |
| 60 | ./test.py test infra --html-report /path/to/report/folder |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 61 | Run one given test in the infra package: |
Philippe Gervais | ff601c3 | 2014-12-02 00:49:29 | [diff] [blame] | 62 | ./test.py test infra/libs/git2/test:*testCommitBogus |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 63 | |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 64 | --py3 runs python 3 tests; otherwise python 2 tests are run. |
| 65 | |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 66 | See expect_tests documentation for more details |
Andrew Chang | 6e83149 | 2020-09-16 23:21:52 | [diff] [blame] | 67 | """ % sys.argv[0]) |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 68 | |
| 69 | |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 70 | def get_modules_with_coveragerc(root_module): |
| 71 | """Returns submodules that have .coveragerc file present.""" |
| 72 | root_dir = os.path.join(INFRA_ROOT, root_module.replace('/', os.sep)) |
| 73 | if not os.path.isdir(root_dir): |
| 74 | return [] |
| 75 | return [ |
| 76 | '%s/%s' % (root_module, d) |
| 77 | for d in os.listdir(root_dir) |
| 78 | if os.path.isfile(os.path.join(root_dir, d, '.coveragerc')) |
| 79 | ] |
vadimsh | 908a1aa | 2015-07-31 00:32:28 | [diff] [blame] | 80 | |
| 81 | |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 82 | # Parse command-line arguments |
| 83 | if len(sys.argv) == 1: |
Philippe Gervais | ff601c3 | 2014-12-02 00:49:29 | [diff] [blame] | 84 | usage() |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 85 | sys.exit(1) |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 86 | else: |
| 87 | if not sys.argv[1] in ('list', 'train', 'test', 'debug'): |
| 88 | usage() |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 89 | sys.exit(1) |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 90 | |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 91 | command = sys.argv[1] |
| 92 | args = sys.argv[2:] |
| 93 | |
| 94 | modules = [] |
| 95 | flags = [] |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 96 | py3 = False |
wrengr | 8542d92 | 2016-09-06 22:03:31 | [diff] [blame] | 97 | # BUG: this will append everything after the first flag to `flags`. Thus, |
| 98 | # it fails to catch when (a) someone doesn't pass a directory after |
| 99 | # "--html-report", nor (b) if they pass multiple directories after that |
| 100 | # flag. |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 101 | for arg in args: |
| 102 | if arg.startswith('-'): |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 103 | if arg == '--py3': |
| 104 | py3 = True |
| 105 | else: |
| 106 | flags.append(arg) |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 107 | continue |
| 108 | if flags: |
| 109 | flags.append(arg) |
| 110 | else: |
| 111 | modules.append(arg) |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 112 | |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 113 | if py3: |
| 114 | python_bin = sys.executable |
| 115 | expect_tests_path = os.path.join( |
| 116 | os.path.dirname(sys.executable), 'expect_tests') |
| 117 | else: |
Robert Iannucci | 6c4eebb | 2024-10-08 20:23:36 | [diff] [blame] | 118 | vpyout = subprocess.run([ |
| 119 | os.path.join(INFRA_ROOT, 'cipd', 'legacy', 'vpython'), |
| 120 | '-c', 'import sys;sys.stdout.write(sys.executable)', |
| 121 | ], capture_output=True, encoding='utf-8') |
| 122 | if vpyout.returncode != 0: |
| 123 | sys.stderr.write(vpyout.stderr) |
| 124 | sys.stdout.write(vpyout.stdout) |
| 125 | vpyout.check_returncode() |
| 126 | python_bin = vpyout.stdout |
| 127 | expect_tests_path = os.path.join(os.path.dirname(python_bin), 'expect_tests') |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 128 | |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 129 | # Set up default list of packages/directories if none have been provided. |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 130 | if not modules: |
Gregory Nisbet | 2c366ec | 2022-03-30 03:43:46 | [diff] [blame] | 131 | # On Windows, test only allowlisted subset of 'infra' and 'packages' modules. |
vadimsh | 908a1aa | 2015-07-31 00:32:28 | [diff] [blame] | 132 | if sys.platform == 'win32': |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 133 | modules.extend([ |
| 134 | p for p in WIN_ENABLED_PACKAGES |
| 135 | if os.path.isdir(os.path.join(INFRA_ROOT, p)) |
| 136 | ]) |
Brian Ryner | f1ccfdb | 2024-02-15 02:34:22 | [diff] [blame] | 137 | if py3: |
| 138 | modules.extend([ |
| 139 | p for p in WIN_ENABLED_PACKAGES_PY3_ONLY |
| 140 | if os.path.isdir(os.path.join(INFRA_ROOT, p)) |
| 141 | ]) |
vadimsh | 908a1aa | 2015-07-31 00:32:28 | [diff] [blame] | 142 | else: |
Brian Ryner | f1ccfdb | 2024-02-15 02:34:22 | [diff] [blame] | 143 | if py3: |
| 144 | modules.extend(['infra']) |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 145 | modules.extend(get_modules_with_coveragerc('packages')) |
| 146 | |
Brian Ryner | 8045831 | 2024-03-20 06:17:07 | [diff] [blame] | 147 | # Skip py2.7 GAE tests for any builders that don't pull the appengine |
| 148 | # directory. For py3, these tests run via their own test.py rather than |
| 149 | # expect_tests. |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 150 | if not py3 and os.path.isdir(os.path.join(INFRA_ROOT, 'appengine')): |
Brian Ryner | aee4d42 | 2024-02-14 22:24:27 | [diff] [blame] | 151 | if TEST_GAE: |
Vadim Shtayura | baad333 | 2016-12-15 23:51:54 | [diff] [blame] | 152 | modules.append('appengine_module') |
| 153 | modules.extend(get_modules_with_coveragerc('appengine')) |
pgervais | 3a1b727 | 2014-10-01 18:53:54 | [diff] [blame] | 154 | |
Philippe Gervais | eeb839c | 2015-02-03 23:19:50 | [diff] [blame] | 155 | os.environ['PYTHONPATH'] = '' |
eseidel | bda3235 | 2014-09-04 23:08:47 | [diff] [blame] | 156 | os.chdir(INFRA_ROOT) |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 157 | if '--help' not in flags and '-h' not in flags: |
vadimsh | aa470f5 | 2015-05-13 22:32:11 | [diff] [blame] | 158 | subprocess.check_call( |
Brian Ryner | 652a91b | 2022-12-15 21:57:27 | [diff] [blame] | 159 | ['python3', '-u', |
Robert Iannucci | 6c4eebb | 2024-10-08 20:23:36 | [diff] [blame] | 160 | os.path.join('bootstrap', 'remove_orphaned_pycs.py'), |
| 161 | 'infra', 'appengine', 'packages', 'luci']) |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 162 | else: |
| 163 | usage() |
| 164 | sys.exit(subprocess.call([python_bin, expect_tests_path, command, '--help'])) |
| 165 | |
| 166 | if sys.platform == 'win32' and '--force-coverage' not in flags: |
| 167 | flags.append('--no-coverage') |
| 168 | |
| 169 | exit_code = 0 |
| 170 | failed_modules = [] |
| 171 | for module in modules: |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 172 | print('Running %s...%s' % (module, ' (py3)' if py3 else '')) |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 173 | module_flags = flags[:] |
Vadim Shtayura | 28b57b1 | 2016-12-15 22:45:31 | [diff] [blame] | 174 | # Remove any test glob, which comes after semicolon (:) and convert to a path. |
| 175 | module_path = module.split(':')[0].replace('/', os.sep) |
Sergiy Byelozyorov | b220095 | 2017-08-07 09:43:48 | [diff] [blame] | 176 | if not any(flag.startswith('--coveragerc') for flag in module_flags): |
| 177 | module_coveragerc = os.path.join(INFRA_ROOT, module_path, '.coveragerc') |
| 178 | module_flags.append('--coveragerc=%s' % module_coveragerc) |
| 179 | if not any(flag.startswith('--html-report-subdir') for flag in module_flags): |
| 180 | module_flags.append('--html-report-subdir=%s' % module_path) |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 181 | cmd = [python_bin, expect_tests_path, command, module] + module_flags |
| 182 | module_exit_code = subprocess.call(cmd) |
| 183 | exit_code = module_exit_code or exit_code |
| 184 | if module_exit_code: |
| 185 | failed_modules.append(module) |
| 186 | |
Brian Ryner | c7b2a20 | 2024-01-02 07:02:54 | [diff] [blame] | 187 | # Tests to run with vpython3 |
Brian Ryner | c4e7fc6 | 2024-02-07 23:06:39 | [diff] [blame] | 188 | if py3: |
| 189 | VPYTHON = 'vpython3' + ('.bat' if sys.platform == 'win32' else '') |
| 190 | for test in VPYTHON3_TESTS: |
| 191 | print('Running %s... (py3)' % test) |
| 192 | cmd = [VPYTHON, test] |
| 193 | test_exit_code = subprocess.call(cmd) |
| 194 | exit_code = test_exit_code or exit_code |
| 195 | if test_exit_code: |
| 196 | failed_modules.append(test) |
Brian Ryner | c7b2a20 | 2024-01-02 07:02:54 | [diff] [blame] | 197 | |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 198 | if exit_code: |
Andrew Chang | 6e83149 | 2020-09-16 23:21:52 | [diff] [blame] | 199 | print() |
| 200 | print('Tests failed in modules:\n %s' % '\n '.join(failed_modules)) |
sergeyberezin | e2eeb96 | 2016-05-10 21:40:38 | [diff] [blame] | 201 | if '--html-report' not in flags: |
Andrew Chang | 6e83149 | 2020-09-16 23:21:52 | [diff] [blame] | 202 | print('\nFor detailed coverage report and per-line branch coverage,') |
| 203 | print('rerun with --html-report <dir>') |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 204 | else: |
Andrew Chang | 6e83149 | 2020-09-16 23:21:52 | [diff] [blame] | 205 | print('All tests passed.') |
sergeyberezin | 0e47fe7 | 2016-04-27 18:47:34 | [diff] [blame] | 206 | |
| 207 | sys.exit(exit_code) |