blob: 8dc8b326e72632a67a207aaa80e571099fbe3b69 [file] [log] [blame]
Ian Zernydcb172e2022-02-22 15:36:45 +01001#!/usr/bin/env python3
Mads Ager418d1ca2017-05-22 09:35:49 +02002# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# Convenience script for running tests. If no argument is given run all tests,
7# if an argument is given, run only tests with that pattern. This script will
8# force the tests to run, even if no input changed.
9
Christoffer Quist Adamsen4684a0b2023-09-22 10:21:39 +020010import argparse
Ian Zerny5fffb0a2019-02-11 13:54:22 +010011import os
Ian Zerny24398bc2019-02-22 11:59:18 +010012import shutil
Rico Windf65a1d62017-06-30 09:41:56 +020013import subprocess
Mads Ager418d1ca2017-05-22 09:35:49 +020014import sys
Rico Windda6836e2018-12-07 12:32:03 +010015import time
Rico Wind06487ac2018-12-10 09:09:19 +010016import uuid
Ian Zerny5fffb0a2019-02-11 13:54:22 +010017
Ian Zerny3ced9262022-03-29 11:06:02 +020018import archive_desugar_jdk_libs
Søren Gjessedc697552025-03-13 14:47:01 +010019import download_kotlin
Ian Zerny5fffb0a2019-02-11 13:54:22 +010020import gradle
Ian Zerny3ced9262022-03-29 11:06:02 +020021import notify
Ian Zernyf271e8d2023-09-11 12:30:41 +020022import testing_state
Ian Zerny5fffb0a2019-02-11 13:54:22 +010023import utils
Jean-Marie Henaffce162f32017-10-04 10:39:27 +020024
Christoffer Quist Adamsen6962b1f2022-02-16 12:01:07 +010025if utils.is_python3():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020026 import threading
Christoffer Quist Adamsen6962b1f2022-02-16 12:01:07 +010027else:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020028 import thread
Christoffer Quist Adamsen6962b1f2022-02-16 12:01:07 +010029
Søren Gjessefe7c0112018-12-03 12:33:12 +010030ALL_ART_VMS = [
Søren Gjesse29b639d2024-05-28 14:39:56 +020031 "default", "15.0.0", "14.0.0", "13.0.0", "12.0.0", "10.0.0", "9.0.0",
32 "8.1.0", "7.0.0", "6.0.1", "5.1.1", "4.4.4", "4.0.4"
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020033]
Mads Ager418d1ca2017-05-22 09:35:49 +020034
Rico Windda6836e2018-12-07 12:32:03 +010035# How often do we check for progress on the bots:
36# Should be long enough that a normal run would always have med progress
37# Should be short enough that we ensure that two calls are close enough
38# to happen before bot times out.
39# A false positiv, i.e., printing the stacks of non hanging processes
Rico Wind46cdf982021-09-27 19:53:45 +020040# is not a problem, no harm done except some logging in stdout.
Rico Windda6836e2018-12-07 12:32:03 +010041TIMEOUT_HANDLER_PERIOD = 60 * 18
42
Rico Wind06487ac2018-12-10 09:09:19 +010043BUCKET = 'r8-test-results'
44
Ian Zerny24398bc2019-02-22 11:59:18 +010045NUMBER_OF_TEST_REPORTS = 5
46REPORTS_PATH = os.path.join(utils.BUILD, 'reports')
47REPORT_INDEX = ['tests', 'test', 'index.html']
Ian Zernybcbd6c52019-10-29 15:27:04 +010048VALID_RUNTIMES = [
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020049 'none',
50 'jdk8',
51 'jdk9',
52 'jdk11',
53 'jdk17',
Søren Gjessec00ff972023-11-20 16:03:55 +010054 'jdk21',
Søren Gjesse25ffd2a2024-12-09 13:45:27 +010055 'jdk23',
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020056] + ['dex-%s' % dexvm for dexvm in ALL_ART_VMS]
57
Ian Zerny24398bc2019-02-22 11:59:18 +010058
Mads Ager418d1ca2017-05-22 09:35:49 +020059def ParseOptions():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020060 result = argparse.ArgumentParser()
61 result.add_argument('--no-internal',
62 '--no_internal',
63 help='Do not run Google internal tests.',
64 default=False,
65 action='store_true')
66 result.add_argument('--archive-failures',
67 '--archive_failures',
68 help='Upload test results to cloud storage on failure.',
69 default=False,
70 action='store_true')
71 result.add_argument(
72 '--archive-failures-file-name',
73 '--archive_failures_file_name',
74 help='Set file name for the archived failures file name',
75 default=uuid.uuid4())
76 result.add_argument('--only-internal',
77 '--only_internal',
78 help='Only run Google internal tests.',
79 default=False,
80 action='store_true')
81 result.add_argument('--all-tests',
82 '--all_tests',
83 help='Run tests in all configurations.',
84 default=False,
85 action='store_true')
86 result.add_argument('--slow-tests',
87 '--slow_tests',
88 help='Also run slow tests.',
89 default=False,
90 action='store_true')
91 result.add_argument('-v',
92 '--verbose',
93 help='Print test stdout to, well, stdout.',
94 default=False,
95 action='store_true')
96 result.add_argument(
97 '--dex-vm',
98 '--dex_vm',
99 help='The android version of the vm to use. "all" will run the tests on '
100 'all art vm versions (stopping after first failed execution)',
101 default="default",
102 choices=ALL_ART_VMS + ["all"])
103 result.add_argument('--dex-vm-kind',
104 '--dex_vm_kind',
105 help='Whether to use host or target version of runtime',
106 default="host",
107 nargs=1,
108 choices=["host", "target"])
109 result.add_argument(
110 '--one-line-per-test',
111 '--one_line_per_test',
112 help='Print a line before a tests starts and after it ends to stdout.',
113 default=False,
114 action='store_true')
115 result.add_argument(
116 '--tool',
117 help='Tool to run ART tests with: "r8" (default) or "d8" or "r8cf"'
118 ' (r8 w/CF-backend). Ignored if "--all_tests" enabled.',
119 default=None,
120 choices=["r8", "d8", "r8cf"])
121 result.add_argument(
122 '--disable-assertions',
123 '--disable_assertions',
124 '-da',
125 help='Disable Java assertions when running the compiler '
126 '(default enabled)',
127 default=False,
128 action='store_true')
129 result.add_argument('--with-code-coverage',
130 '--with_code_coverage',
131 help='Enable code coverage with Jacoco.',
132 default=False,
133 action='store_true')
134 result.add_argument(
135 '--test-dir',
136 '--test_dir',
137 help='Use a custom directory for the test artifacts instead of a'
138 ' temporary (which is automatically removed after the test).'
139 ' Note that the directory will not be cleared before the test.')
140 result.add_argument(
141 '--command-cache-dir',
142 '--command_cache_dir',
143 help='Cache command invocations to this directory, speeds up test runs',
144 default=os.environ.get('R8_COMMAND_CACHE_DIR'))
145 result.add_argument(
146 '--command-cache-stats',
147 '--command_cache_stats',
148 help='Collect and print statistics about the command cache.',
149 default=False,
150 action='store_true')
151 result.add_argument('--java-home',
152 '--java_home',
153 help='Use a custom java version to run tests.')
154 result.add_argument('--java-max-memory-size',
155 '--java_max_memory_size',
156 help='Set memory for running tests, default 4G',
157 default=os.environ.get('R8_JAVA_MAX_MEMORY_SIZE', '4G'))
158 result.add_argument(
159 '--test-namespace',
160 '--test_namespace',
161 help='Only run tests in this namespace. The namespace is relative to '
162 'com/android/tools/r8, e.g., desugar/desugaredlibrary',
163 default=None)
164 result.add_argument('--shard-count',
165 '--shard_count',
166 help='We are running this many shards.')
167 result.add_argument('--shard-number',
168 '--shard_number',
169 help='We are running this shard.')
170 result.add_argument(
171 '--generate-golden-files-to',
172 '--generate_golden_files_to',
173 help='Store dex files produced by tests in the specified directory.'
174 ' It is aimed to be read on platforms with no host runtime available'
175 ' for comparison.')
176 result.add_argument(
177 '--use-golden-files-in',
178 '--use_golden_files_in',
179 help='Download golden files hierarchy for this commit in the specified'
180 ' location and use them instead of executing on host runtime.')
181 result.add_argument(
182 '--no-r8lib',
183 '--no_r8lib',
184 default=False,
185 action='store_true',
186 help='Run the tests on R8 full with relocated dependencies.')
187 result.add_argument('--no-arttests',
188 '--no_arttests',
189 default=False,
190 action='store_true',
191 help='Do not run the art tests.')
192 result.add_argument(
193 '--r8lib-no-deps',
194 '--r8lib_no_deps',
195 default=False,
196 action='store_true',
197 help='Run the tests on r8lib without relocated dependencies.')
198 result.add_argument('--failed',
199 default=False,
200 action='store_true',
201 help='Run the tests that failed last execution.')
202 result.add_argument(
203 '--fail-fast',
204 '--fail_fast',
205 default=False,
206 action='store_true',
207 help='Stop on first failure. Passes --fail-fast to gradle test runner.')
208 result.add_argument(
209 '--worktree',
210 default=False,
211 action='store_true',
212 help='Tests are run in worktree and should not use gradle user home.')
213 result.add_argument(
214 '--runtimes',
215 default=None,
216 help='Test parameter runtimes to use, separated by : (eg, none:jdk9).'
217 ' Special values include: all (for all runtimes)'
218 ' and empty (for no runtimes).')
219 result.add_argument('--print-hanging-stacks',
220 '--print_hanging_stacks',
221 default=-1,
222 type=int,
223 help='Print hanging stacks after timeout in seconds')
224 result.add_argument(
225 '--print-full-stacktraces',
226 '--print_full_stacktraces',
227 default=False,
228 action='store_true',
229 help='Print the full stacktraces without any filtering applied')
230 result.add_argument('--print-obfuscated-stacktraces',
231 '--print_obfuscated_stacktraces',
232 default=False,
233 action='store_true',
234 help='Print the obfuscated stacktraces')
235 result.add_argument(
236 '--debug-agent',
237 '--debug_agent',
238 help=
239 'Enable Java debug agent and suspend compilation (default disabled)',
240 default=False,
241 action='store_true')
242 result.add_argument('--desugared-library-configuration',
243 '--desugared_library-configuration',
244 help='Use alternative desugared library configuration.')
245 result.add_argument('--desugared-library',
246 '--desugared_library',
247 help='Build and use desugared library from GitHub.')
248 result.add_argument('--print-times',
249 '--print_times',
250 help='Print the execution time of the slowest tests..',
251 default=False,
252 action='store_true')
253 result.add_argument('--testing-state-dir',
254 help='Explicitly set the testing state directory '
255 '(defaults to build/test-state/<git-branch>).')
256 result.add_argument('--rerun',
257 help='Rerun tests (implicitly enables testing state).',
258 choices=testing_state.CHOICES)
259 result.add_argument('--stacktrace',
260 help='Pass --stacktrace to the gradle run',
261 default=False,
262 action='store_true')
Ian Zerny27cb1cc2024-02-01 14:20:35 +0100263 result.add_argument('--no-daemon',
264 help='Pass --no-daemon to the gradle run',
265 default=False,
266 action='store_true')
Christoffer Adamsen2aee8412024-09-19 12:20:08 +0200267 result.add_argument('--land',
268 help='Land current CL if tests pass',
269 default=False,
270 action='store_true')
271 result.add_argument('--land-bypass-hooks',
272 help='Pass --bypass-hooks to `git cl land`',
273 default=False,
274 action='store_true')
Rico Wind4088d342024-09-04 06:51:34 +0200275 result.add_argument('--low-priority',
276 help='Run gradle with priority=low (higher niceness)',
277 default=False,
278 action='store_true')
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200279 result.add_argument(
280 '--kotlin-compiler-dev',
281 help='Specify to download a kotlin dev compiler and run '
282 'tests with that',
283 default=False,
284 action='store_true')
285 result.add_argument('--kotlin-compiler-old',
286 help='Specify to run tests on older kotlin compilers',
287 default=False,
288 action='store_true')
Christoffer Adamsen2aee8412024-09-19 12:20:08 +0200289 options, args = result.parse_known_args()
290 if options.land_bypass_hooks:
291 options.land = True
292 return options, args
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200293
Mads Ager418d1ca2017-05-22 09:35:49 +0200294
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200295def has_failures(classes_file):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200296 with open(classes_file) as f:
297 contents = f.read()
298 # The report has a div tag with the percentage of tests that succeeded.
299 assert '<div class="percent">' in contents
300 return '<div class="percent">100%</div>' not in contents
301
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200302
303def should_upload(filename, absolute_filename):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200304 # filename is relative to REPO_ROOT/build/reports/tests
305 if filename.startswith('test/packages'):
306 # We don't upload the package overview
307 return False
308 if filename.startswith('test/classes'):
309 return has_failures(absolute_filename)
310 # Always upload index, css and js
311 return True
312
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200313
Morten Krogh-Jespersenef978ff2021-10-11 12:44:00 +0200314def archive_failures(options):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200315 upload_dir = os.path.join(utils.REPO_ROOT, 'build', 'reports', 'tests')
316 file_name = options.archive_failures_file_name
317 destination_dir = 'gs://%s/%s/' % (BUCKET, file_name)
318 for (dir_path, dir_names, file_names) in os.walk(upload_dir):
319 for f in file_names:
320 absolute_file = os.path.join(dir_path, f)
321 relative_file = absolute_file[len(upload_dir) + 1:]
322 if (should_upload(relative_file, absolute_file)):
323 utils.upload_file_to_cloud_storage(
324 absolute_file, destination_dir + relative_file)
325 url = 'https://storage.googleapis.com/%s/%s/test/index.html' % (BUCKET,
326 file_name)
327 print('Test results available at: %s' % url)
328
Rico Wind06487ac2018-12-10 09:09:19 +0100329
Rico Windfae6adb2024-08-02 11:09:16 +0200330def bot_symlinks():
331 art7 = os.path.join(utils.TOOLS_DIR, "linux", "art-7.0.0")
332 art7_sha = art7 + ".tar.gz.sha1"
333 utils.DownloadFromGoogleCloudStorage(art7_sha)
334 if not os.path.exists("tools/linux/art-7.0.0/lib/libncurses.so.5"):
335 os.symlink("/usr/lib/i386-linux-gnu/libncurses.so.6",
336 art7 + "/lib/libncurses.so.5")
Rico Wind8fccd142024-08-30 12:14:01 +0200337 if not os.path.exists("tools/linux/art-7.0.0/lib/libtinfo.so.5"):
338 # We don't have libtinfo, but this is never used, so we just need
339 # a valid 32bit library file.
340 os.symlink("/usr/lib/i386-linux-gnu/libncurses.so.6",
341 art7 + "/lib/libtinfo.so.5")
Rico Windfae6adb2024-08-02 11:09:16 +0200342 if not os.path.exists("tools/linux/art-7.0.0/lib64/libncurses.so.5"):
343 os.symlink("/usr/lib/x86_64-linux-gnu/libncurses.so.6",
344 art7 + "/lib64/libncurses.so.5")
Rico Wind8fccd142024-08-30 12:14:01 +0200345 if not os.path.exists("tools/linux/art-7.0.0/lib64/libtinfo.so.5"):
346 # We don't have libtinfo, but this is never used, so we just need
347 # a valid 64bit library file.
348 os.symlink("/usr/lib/x86_64-linux-gnu/libncurses.so.6",
349 art7 + "/lib64/libtinfo.so.5")
Rico Windfae6adb2024-08-02 11:09:16 +0200350
Christoffer Adamsen2aee8412024-09-19 12:20:08 +0200351
Mads Ager418d1ca2017-05-22 09:35:49 +0200352def Main():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200353 (options, args) = ParseOptions()
Christoffer Adamsen2aee8412024-09-19 12:20:08 +0200354 return_code = test(options, args)
355 if return_code == 0 and options.land:
356 land(options)
357 return return_code
358
359
360def test(options, args):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200361 if utils.is_bot():
362 gradle.RunGradle(['--no-daemon', 'clean'])
363 print('Running with python ' + str(sys.version_info))
364 # Always print stats on bots if command cache is enabled
365 options.command_cache_stats = options.command_cache_dir is not None
Rico Windfae6adb2024-08-02 11:09:16 +0200366 if options.dex_vm == '7.0.0':
367 bot_symlinks()
Sebastien Hertze2687b62017-07-25 11:16:04 +0200368
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200369 desugar_jdk_json_dir = None
370 if options.desugared_library_configuration:
371 if options.desugared_library_configuration != 'jdk11':
372 print("Only value supported for --desugared-library is 'jdk11'")
373 exit(1)
374 desugar_jdk_json_dir = 'src/library_desugar/jdk11'
Søren Gjesseef195772021-03-11 16:04:42 +0100375
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200376 desugar_jdk_libs = None
377 if options.desugared_library:
378 if options.desugared_library != 'HEAD':
379 print("Only value supported for --desugared-library is 'HEAD'")
380 exit(1)
381 desugar_jdk_libs_dir = 'build/desugar_jdk_libs'
382 shutil.rmtree(desugar_jdk_libs_dir, ignore_errors=True)
383 os.makedirs(desugar_jdk_libs_dir)
384 print('Building desugared library.')
385 with utils.TempDir() as checkout_dir:
386 archive_desugar_jdk_libs.CloneDesugaredLibrary(
387 'google', checkout_dir, 'HEAD')
388 # Make sure bazel is extracted in third_party.
389 utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE)
390 utils.DownloadFromGoogleCloudStorage(utils.JAVA8_SHA_FILE)
391 utils.DownloadFromGoogleCloudStorage(utils.JAVA11_SHA_FILE)
392 (library_jar,
393 maven_zip) = archive_desugar_jdk_libs.BuildDesugaredLibrary(
394 checkout_dir, 'jdk11_legacy' if
395 options.desugared_library_configuration == 'jdk11' else 'jdk8')
396 desugar_jdk_libs = os.path.join(desugar_jdk_libs_dir,
397 os.path.basename(library_jar))
398 shutil.copyfile(library_jar, desugar_jdk_libs)
399 print('Desugared library for test in ' + desugar_jdk_libs)
Søren Gjesse4a45f9b2021-02-11 14:05:29 +0100400
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200401 gradle_args = []
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200402
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200403 if options.stacktrace or utils.is_bot():
404 gradle_args.append('--stacktrace')
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200405
Ian Zerny27cb1cc2024-02-01 14:20:35 +0100406 if options.no_daemon or utils.is_bot():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200407 # Bots don't like dangling processes.
408 gradle_args.append('--no-daemon')
Rico Wind22707fc2019-03-15 13:19:57 +0100409
Rico Wind4088d342024-09-04 06:51:34 +0200410 if options.low_priority:
411 gradle_args.append('--priority=low')
Andrew Grievede8df452024-11-06 11:00:43 -0500412 # Default is 3, but some VMs become unresponsive with this value.
413 # Increase to reduce concurrency.
414 if not os.environ.get('R8_GRADLE_CORES_PER_FORK'):
415 os.environ['R8_GRADLE_CORES_PER_FORK'] = '5'
Rico Wind4088d342024-09-04 06:51:34 +0200416
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200417 # Set all necessary Gradle properties and options first.
418 if options.shard_count:
419 assert options.shard_number
420 gradle_args.append('-Pshard_count=%s' % options.shard_count)
421 gradle_args.append('-Pshard_number=%s' % options.shard_number)
422 if options.verbose:
423 gradle_args.append('-Pprint_test_stdout')
424 if options.no_internal:
425 gradle_args.append('-Pno_internal')
426 if options.only_internal:
427 gradle_args.append('-Ponly_internal')
428 if options.all_tests:
429 gradle_args.append('-Pall_tests')
430 if options.slow_tests:
431 gradle_args.append('-Pslow_tests=1')
432 if options.tool:
433 gradle_args.append('-Ptool=%s' % options.tool)
434 if options.one_line_per_test:
435 gradle_args.append('-Pone_line_per_test')
436 if options.test_namespace:
437 gradle_args.append('-Ptest_namespace=%s' % options.test_namespace)
438 if options.disable_assertions:
439 gradle_args.append('-Pdisable_assertions')
440 if options.with_code_coverage:
441 gradle_args.append('-Pwith_code_coverage')
442 if options.print_full_stacktraces:
443 gradle_args.append('-Pprint_full_stacktraces')
444 if options.print_obfuscated_stacktraces:
445 gradle_args.append('-Pprint_obfuscated_stacktraces')
446 if options.kotlin_compiler_old:
447 gradle_args.append('-Pkotlin_compiler_old')
448 if options.kotlin_compiler_dev:
449 gradle_args.append('-Pkotlin_compiler_dev')
Søren Gjessedc697552025-03-13 14:47:01 +0100450 download_kotlin.download_newest()
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200451 if os.name == 'nt':
452 gradle_args.append('-Pno_internal')
453 if options.test_dir:
454 gradle_args.append('-Ptest_dir=' + options.test_dir)
455 if not os.path.exists(options.test_dir):
456 os.makedirs(options.test_dir)
457 if options.command_cache_dir:
458 gradle_args.append('-Pcommand_cache_dir=' + options.command_cache_dir)
459 if not os.path.exists(options.command_cache_dir):
460 os.makedirs(options.command_cache_dir)
461 if options.command_cache_stats:
462 stats_dir = os.path.join(options.command_cache_dir, 'stats')
463 gradle_args.append('-Pcommand_cache_stats_dir=' + stats_dir)
464 if not os.path.exists(stats_dir):
465 os.makedirs(stats_dir)
466 # Clean out old stats files
467 for (_, _, file_names) in os.walk(stats_dir):
468 for f in file_names:
469 os.remove(os.path.join(stats_dir, f))
470 if options.java_home:
471 gradle_args.append('-Dorg.gradle.java.home=' + options.java_home)
472 if options.java_max_memory_size:
473 gradle_args.append('-Ptest_xmx=' + options.java_max_memory_size)
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200474 if options.generate_golden_files_to:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200475 gradle_args.append('-Pgenerate_golden_files_to=' +
476 options.generate_golden_files_to)
477 if not os.path.exists(options.generate_golden_files_to):
478 os.makedirs(options.generate_golden_files_to)
479 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
480 if options.use_golden_files_in:
481 gradle_args.append('-Puse_golden_files_in=' +
482 options.use_golden_files_in)
483 if not os.path.exists(options.use_golden_files_in):
484 os.makedirs(options.use_golden_files_in)
485 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
486 if options.r8lib_no_deps and options.no_r8lib:
487 print(
488 'Inconsistent arguments: both --no-r8lib and --r8lib-no-deps specified.'
489 )
490 exit(1)
491 if options.r8lib_no_deps:
492 gradle_args.append('-Pr8lib_no_deps')
493 elif not options.no_r8lib:
494 gradle_args.append('-Pr8lib')
495 if options.worktree:
496 gradle_args.append('-g=' +
497 os.path.join(utils.REPO_ROOT, ".gradle_user_home"))
498 gradle_args.append('--no-daemon')
499 if options.debug_agent:
500 gradle_args.append('--no-daemon')
501 if desugar_jdk_json_dir:
502 gradle_args.append('-Pdesugar_jdk_json_dir=' + desugar_jdk_json_dir)
503 if desugar_jdk_libs:
504 gradle_args.append('-Pdesugar_jdk_libs=' + desugar_jdk_libs)
505 if options.no_arttests:
506 gradle_args.append('-Pno_arttests=true')
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200507
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200508 if options.rerun:
509 testing_state.set_up_test_state(gradle_args, options.rerun,
510 options.testing_state_dir)
Mads Ager418d1ca2017-05-22 09:35:49 +0200511
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200512 # Enable completeness testing of ART profile rewriting.
513 gradle_args.append('-Part_profile_rewriting_completeness_check=true')
514
515 # Build an R8 with dependencies for bootstrapping tests before adding test sources.
516 gradle_args.append(utils.GRADLE_TASK_R8)
517 gradle_args.append(utils.GRADLE_TASK_CLEAN_TEST)
518 gradle_args.append(utils.GRADLE_TASK_TEST)
519 gradle_args.append('--stacktrace')
520 gradle_args.append('-Pprint_full_stacktraces')
521
522 if options.debug_agent:
523 gradle_args.append('--debug-jvm')
524 if options.fail_fast:
525 gradle_args.append('--fail-fast')
526 if options.failed:
527 args = compute_failed_tests(args)
528 if args is None:
529 return 1
530 if len(args) == 0:
531 print("No failing tests")
532 return 0
533 # Test filtering. Must always follow the 'test' task.
534 testFilterProperty = []
535 for testFilter in args:
536 gradle_args.append('--tests')
537 gradle_args.append(testFilter)
538 testFilterProperty.append(testFilter)
539 assert not ("|" in testFilter), "| is used as separating character"
540 if len(testFilterProperty) > 0:
541 gradle_args.append("-Ptestfilter=" + "|".join(testFilterProperty))
542 if options.with_code_coverage:
543 # Create Jacoco report after tests.
544 gradle_args.append('jacocoTestReport')
545
546 if options.use_golden_files_in:
547 sha1 = '%s' % utils.get_HEAD_sha1()
548 with utils.ChangedWorkingDirectory(options.use_golden_files_in):
549 utils.download_file_from_cloud_storage(
550 'gs://r8-test-results/golden-files/%s.tar.gz' % sha1,
551 '%s.tar.gz' % sha1)
552 utils.unpack_archive('%s.tar.gz' % sha1)
553
554 print_stacks_timeout = options.print_hanging_stacks
555 if (utils.is_bot() and not utils.IsWindows()) or print_stacks_timeout > -1:
556 timestamp_file = os.path.join(utils.BUILD, 'last_test_time')
557 if os.path.exists(timestamp_file):
558 os.remove(timestamp_file)
559 gradle_args.append('-Pupdate_test_timestamp=' + timestamp_file)
560 print_stacks_timeout = (print_stacks_timeout if print_stacks_timeout
561 != -1 else TIMEOUT_HANDLER_PERIOD)
562 if utils.is_python3():
563 threading.Thread(target=timeout_handler,
564 args=(timestamp_file, print_stacks_timeout),
565 daemon=True).start()
566 else:
567 thread.start_new_thread(timeout_handler, (
568 timestamp_file,
569 print_stacks_timeout,
570 ))
571 rotate_test_reports()
572
Rico Wind847b9282024-03-26 09:11:29 +0100573 if options.print_times:
574 gradle_args.append('-Pprint_times=true')
575
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200576 # Now run tests on selected runtime(s).
577 if options.runtimes:
578 if options.dex_vm != 'default':
579 print('Unexpected runtimes and dex_vm argument: ' + options.dex_vm)
580 sys.exit(1)
581 if options.runtimes == 'empty':
582 # Set runtimes with no content will configure no runtimes.
583 gradle_args.append('-Pruntimes=')
584 elif options.runtimes == 'all':
585 # An unset runtimes will configure all runtimes
586 pass
587 else:
588 prefixes = [
589 prefix.strip() for prefix in options.runtimes.split(':')
590 ]
591 runtimes = []
592 for prefix in prefixes:
593 matches = [rt for rt in VALID_RUNTIMES if rt.startswith(prefix)]
594 if len(matches) == 0:
595 print("Invalid runtime prefix '%s'." % prefix)
596 print("Must be just 'all', 'empty'," \
597 " or a prefix of %s" % ', '.join(VALID_RUNTIMES))
598 sys.exit(1)
599 runtimes.extend(matches)
600 gradle_args.append('-Pruntimes=%s' % ':'.join(runtimes))
601
602 return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
603 return archive_and_return(return_code, options)
604
605 # Legacy testing populates the runtimes based on dex_vm.
606 vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
607
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200608 for art_vm in vms_to_test:
609 vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
610 runtimes = ['dex-' + art_vm]
611 # Append the "none" runtime and default JVM if running the "default" DEX VM.
612 if art_vm == "default":
613 runtimes.extend(['jdk11', 'none'])
614 return_code = gradle.RunGradle(gradle_args + [
615 '-Pdex_vm=%s' % art_vm + vm_suffix,
616 '-Pruntimes=%s' % ':'.join(runtimes),
617 ],
618 throw_on_failure=False)
619 if options.generate_golden_files_to:
620 sha1 = '%s' % utils.get_HEAD_sha1()
621 with utils.ChangedWorkingDirectory(
622 options.generate_golden_files_to):
623 archive = utils.create_archive(sha1)
624 utils.upload_file_to_cloud_storage(
625 archive, 'gs://r8-test-results/golden-files/' + archive)
626
627 return archive_and_return(return_code, options)
628
629 return 0
630
Jinseong Jeon9749d172017-09-19 00:25:01 -0700631
Ian Zerny17561362019-05-27 15:16:26 +0200632def archive_and_return(return_code, options):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200633 if return_code != 0:
634 if options.archive_failures:
635 archive_failures(options)
636 if options.command_cache_stats:
637 stats_dir = os.path.join(options.command_cache_dir, 'stats')
638 cache_hit = 0
639 cache_miss = 0
640 cache_put = 0
641 for (_, _, file_names) in os.walk(stats_dir):
642 for f in file_names:
643 if f.endswith('CACHEHIT'):
644 cache_hit += os.stat(os.path.join(stats_dir, f)).st_size
645 if f.endswith('CACHEMISS'):
646 cache_miss += os.stat(os.path.join(stats_dir, f)).st_size
647 if f.endswith('CACHEPUT'):
648 cache_put += os.stat(os.path.join(stats_dir, f)).st_size
649 print('Command cache stats')
650 print(' Cache hits: ' + str(cache_hit))
651 print(' Cache miss: ' + str(cache_miss))
652 print(' Cache puts: ' + str(cache_put))
653 return return_code
654
Rico Windc58a20e2019-05-23 09:43:19 +0200655
Christoffer Adamsen2aee8412024-09-19 12:20:08 +0200656def land(options):
657 cmd = ['git', 'cl', 'land']
658 if options.land_bypass_hooks:
659 cmd.append('--bypass-hooks')
660 subprocess.check_call(cmd)
661
662
Rico Windda6836e2018-12-07 12:32:03 +0100663def print_jstacks():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200664 processes = subprocess.check_output(['ps', 'aux']).decode('utf-8')
665 for l in processes.splitlines():
666 if 'art' in l or 'dalvik' in l:
667 print('Running art of dalvik process: \n%s' % l)
668 if 'java' in l and 'openjdk' in l:
669 print('Running jstack on process: \n%s' % l)
670 # Example line:
671 # ricow 184313 2.6 0.0 36839068 31808 ? Sl 09:53 0:00 /us..
672 columns = l.split()
673 pid = columns[1]
674 return_value = subprocess.call(['jstack', pid])
675 if return_value:
676 print('Could not jstack %s' % l)
677
Rico Windda6836e2018-12-07 12:32:03 +0100678
679def get_time_from_file(timestamp_file):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200680 if os.path.exists(timestamp_file):
681 timestamp = os.stat(timestamp_file).st_mtime
682 print('TIMEOUT HANDLER timestamp: %s' % (timestamp))
683 sys.stdout.flush()
684 return timestamp
685 else:
686 print('TIMEOUT HANDLER no timestamp file yet')
687 sys.stdout.flush()
688 return None
689
Rico Windda6836e2018-12-07 12:32:03 +0100690
Morten Krogh-Jespersendcb8d452020-07-09 15:07:50 +0200691def timeout_handler(timestamp_file, timeout_handler_period):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200692 last_timestamp = None
693 while True:
694 time.sleep(timeout_handler_period)
695 new_timestamp = get_time_from_file(timestamp_file)
696 if last_timestamp and new_timestamp == last_timestamp:
697 print_jstacks()
698 last_timestamp = new_timestamp
699
Rico Windda6836e2018-12-07 12:32:03 +0100700
Ian Zerny24398bc2019-02-22 11:59:18 +0100701def report_dir_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200702 if index == 0:
703 return REPORTS_PATH
704 return '%s%d' % (REPORTS_PATH, index)
705
Ian Zerny24398bc2019-02-22 11:59:18 +0100706
707def report_index_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200708 return os.path.join(report_dir_path(index), *REPORT_INDEX)
709
Ian Zerny24398bc2019-02-22 11:59:18 +0100710
711# Rotate test results so previous results are still accessible.
712def rotate_test_reports():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200713 if not os.path.exists(report_dir_path(0)):
714 return
715 i = 1
716 while i < NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
717 i += 1
718 if i == NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
719 shutil.rmtree(report_dir_path(i))
720 while i > 0:
721 shutil.move(report_dir_path(i - 1), report_dir_path(i))
722 i -= 1
723
Ian Zerny24398bc2019-02-22 11:59:18 +0100724
725def compute_failed_tests(args):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200726 if len(args) > 1:
727 print(
728 "Running with --failed can take an optional path to a report index (or report number)."
729 )
730 return None
731 report = report_index_path(0)
732 # If the default report does not exist, fall back to the previous report as it may be a failed
733 # gradle run which has already moved the report to report1, but did not produce a new report.
734 if not os.path.exists(report):
735 report1 = report_index_path(1)
736 if os.path.exists(report1):
737 report = report1
738 if len(args) == 1:
739 try:
740 # try to parse the arg as a report index.
741 index = int(args[0])
742 report = report_index_path(index)
743 except ValueError:
744 # if integer parsing failed assume it is a report file path.
745 report = args[0]
746 if not os.path.exists(report):
747 print("Can't re-run failing, no report at:", report)
748 return None
749 print("Reading failed tests in", report)
750 failing = set()
751 inFailedSection = False
752 for line in open(report):
753 l = line.strip()
754 if l == "<h2>Failed tests</h2>":
755 inFailedSection = True
756 elif l.startswith("<h2>"):
757 inFailedSection = False
758 prefix = '<a href="classes/'
759 if inFailedSection and l.startswith(prefix):
760 href = l[len(prefix):l.index('">')]
761 # Ignore enties ending with .html which are test classes, not test methods.
762 if not href.endswith('.html'):
763 # Remove the .html and anchor separateor, also, a classMethod test is the static
764 # setup failing so rerun the full class of tests.
765 test = href.replace('.html', '').replace('#', '.').replace(
766 '.classMethod', '')
767 failing.add(test)
768 return list(failing)
769
770
Mads Ager418d1ca2017-05-22 09:35:49 +0200771if __name__ == '__main__':
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200772 return_code = Main()
773 if return_code != 0:
774 notify.notify("Tests failed.")
775 else:
776 notify.notify("Tests passed.")
777 sys.exit(return_code)