blob: 973f8a413da7f24d800a69494b16c0b654d59751 [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 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 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
Rico Wind18a46992024-08-13 13:08:38 +0200315def bot_symlinks():
316 art7 = os.path.join(utils.TOOLS_DIR, "linux", "art-7.0.0")
317 art7_sha = art7 + ".tar.gz.sha1"
318 utils.DownloadFromGoogleCloudStorage(art7_sha)
319 if not os.path.exists("tools/linux/art-7.0.0/lib/libncurses.so.5"):
320 os.symlink("/usr/lib/i386-linux-gnu/libncurses.so.6",
321 art7 + "/lib/libncurses.so.5")
322 if not os.path.exists("tools/linux/art-7.0.0/lib64/libncurses.so.5"):
323 os.symlink("/usr/lib/x86_64-linux-gnu/libncurses.so.6",
324 art7 + "/lib64/libncurses.so.5")
325
Mads Ager418d1ca2017-05-22 09:35:49 +0200326def Main():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200327 (options, args) = ParseOptions()
328 if utils.is_bot():
329 gradle.RunGradle(['--no-daemon', 'clean'])
330 print('Running with python ' + str(sys.version_info))
331 # Always print stats on bots if command cache is enabled
332 options.command_cache_stats = options.command_cache_dir is not None
Rico Wind18a46992024-08-13 13:08:38 +0200333 if options.dex_vm == '7.0.0':
334 bot_symlinks()
Sebastien Hertze2687b62017-07-25 11:16:04 +0200335
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200336 desugar_jdk_json_dir = None
337 if options.desugared_library_configuration:
338 if options.desugared_library_configuration != 'jdk11':
339 print("Only value supported for --desugared-library is 'jdk11'")
340 exit(1)
341 desugar_jdk_json_dir = 'src/library_desugar/jdk11'
Søren Gjesseef195772021-03-11 16:04:42 +0100342
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200343 desugar_jdk_libs = None
344 if options.desugared_library:
345 if options.desugared_library != 'HEAD':
346 print("Only value supported for --desugared-library is 'HEAD'")
347 exit(1)
348 desugar_jdk_libs_dir = 'build/desugar_jdk_libs'
349 shutil.rmtree(desugar_jdk_libs_dir, ignore_errors=True)
350 os.makedirs(desugar_jdk_libs_dir)
351 print('Building desugared library.')
352 with utils.TempDir() as checkout_dir:
353 archive_desugar_jdk_libs.CloneDesugaredLibrary(
354 'google', checkout_dir, 'HEAD')
355 # Make sure bazel is extracted in third_party.
356 utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE)
357 utils.DownloadFromGoogleCloudStorage(utils.JAVA8_SHA_FILE)
358 utils.DownloadFromGoogleCloudStorage(utils.JAVA11_SHA_FILE)
359 (library_jar,
360 maven_zip) = archive_desugar_jdk_libs.BuildDesugaredLibrary(
361 checkout_dir, 'jdk11_legacy' if
362 options.desugared_library_configuration == 'jdk11' else 'jdk8')
363 desugar_jdk_libs = os.path.join(desugar_jdk_libs_dir,
364 os.path.basename(library_jar))
365 shutil.copyfile(library_jar, desugar_jdk_libs)
366 print('Desugared library for test in ' + desugar_jdk_libs)
Søren Gjesse4a45f9b2021-02-11 14:05:29 +0100367
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200368 gradle_args = []
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200369
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200370 if options.stacktrace or utils.is_bot():
371 gradle_args.append('--stacktrace')
Ian Zerny9a0e96a2021-04-28 12:35:49 +0200372
Ian Zerny27cb1cc2024-02-01 14:20:35 +0100373 if options.no_daemon or utils.is_bot():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200374 # Bots don't like dangling processes.
375 gradle_args.append('--no-daemon')
Rico Wind22707fc2019-03-15 13:19:57 +0100376
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200377 # Set all necessary Gradle properties and options first.
378 if options.shard_count:
379 assert options.shard_number
380 gradle_args.append('-Pshard_count=%s' % options.shard_count)
381 gradle_args.append('-Pshard_number=%s' % options.shard_number)
382 if options.verbose:
383 gradle_args.append('-Pprint_test_stdout')
384 if options.no_internal:
385 gradle_args.append('-Pno_internal')
386 if options.only_internal:
387 gradle_args.append('-Ponly_internal')
388 if options.all_tests:
389 gradle_args.append('-Pall_tests')
390 if options.slow_tests:
391 gradle_args.append('-Pslow_tests=1')
392 if options.tool:
393 gradle_args.append('-Ptool=%s' % options.tool)
394 if options.one_line_per_test:
395 gradle_args.append('-Pone_line_per_test')
396 if options.test_namespace:
397 gradle_args.append('-Ptest_namespace=%s' % options.test_namespace)
398 if options.disable_assertions:
399 gradle_args.append('-Pdisable_assertions')
400 if options.with_code_coverage:
401 gradle_args.append('-Pwith_code_coverage')
402 if options.print_full_stacktraces:
403 gradle_args.append('-Pprint_full_stacktraces')
404 if options.print_obfuscated_stacktraces:
405 gradle_args.append('-Pprint_obfuscated_stacktraces')
406 if options.kotlin_compiler_old:
407 gradle_args.append('-Pkotlin_compiler_old')
408 if options.kotlin_compiler_dev:
409 gradle_args.append('-Pkotlin_compiler_dev')
410 download_kotlin_dev.download_newest()
411 if os.name == 'nt':
412 gradle_args.append('-Pno_internal')
413 if options.test_dir:
414 gradle_args.append('-Ptest_dir=' + options.test_dir)
415 if not os.path.exists(options.test_dir):
416 os.makedirs(options.test_dir)
417 if options.command_cache_dir:
418 gradle_args.append('-Pcommand_cache_dir=' + options.command_cache_dir)
419 if not os.path.exists(options.command_cache_dir):
420 os.makedirs(options.command_cache_dir)
421 if options.command_cache_stats:
422 stats_dir = os.path.join(options.command_cache_dir, 'stats')
423 gradle_args.append('-Pcommand_cache_stats_dir=' + stats_dir)
424 if not os.path.exists(stats_dir):
425 os.makedirs(stats_dir)
426 # Clean out old stats files
427 for (_, _, file_names) in os.walk(stats_dir):
428 for f in file_names:
429 os.remove(os.path.join(stats_dir, f))
430 if options.java_home:
431 gradle_args.append('-Dorg.gradle.java.home=' + options.java_home)
432 if options.java_max_memory_size:
433 gradle_args.append('-Ptest_xmx=' + options.java_max_memory_size)
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200434 if options.generate_golden_files_to:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200435 gradle_args.append('-Pgenerate_golden_files_to=' +
436 options.generate_golden_files_to)
437 if not os.path.exists(options.generate_golden_files_to):
438 os.makedirs(options.generate_golden_files_to)
439 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
440 if options.use_golden_files_in:
441 gradle_args.append('-Puse_golden_files_in=' +
442 options.use_golden_files_in)
443 if not os.path.exists(options.use_golden_files_in):
444 os.makedirs(options.use_golden_files_in)
445 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
446 if options.r8lib_no_deps and options.no_r8lib:
447 print(
448 'Inconsistent arguments: both --no-r8lib and --r8lib-no-deps specified.'
449 )
450 exit(1)
451 if options.r8lib_no_deps:
452 gradle_args.append('-Pr8lib_no_deps')
453 elif not options.no_r8lib:
454 gradle_args.append('-Pr8lib')
455 if options.worktree:
456 gradle_args.append('-g=' +
457 os.path.join(utils.REPO_ROOT, ".gradle_user_home"))
458 gradle_args.append('--no-daemon')
459 if options.debug_agent:
460 gradle_args.append('--no-daemon')
461 if desugar_jdk_json_dir:
462 gradle_args.append('-Pdesugar_jdk_json_dir=' + desugar_jdk_json_dir)
463 if desugar_jdk_libs:
464 gradle_args.append('-Pdesugar_jdk_libs=' + desugar_jdk_libs)
465 if options.no_arttests:
466 gradle_args.append('-Pno_arttests=true')
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200467
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200468 if options.rerun:
469 testing_state.set_up_test_state(gradle_args, options.rerun,
470 options.testing_state_dir)
Mads Ager418d1ca2017-05-22 09:35:49 +0200471
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200472 # Enable completeness testing of ART profile rewriting.
473 gradle_args.append('-Part_profile_rewriting_completeness_check=true')
474
475 # Build an R8 with dependencies for bootstrapping tests before adding test sources.
476 gradle_args.append(utils.GRADLE_TASK_R8)
477 gradle_args.append(utils.GRADLE_TASK_CLEAN_TEST)
478 gradle_args.append(utils.GRADLE_TASK_TEST)
479 gradle_args.append('--stacktrace')
480 gradle_args.append('-Pprint_full_stacktraces')
481
482 if options.debug_agent:
483 gradle_args.append('--debug-jvm')
484 if options.fail_fast:
485 gradle_args.append('--fail-fast')
486 if options.failed:
487 args = compute_failed_tests(args)
488 if args is None:
489 return 1
490 if len(args) == 0:
491 print("No failing tests")
492 return 0
493 # Test filtering. Must always follow the 'test' task.
494 testFilterProperty = []
495 for testFilter in args:
496 gradle_args.append('--tests')
497 gradle_args.append(testFilter)
498 testFilterProperty.append(testFilter)
499 assert not ("|" in testFilter), "| is used as separating character"
500 if len(testFilterProperty) > 0:
501 gradle_args.append("-Ptestfilter=" + "|".join(testFilterProperty))
502 if options.with_code_coverage:
503 # Create Jacoco report after tests.
504 gradle_args.append('jacocoTestReport')
505
506 if options.use_golden_files_in:
507 sha1 = '%s' % utils.get_HEAD_sha1()
508 with utils.ChangedWorkingDirectory(options.use_golden_files_in):
509 utils.download_file_from_cloud_storage(
510 'gs://r8-test-results/golden-files/%s.tar.gz' % sha1,
511 '%s.tar.gz' % sha1)
512 utils.unpack_archive('%s.tar.gz' % sha1)
513
514 print_stacks_timeout = options.print_hanging_stacks
515 if (utils.is_bot() and not utils.IsWindows()) or print_stacks_timeout > -1:
516 timestamp_file = os.path.join(utils.BUILD, 'last_test_time')
517 if os.path.exists(timestamp_file):
518 os.remove(timestamp_file)
519 gradle_args.append('-Pupdate_test_timestamp=' + timestamp_file)
520 print_stacks_timeout = (print_stacks_timeout if print_stacks_timeout
521 != -1 else TIMEOUT_HANDLER_PERIOD)
522 if utils.is_python3():
523 threading.Thread(target=timeout_handler,
524 args=(timestamp_file, print_stacks_timeout),
525 daemon=True).start()
526 else:
527 thread.start_new_thread(timeout_handler, (
528 timestamp_file,
529 print_stacks_timeout,
530 ))
531 rotate_test_reports()
532
Rico Wind847b9282024-03-26 09:11:29 +0100533 if options.print_times:
534 gradle_args.append('-Pprint_times=true')
535
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200536 # Now run tests on selected runtime(s).
537 if options.runtimes:
538 if options.dex_vm != 'default':
539 print('Unexpected runtimes and dex_vm argument: ' + options.dex_vm)
540 sys.exit(1)
541 if options.runtimes == 'empty':
542 # Set runtimes with no content will configure no runtimes.
543 gradle_args.append('-Pruntimes=')
544 elif options.runtimes == 'all':
545 # An unset runtimes will configure all runtimes
546 pass
547 else:
548 prefixes = [
549 prefix.strip() for prefix in options.runtimes.split(':')
550 ]
551 runtimes = []
552 for prefix in prefixes:
553 matches = [rt for rt in VALID_RUNTIMES if rt.startswith(prefix)]
554 if len(matches) == 0:
555 print("Invalid runtime prefix '%s'." % prefix)
556 print("Must be just 'all', 'empty'," \
557 " or a prefix of %s" % ', '.join(VALID_RUNTIMES))
558 sys.exit(1)
559 runtimes.extend(matches)
560 gradle_args.append('-Pruntimes=%s' % ':'.join(runtimes))
561
562 return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
563 return archive_and_return(return_code, options)
564
565 # Legacy testing populates the runtimes based on dex_vm.
566 vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
567
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200568 for art_vm in vms_to_test:
569 vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
570 runtimes = ['dex-' + art_vm]
571 # Append the "none" runtime and default JVM if running the "default" DEX VM.
572 if art_vm == "default":
573 runtimes.extend(['jdk11', 'none'])
574 return_code = gradle.RunGradle(gradle_args + [
575 '-Pdex_vm=%s' % art_vm + vm_suffix,
576 '-Pruntimes=%s' % ':'.join(runtimes),
577 ],
578 throw_on_failure=False)
579 if options.generate_golden_files_to:
580 sha1 = '%s' % utils.get_HEAD_sha1()
581 with utils.ChangedWorkingDirectory(
582 options.generate_golden_files_to):
583 archive = utils.create_archive(sha1)
584 utils.upload_file_to_cloud_storage(
585 archive, 'gs://r8-test-results/golden-files/' + archive)
586
587 return archive_and_return(return_code, options)
588
589 return 0
590
Jinseong Jeon9749d172017-09-19 00:25:01 -0700591
Ian Zerny17561362019-05-27 15:16:26 +0200592def archive_and_return(return_code, options):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200593 if return_code != 0:
594 if options.archive_failures:
595 archive_failures(options)
596 if options.command_cache_stats:
597 stats_dir = os.path.join(options.command_cache_dir, 'stats')
598 cache_hit = 0
599 cache_miss = 0
600 cache_put = 0
601 for (_, _, file_names) in os.walk(stats_dir):
602 for f in file_names:
603 if f.endswith('CACHEHIT'):
604 cache_hit += os.stat(os.path.join(stats_dir, f)).st_size
605 if f.endswith('CACHEMISS'):
606 cache_miss += os.stat(os.path.join(stats_dir, f)).st_size
607 if f.endswith('CACHEPUT'):
608 cache_put += os.stat(os.path.join(stats_dir, f)).st_size
609 print('Command cache stats')
610 print(' Cache hits: ' + str(cache_hit))
611 print(' Cache miss: ' + str(cache_miss))
612 print(' Cache puts: ' + str(cache_put))
613 return return_code
614
Rico Windc58a20e2019-05-23 09:43:19 +0200615
Rico Windda6836e2018-12-07 12:32:03 +0100616def print_jstacks():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200617 processes = subprocess.check_output(['ps', 'aux']).decode('utf-8')
618 for l in processes.splitlines():
619 if 'art' in l or 'dalvik' in l:
620 print('Running art of dalvik process: \n%s' % l)
621 if 'java' in l and 'openjdk' in l:
622 print('Running jstack on process: \n%s' % l)
623 # Example line:
624 # ricow 184313 2.6 0.0 36839068 31808 ? Sl 09:53 0:00 /us..
625 columns = l.split()
626 pid = columns[1]
627 return_value = subprocess.call(['jstack', pid])
628 if return_value:
629 print('Could not jstack %s' % l)
630
Rico Windda6836e2018-12-07 12:32:03 +0100631
632def get_time_from_file(timestamp_file):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200633 if os.path.exists(timestamp_file):
634 timestamp = os.stat(timestamp_file).st_mtime
635 print('TIMEOUT HANDLER timestamp: %s' % (timestamp))
636 sys.stdout.flush()
637 return timestamp
638 else:
639 print('TIMEOUT HANDLER no timestamp file yet')
640 sys.stdout.flush()
641 return None
642
Rico Windda6836e2018-12-07 12:32:03 +0100643
Morten Krogh-Jespersendcb8d452020-07-09 15:07:50 +0200644def timeout_handler(timestamp_file, timeout_handler_period):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200645 last_timestamp = None
646 while True:
647 time.sleep(timeout_handler_period)
648 new_timestamp = get_time_from_file(timestamp_file)
649 if last_timestamp and new_timestamp == last_timestamp:
650 print_jstacks()
651 last_timestamp = new_timestamp
652
Rico Windda6836e2018-12-07 12:32:03 +0100653
Ian Zerny24398bc2019-02-22 11:59:18 +0100654def report_dir_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200655 if index == 0:
656 return REPORTS_PATH
657 return '%s%d' % (REPORTS_PATH, index)
658
Ian Zerny24398bc2019-02-22 11:59:18 +0100659
660def report_index_path(index):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200661 return os.path.join(report_dir_path(index), *REPORT_INDEX)
662
Ian Zerny24398bc2019-02-22 11:59:18 +0100663
664# Rotate test results so previous results are still accessible.
665def rotate_test_reports():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200666 if not os.path.exists(report_dir_path(0)):
667 return
668 i = 1
669 while i < NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
670 i += 1
671 if i == NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
672 shutil.rmtree(report_dir_path(i))
673 while i > 0:
674 shutil.move(report_dir_path(i - 1), report_dir_path(i))
675 i -= 1
676
Ian Zerny24398bc2019-02-22 11:59:18 +0100677
678def compute_failed_tests(args):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200679 if len(args) > 1:
680 print(
681 "Running with --failed can take an optional path to a report index (or report number)."
682 )
683 return None
684 report = report_index_path(0)
685 # If the default report does not exist, fall back to the previous report as it may be a failed
686 # gradle run which has already moved the report to report1, but did not produce a new report.
687 if not os.path.exists(report):
688 report1 = report_index_path(1)
689 if os.path.exists(report1):
690 report = report1
691 if len(args) == 1:
692 try:
693 # try to parse the arg as a report index.
694 index = int(args[0])
695 report = report_index_path(index)
696 except ValueError:
697 # if integer parsing failed assume it is a report file path.
698 report = args[0]
699 if not os.path.exists(report):
700 print("Can't re-run failing, no report at:", report)
701 return None
702 print("Reading failed tests in", report)
703 failing = set()
704 inFailedSection = False
705 for line in open(report):
706 l = line.strip()
707 if l == "<h2>Failed tests</h2>":
708 inFailedSection = True
709 elif l.startswith("<h2>"):
710 inFailedSection = False
711 prefix = '<a href="classes/'
712 if inFailedSection and l.startswith(prefix):
713 href = l[len(prefix):l.index('">')]
714 # Ignore enties ending with .html which are test classes, not test methods.
715 if not href.endswith('.html'):
716 # Remove the .html and anchor separateor, also, a classMethod test is the static
717 # setup failing so rerun the full class of tests.
718 test = href.replace('.html', '').replace('#', '.').replace(
719 '.classMethod', '')
720 failing.add(test)
721 return list(failing)
722
723
Mads Ager418d1ca2017-05-22 09:35:49 +0200724if __name__ == '__main__':
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200725 return_code = Main()
726 if return_code != 0:
727 notify.notify("Tests failed.")
728 else:
729 notify.notify("Tests passed.")
730 sys.exit(return_code)