blob: 9aee64a4b32a4069d99672bae3c8384d2d91845a [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
19import download_kotlin_dev
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 Gjesseeeb3e5b2024-05-31 10:51:21 +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 Gjessee9a4fe82024-04-29 09:26:05 +020055 'jdk22',
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 Quist Adamsen2434a4d2023-10-16 11:29:03 +0200267 result.add_argument(
268 '--kotlin-compiler-dev',
269 help='Specify to download a kotlin dev compiler and run '
270 'tests with that',
271 default=False,
272 action='store_true')
273 result.add_argument('--kotlin-compiler-old',
274 help='Specify to run tests on older kotlin compilers',
275 default=False,
276 action='store_true')
277 return result.parse_known_args()
278
Mads Ager418d1ca2017-05-22 09:35:49 +0200279
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200280def has_failures(classes_file):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200281 with open(classes_file) as f:
282 contents = f.read()
283 # The report has a div tag with the percentage of tests that succeeded.
284 assert '<div class="percent">' in contents
285 return '<div class="percent">100%</div>' not in contents
286
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200287
288def should_upload(filename, absolute_filename):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200289 # filename is relative to REPO_ROOT/build/reports/tests
290 if filename.startswith('test/packages'):
291 # We don't upload the package overview
292 return False
293 if filename.startswith('test/classes'):
294 return has_failures(absolute_filename)
295 # Always upload index, css and js
296 return True
297
Rico Wind4cd3cbc2022-04-26 11:25:15 +0200298
Morten Krogh-Jespersenef978ff2021-10-11 12:44:00 +0200299def archive_failures(options):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200300 upload_dir = os.path.join(utils.REPO_ROOT, 'build', 'reports', 'tests')
301 file_name = options.archive_failures_file_name
302 destination_dir = 'gs://%s/%s/' % (BUCKET, file_name)
303 for (dir_path, dir_names, file_names) in os.walk(upload_dir):
304 for f in file_names:
305 absolute_file = os.path.join(dir_path, f)
306 relative_file = absolute_file[len(upload_dir) + 1:]
307 if (should_upload(relative_file, absolute_file)):
308 utils.upload_file_to_cloud_storage(
309 absolute_file, destination_dir + relative_file)
310 url = 'https://storage.googleapis.com/%s/%s/test/index.html' % (BUCKET,
311 file_name)
312 print('Test results available at: %s' % url)
313
Rico Wind06487ac2018-12-10 09:09:19 +0100314
Mads Ager418d1ca2017-05-22 09:35:49 +0200315def Main():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200316 (options, args) = ParseOptions()
317 if utils.is_bot():
318 gradle.RunGradle(['--no-daemon', 'clean'])
319 print('Running with python ' + str(sys.version_info))
320 # Always print stats on bots if command cache is enabled
321 options.command_cache_stats = options.command_cache_dir is not None
Sebastien Hertze2687b62017-07-25 11:16:04 +0200322
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200323 desugar_jdk_json_dir = None
324 if options.desugared_library_configuration:
325 if options.desugared_library_configuration != 'jdk11':
326 print("Only value supported for --desugared-library is 'jdk11'")
327 exit(1)
328 desugar_jdk_json_dir = 'src/library_desugar/jdk11'
Søren Gjesseef195772021-03-11 16:04:42 +0100329
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200330 desugar_jdk_libs = None
331 if options.desugared_library:
332 if options.desugared_library != 'HEAD':
333 print("Only value supported for --desugared-library is 'HEAD'")
334 exit(1)
335 desugar_jdk_libs_dir = 'build/desugar_jdk_libs'
336 shutil.rmtree(desugar_jdk_libs_dir, ignore_errors=True)
337 os.makedirs(desugar_jdk_libs_dir)
338 print('Building desugared library.')
339 with utils.TempDir() as checkout_dir:
340 archive_desugar_jdk_libs.CloneDesugaredLibrary(
341 'google', checkout_dir, 'HEAD')
342 # Make sure bazel is extracted in third_party.
343 utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE)
344 utils.DownloadFromGoogleCloudStorage(utils.JAVA8_SHA_FILE)
345 utils.DownloadFromGoogleCloudStorage(utils.JAVA11_SHA_FILE)
346 (library_jar,
347 maven_zip) = archive_desugar_jdk_libs.BuildDesugaredLibrary(
348 checkout_dir, 'jdk11_legacy' if
349 options.desugared_library_configuration == 'jdk11' else 'jdk8')
350 desugar_jdk_libs = os.path.join(desugar_jdk_libs_dir,
351 os.path.basename(library_jar))
352 shutil.copyfile(library_jar, desugar_jdk_libs)
353 print('Desugared library for test in ' + desugar_jdk_libs)
Søren Gjesse4a45f9b2021-02-11 14:05:29 +0100354
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200355 gradle_args = []
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200356
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200357 if options.stacktrace or utils.is_bot():
358 gradle_args.append('--stacktrace')
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200359
Ian Zerny27cb1cc2024-02-01 14:20:35 +0100360 if options.no_daemon or utils.is_bot():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200361 # Bots don't like dangling processes.
362 gradle_args.append('--no-daemon')
Rico Wind22707fc2019-03-15 13:19:57 +0100363
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200364 # Set all necessary Gradle properties and options first.
365 if options.shard_count:
366 assert options.shard_number
367 gradle_args.append('-Pshard_count=%s' % options.shard_count)
368 gradle_args.append('-Pshard_number=%s' % options.shard_number)
369 if options.verbose:
370 gradle_args.append('-Pprint_test_stdout')
371 if options.no_internal:
372 gradle_args.append('-Pno_internal')
373 if options.only_internal:
374 gradle_args.append('-Ponly_internal')
375 if options.all_tests:
376 gradle_args.append('-Pall_tests')
377 if options.slow_tests:
378 gradle_args.append('-Pslow_tests=1')
379 if options.tool:
380 gradle_args.append('-Ptool=%s' % options.tool)
381 if options.one_line_per_test:
382 gradle_args.append('-Pone_line_per_test')
383 if options.test_namespace:
384 gradle_args.append('-Ptest_namespace=%s' % options.test_namespace)
385 if options.disable_assertions:
386 gradle_args.append('-Pdisable_assertions')
387 if options.with_code_coverage:
388 gradle_args.append('-Pwith_code_coverage')
389 if options.print_full_stacktraces:
390 gradle_args.append('-Pprint_full_stacktraces')
391 if options.print_obfuscated_stacktraces:
392 gradle_args.append('-Pprint_obfuscated_stacktraces')
393 if options.kotlin_compiler_old:
394 gradle_args.append('-Pkotlin_compiler_old')
395 if options.kotlin_compiler_dev:
396 gradle_args.append('-Pkotlin_compiler_dev')
397 download_kotlin_dev.download_newest()
398 if os.name == 'nt':
399 gradle_args.append('-Pno_internal')
400 if options.test_dir:
401 gradle_args.append('-Ptest_dir=' + options.test_dir)
402 if not os.path.exists(options.test_dir):
403 os.makedirs(options.test_dir)
404 if options.command_cache_dir:
405 gradle_args.append('-Pcommand_cache_dir=' + options.command_cache_dir)
406 if not os.path.exists(options.command_cache_dir):
407 os.makedirs(options.command_cache_dir)
408 if options.command_cache_stats:
409 stats_dir = os.path.join(options.command_cache_dir, 'stats')
410 gradle_args.append('-Pcommand_cache_stats_dir=' + stats_dir)
411 if not os.path.exists(stats_dir):
412 os.makedirs(stats_dir)
413 # Clean out old stats files
414 for (_, _, file_names) in os.walk(stats_dir):
415 for f in file_names:
416 os.remove(os.path.join(stats_dir, f))
417 if options.java_home:
418 gradle_args.append('-Dorg.gradle.java.home=' + options.java_home)
419 if options.java_max_memory_size:
420 gradle_args.append('-Ptest_xmx=' + options.java_max_memory_size)
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200421 if options.generate_golden_files_to:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200422 gradle_args.append('-Pgenerate_golden_files_to=' +
423 options.generate_golden_files_to)
424 if not os.path.exists(options.generate_golden_files_to):
425 os.makedirs(options.generate_golden_files_to)
426 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
427 if options.use_golden_files_in:
428 gradle_args.append('-Puse_golden_files_in=' +
429 options.use_golden_files_in)
430 if not os.path.exists(options.use_golden_files_in):
431 os.makedirs(options.use_golden_files_in)
432 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
433 if options.r8lib_no_deps and options.no_r8lib:
434 print(
435 'Inconsistent arguments: both --no-r8lib and --r8lib-no-deps specified.'
436 )
437 exit(1)
438 if options.r8lib_no_deps:
439 gradle_args.append('-Pr8lib_no_deps')
440 elif not options.no_r8lib:
441 gradle_args.append('-Pr8lib')
442 if options.worktree:
443 gradle_args.append('-g=' +
444 os.path.join(utils.REPO_ROOT, ".gradle_user_home"))
445 gradle_args.append('--no-daemon')
446 if options.debug_agent:
447 gradle_args.append('--no-daemon')
448 if desugar_jdk_json_dir:
449 gradle_args.append('-Pdesugar_jdk_json_dir=' + desugar_jdk_json_dir)
450 if desugar_jdk_libs:
451 gradle_args.append('-Pdesugar_jdk_libs=' + desugar_jdk_libs)
452 if options.no_arttests:
453 gradle_args.append('-Pno_arttests=true')
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200454
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200455 if options.rerun:
456 testing_state.set_up_test_state(gradle_args, options.rerun,
457 options.testing_state_dir)
Mads Ager418d1ca2017-05-22 09:35:49 +0200458
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200459 # Enable completeness testing of ART profile rewriting.
460 gradle_args.append('-Part_profile_rewriting_completeness_check=true')
461
462 # Build an R8 with dependencies for bootstrapping tests before adding test sources.
463 gradle_args.append(utils.GRADLE_TASK_R8)
464 gradle_args.append(utils.GRADLE_TASK_CLEAN_TEST)
465 gradle_args.append(utils.GRADLE_TASK_TEST)
466 gradle_args.append('--stacktrace')
467 gradle_args.append('-Pprint_full_stacktraces')
468
469 if options.debug_agent:
470 gradle_args.append('--debug-jvm')
471 if options.fail_fast:
472 gradle_args.append('--fail-fast')
473 if options.failed:
474 args = compute_failed_tests(args)
475 if args is None:
476 return 1
477 if len(args) == 0:
478 print("No failing tests")
479 return 0
480 # Test filtering. Must always follow the 'test' task.
481 testFilterProperty = []
482 for testFilter in args:
483 gradle_args.append('--tests')
484 gradle_args.append(testFilter)
485 testFilterProperty.append(testFilter)
486 assert not ("|" in testFilter), "| is used as separating character"
487 if len(testFilterProperty) > 0:
488 gradle_args.append("-Ptestfilter=" + "|".join(testFilterProperty))
489 if options.with_code_coverage:
490 # Create Jacoco report after tests.
491 gradle_args.append('jacocoTestReport')
492
493 if options.use_golden_files_in:
494 sha1 = '%s' % utils.get_HEAD_sha1()
495 with utils.ChangedWorkingDirectory(options.use_golden_files_in):
496 utils.download_file_from_cloud_storage(
497 'gs://r8-test-results/golden-files/%s.tar.gz' % sha1,
498 '%s.tar.gz' % sha1)
499 utils.unpack_archive('%s.tar.gz' % sha1)
500
501 print_stacks_timeout = options.print_hanging_stacks
502 if (utils.is_bot() and not utils.IsWindows()) or print_stacks_timeout > -1:
503 timestamp_file = os.path.join(utils.BUILD, 'last_test_time')
504 if os.path.exists(timestamp_file):
505 os.remove(timestamp_file)
506 gradle_args.append('-Pupdate_test_timestamp=' + timestamp_file)
507 print_stacks_timeout = (print_stacks_timeout if print_stacks_timeout
508 != -1 else TIMEOUT_HANDLER_PERIOD)
509 if utils.is_python3():
510 threading.Thread(target=timeout_handler,
511 args=(timestamp_file, print_stacks_timeout),
512 daemon=True).start()
513 else:
514 thread.start_new_thread(timeout_handler, (
515 timestamp_file,
516 print_stacks_timeout,
517 ))
518 rotate_test_reports()
519
Rico Wind847b9282024-03-26 09:11:29 +0100520 if options.print_times:
521 gradle_args.append('-Pprint_times=true')
522
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200523 # Now run tests on selected runtime(s).
524 if options.runtimes:
525 if options.dex_vm != 'default':
526 print('Unexpected runtimes and dex_vm argument: ' + options.dex_vm)
527 sys.exit(1)
528 if options.runtimes == 'empty':
529 # Set runtimes with no content will configure no runtimes.
530 gradle_args.append('-Pruntimes=')
531 elif options.runtimes == 'all':
532 # An unset runtimes will configure all runtimes
533 pass
534 else:
535 prefixes = [
536 prefix.strip() for prefix in options.runtimes.split(':')
537 ]
538 runtimes = []
539 for prefix in prefixes:
540 matches = [rt for rt in VALID_RUNTIMES if rt.startswith(prefix)]
541 if len(matches) == 0:
542 print("Invalid runtime prefix '%s'." % prefix)
543 print("Must be just 'all', 'empty'," \
544 " or a prefix of %s" % ', '.join(VALID_RUNTIMES))
545 sys.exit(1)
546 runtimes.extend(matches)
547 gradle_args.append('-Pruntimes=%s' % ':'.join(runtimes))
548
549 return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
550 return archive_and_return(return_code, options)
551
552 # Legacy testing populates the runtimes based on dex_vm.
553 vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
554
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200555 for art_vm in vms_to_test:
556 vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
557 runtimes = ['dex-' + art_vm]
558 # Append the "none" runtime and default JVM if running the "default" DEX VM.
559 if art_vm == "default":
560 runtimes.extend(['jdk11', 'none'])
561 return_code = gradle.RunGradle(gradle_args + [
562 '-Pdex_vm=%s' % art_vm + vm_suffix,
563 '-Pruntimes=%s' % ':'.join(runtimes),
564 ],
565 throw_on_failure=False)
566 if options.generate_golden_files_to:
567 sha1 = '%s' % utils.get_HEAD_sha1()
568 with utils.ChangedWorkingDirectory(
569 options.generate_golden_files_to):
570 archive = utils.create_archive(sha1)
571 utils.upload_file_to_cloud_storage(
572 archive, 'gs://r8-test-results/golden-files/' + archive)
573
574 return archive_and_return(return_code, options)
575
576 return 0
577
Jinseong Jeon9749d172017-09-19 00:25:01 -0700578
Ian Zerny17561362019-05-27 15:16:26 +0200579def archive_and_return(return_code, options):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200580 if return_code != 0:
581 if options.archive_failures:
582 archive_failures(options)
583 if options.command_cache_stats:
584 stats_dir = os.path.join(options.command_cache_dir, 'stats')
585 cache_hit = 0
586 cache_miss = 0
587 cache_put = 0
588 for (_, _, file_names) in os.walk(stats_dir):
589 for f in file_names:
590 if f.endswith('CACHEHIT'):
591 cache_hit += os.stat(os.path.join(stats_dir, f)).st_size
592 if f.endswith('CACHEMISS'):
593 cache_miss += os.stat(os.path.join(stats_dir, f)).st_size
594 if f.endswith('CACHEPUT'):
595 cache_put += os.stat(os.path.join(stats_dir, f)).st_size
596 print('Command cache stats')
597 print(' Cache hits: ' + str(cache_hit))
598 print(' Cache miss: ' + str(cache_miss))
599 print(' Cache puts: ' + str(cache_put))
600 return return_code
601
Rico Windc58a20e2019-05-23 09:43:19 +0200602
Rico Windda6836e2018-12-07 12:32:03 +0100603def print_jstacks():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200604 processes = subprocess.check_output(['ps', 'aux']).decode('utf-8')
605 for l in processes.splitlines():
606 if 'art' in l or 'dalvik' in l:
607 print('Running art of dalvik process: \n%s' % l)
608 if 'java' in l and 'openjdk' in l:
609 print('Running jstack on process: \n%s' % l)
610 # Example line:
611 # ricow 184313 2.6 0.0 36839068 31808 ? Sl 09:53 0:00 /us..
612 columns = l.split()
613 pid = columns[1]
614 return_value = subprocess.call(['jstack', pid])
615 if return_value:
616 print('Could not jstack %s' % l)
617
Rico Windda6836e2018-12-07 12:32:03 +0100618
619def get_time_from_file(timestamp_file):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200620 if os.path.exists(timestamp_file):
621 timestamp = os.stat(timestamp_file).st_mtime
622 print('TIMEOUT HANDLER timestamp: %s' % (timestamp))
623 sys.stdout.flush()
624 return timestamp
625 else:
626 print('TIMEOUT HANDLER no timestamp file yet')
627 sys.stdout.flush()
628 return None
629
Rico Windda6836e2018-12-07 12:32:03 +0100630
Morten Krogh-Jespersendcb8d452020-07-09 15:07:50 +0200631def timeout_handler(timestamp_file, timeout_handler_period):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200632 last_timestamp = None
633 while True:
634 time.sleep(timeout_handler_period)
635 new_timestamp = get_time_from_file(timestamp_file)
636 if last_timestamp and new_timestamp == last_timestamp:
637 print_jstacks()
638 last_timestamp = new_timestamp
639
Rico Windda6836e2018-12-07 12:32:03 +0100640
Ian Zerny24398bc2019-02-22 11:59:18 +0100641def report_dir_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200642 if index == 0:
643 return REPORTS_PATH
644 return '%s%d' % (REPORTS_PATH, index)
645
Ian Zerny24398bc2019-02-22 11:59:18 +0100646
647def report_index_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200648 return os.path.join(report_dir_path(index), *REPORT_INDEX)
649
Ian Zerny24398bc2019-02-22 11:59:18 +0100650
651# Rotate test results so previous results are still accessible.
652def rotate_test_reports():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200653 if not os.path.exists(report_dir_path(0)):
654 return
655 i = 1
656 while i < NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
657 i += 1
658 if i == NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
659 shutil.rmtree(report_dir_path(i))
660 while i > 0:
661 shutil.move(report_dir_path(i - 1), report_dir_path(i))
662 i -= 1
663
Ian Zerny24398bc2019-02-22 11:59:18 +0100664
665def compute_failed_tests(args):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200666 if len(args) > 1:
667 print(
668 "Running with --failed can take an optional path to a report index (or report number)."
669 )
670 return None
671 report = report_index_path(0)
672 # If the default report does not exist, fall back to the previous report as it may be a failed
673 # gradle run which has already moved the report to report1, but did not produce a new report.
674 if not os.path.exists(report):
675 report1 = report_index_path(1)
676 if os.path.exists(report1):
677 report = report1
678 if len(args) == 1:
679 try:
680 # try to parse the arg as a report index.
681 index = int(args[0])
682 report = report_index_path(index)
683 except ValueError:
684 # if integer parsing failed assume it is a report file path.
685 report = args[0]
686 if not os.path.exists(report):
687 print("Can't re-run failing, no report at:", report)
688 return None
689 print("Reading failed tests in", report)
690 failing = set()
691 inFailedSection = False
692 for line in open(report):
693 l = line.strip()
694 if l == "<h2>Failed tests</h2>":
695 inFailedSection = True
696 elif l.startswith("<h2>"):
697 inFailedSection = False
698 prefix = '<a href="classes/'
699 if inFailedSection and l.startswith(prefix):
700 href = l[len(prefix):l.index('">')]
701 # Ignore enties ending with .html which are test classes, not test methods.
702 if not href.endswith('.html'):
703 # Remove the .html and anchor separateor, also, a classMethod test is the static
704 # setup failing so rerun the full class of tests.
705 test = href.replace('.html', '').replace('#', '.').replace(
706 '.classMethod', '')
707 failing.add(test)
708 return list(failing)
709
710
Mads Ager418d1ca2017-05-22 09:35:49 +0200711if __name__ == '__main__':
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200712 return_code = Main()
713 if return_code != 0:
714 notify.notify("Tests failed.")
715 else:
716 notify.notify("Tests passed.")
717 sys.exit(return_code)