blob: 2815834d3ed4be82e4ae2dd27b0243cd1d7f9c73 [file] [log] [blame]
Mads Ager418d1ca2017-05-22 09:35:49 +02001#!/usr/bin/env python
2# 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
Mads Ager418d1ca2017-05-22 09:35:49 +020010import optparse
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 thread
16import time
Rico Wind06487ac2018-12-10 09:09:19 +010017import uuid
Ian Zerny5fffb0a2019-02-11 13:54:22 +010018
19import gradle
Stephan Herhutd24b1b72017-08-24 15:09:36 +020020import notify
Ian Zerny5fffb0a2019-02-11 13:54:22 +010021import utils
Jean-Marie Henaffce162f32017-10-04 10:39:27 +020022
Søren Gjessefe7c0112018-12-03 12:33:12 +010023ALL_ART_VMS = [
24 "default",
25 "9.0.0",
26 "8.1.0",
27 "7.0.0",
28 "6.0.1",
29 "5.1.1",
30 "4.4.4",
31 "4.0.4"]
Mads Ager418d1ca2017-05-22 09:35:49 +020032
Rico Windda6836e2018-12-07 12:32:03 +010033# How often do we check for progress on the bots:
34# Should be long enough that a normal run would always have med progress
35# Should be short enough that we ensure that two calls are close enough
36# to happen before bot times out.
37# A false positiv, i.e., printing the stacks of non hanging processes
38# is not a problem, no harm done except some logging in the stdout.
39TIMEOUT_HANDLER_PERIOD = 60 * 18
40
Rico Wind06487ac2018-12-10 09:09:19 +010041BUCKET = 'r8-test-results'
42
Ian Zerny24398bc2019-02-22 11:59:18 +010043NUMBER_OF_TEST_REPORTS = 5
44REPORTS_PATH = os.path.join(utils.BUILD, 'reports')
45REPORT_INDEX = ['tests', 'test', 'index.html']
46
Mads Ager418d1ca2017-05-22 09:35:49 +020047def ParseOptions():
48 result = optparse.OptionParser()
Søren Gjesse77527982018-10-05 12:58:49 +020049 result.add_option('--no-internal', '--no_internal',
Mads Ager418d1ca2017-05-22 09:35:49 +020050 help='Do not run Google internal tests.',
51 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020052 result.add_option('--archive-failures', '--archive_failures',
Rico Winda94f01c2017-06-27 10:32:34 +020053 help='Upload test results to cloud storage on failure.',
54 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020055 result.add_option('--only-internal', '--only_internal',
Mads Ager418d1ca2017-05-22 09:35:49 +020056 help='Only run Google internal tests.',
57 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020058 result.add_option('--all-tests', '--all_tests',
Mads Ager418d1ca2017-05-22 09:35:49 +020059 help='Run tests in all configurations.',
60 default=False, action='store_true')
61 result.add_option('-v', '--verbose',
62 help='Print test stdout to, well, stdout.',
63 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020064 result.add_option('--dex-vm', '--dex_vm',
Mads Ager418d1ca2017-05-22 09:35:49 +020065 help='The android version of the vm to use. "all" will run the tests on '
66 'all art vm versions (stopping after first failed execution)',
67 default="default",
68 choices=ALL_ART_VMS + ["all"])
Søren Gjesse77527982018-10-05 12:58:49 +020069 result.add_option('--dex-vm-kind', '--dex_vm_kind',
Jean-Marie Henaffce162f32017-10-04 10:39:27 +020070 help='Whether to use host or target version of runtime',
71 default="host",
72 nargs=1,
73 choices=["host", "target"])
Søren Gjesse77527982018-10-05 12:58:49 +020074 result.add_option('--one-line-per-test', '--one_line_per_test',
Mads Ager418d1ca2017-05-22 09:35:49 +020075 help='Print a line before a tests starts and after it ends to stdout.',
76 default=False, action='store_true')
77 result.add_option('--tool',
Tamas Kenezcfb2c052018-10-12 11:03:57 +020078 help='Tool to run ART tests with: "r8" (default) or "d8" or "r8cf"'
79 ' (r8 w/CF-backend). Ignored if "--all_tests" enabled.',
80 default=None, choices=["r8", "d8", "r8cf"])
Mads Ager418d1ca2017-05-22 09:35:49 +020081 result.add_option('--jctf',
Tamas Kenezcfb2c052018-10-12 11:03:57 +020082 help='Run JCTF tests with: "r8" (default) or "d8" or "r8cf".',
Mads Ager418d1ca2017-05-22 09:35:49 +020083 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020084 result.add_option('--only-jctf', '--only_jctf',
Tamas Kenezcfb2c052018-10-12 11:03:57 +020085 help='Run only JCTF tests with: "r8" (default) or "d8" or "r8cf".',
Mads Ager418d1ca2017-05-22 09:35:49 +020086 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020087 result.add_option('--jctf-compile-only', '--jctf_compile_only',
Mads Ager418d1ca2017-05-22 09:35:49 +020088 help="Don't run, only compile JCTF tests.",
89 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020090 result.add_option('--disable-assertions', '--disable_assertions',
Tamas Kenezb77b7d82017-08-17 14:05:16 +020091 help='Disable assertions when running tests.',
Søren Gjesseaf1c5e22017-06-15 12:24:03 +020092 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020093 result.add_option('--with-code-coverage', '--with_code_coverage',
Tamas Kenezb77b7d82017-08-17 14:05:16 +020094 help='Enable code coverage with Jacoco.',
Sebastien Hertze2687b62017-07-25 11:16:04 +020095 default=False, action='store_true')
Søren Gjesse77527982018-10-05 12:58:49 +020096 result.add_option('--test-dir', '--test_dir',
Tamas Kenezb77b7d82017-08-17 14:05:16 +020097 help='Use a custom directory for the test artifacts instead of a'
98 ' temporary (which is automatically removed after the test).'
99 ' Note that the directory will not be cleared before the test.')
Søren Gjesse77527982018-10-05 12:58:49 +0200100 result.add_option('--java-home', '--java_home',
Mikaël Peltier5c0a3232017-10-18 09:14:40 +0200101 help='Use a custom java version to run tests.')
Ian Zerny5fffb0a2019-02-11 13:54:22 +0100102 result.add_option('--java-max-memory-size', '--java_max_memory_size',
103 help='Use a custom max memory size for the gradle java instance, eg, 4g')
Rico Wind8e2f7e42019-02-21 10:13:21 +0100104 result.add_option('--shard-count', '--shard_count',
105 help='We are running this many shards.')
106 result.add_option('--shard-number', '--shard_number',
107 help='We are running this shard.')
Søren Gjesse77527982018-10-05 12:58:49 +0200108 result.add_option('--generate-golden-files-to', '--generate_golden_files_to',
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200109 help='Store dex files produced by tests in the specified directory.'
110 ' It is aimed to be read on platforms with no host runtime available'
111 ' for comparison.')
Søren Gjesse77527982018-10-05 12:58:49 +0200112 result.add_option('--use-golden-files-in', '--use_golden_files_in',
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200113 help='Download golden files hierarchy for this commit in the specified'
114 ' location and use them instead of executing on host runtime.')
Søren Gjesse1956bdb2019-02-19 08:37:52 +0100115 result.add_option('--no-r8lib', '--no_r8lib',
116 default=False, action='store_true',
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100117 help='Run the tests on R8 full with relocated dependencies.')
Søren Gjesse1956bdb2019-02-19 08:37:52 +0100118 result.add_option('--r8lib-no-deps', '--r8lib_no_deps',
119 default=False, action='store_true',
Morten Krogh-Jespersen807b15f2018-12-17 14:24:22 +0100120 help='Run the tests on r8lib without relocated dependencies.')
Ian Zerny24398bc2019-02-22 11:59:18 +0100121 result.add_option('--failed',
122 default=False, action='store_true',
123 help='Run the tests that failed last execution.')
124 result.add_option('--fail-fast', '--fail_fast',
125 default=False, action='store_true',
126 help='Stop on first failure. Passes --fail-fast to gradle test runner.')
Mads Ager418d1ca2017-05-22 09:35:49 +0200127 return result.parse_args()
128
Rico Wind06487ac2018-12-10 09:09:19 +0100129def archive_failures():
130 upload_dir = os.path.join(utils.REPO_ROOT, 'build', 'reports', 'tests')
131 u_dir = uuid.uuid4()
132 destination = 'gs://%s/%s' % (BUCKET, u_dir)
133 utils.upload_dir_to_cloud_storage(upload_dir, destination, is_html=True)
134 url = 'http://storage.googleapis.com/%s/%s/test/index.html' % (BUCKET, u_dir)
135 print 'Test results available at: %s' % url
136 print '@@@STEP_LINK@Test failures@%s@@@' % url
137
Mads Ager418d1ca2017-05-22 09:35:49 +0200138def Main():
139 (options, args) = ParseOptions()
Rico Windda6836e2018-12-07 12:32:03 +0100140 if utils.is_bot():
Rico Wind22707fc2019-03-15 13:19:57 +0100141 gradle.RunGradle(['--no-daemon', 'clean'])
Sebastien Hertze2687b62017-07-25 11:16:04 +0200142
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200143 gradle_args = ['--stacktrace']
Rico Wind22707fc2019-03-15 13:19:57 +0100144 if utils.is_bot():
145 # Bots don't like dangling processes
146 gradle_args.append('--no-daemon')
147
Sebastien Hertze2687b62017-07-25 11:16:04 +0200148 # Set all necessary Gradle properties and options first.
Rico Wind8e2f7e42019-02-21 10:13:21 +0100149 if options.shard_count:
150 assert options.shard_number
151 gradle_args.append('-Pshard_count=%s' % options.shard_count)
152 gradle_args.append('-Pshard_number=%s' % options.shard_number)
Mads Ager418d1ca2017-05-22 09:35:49 +0200153 if options.verbose:
154 gradle_args.append('-Pprint_test_stdout')
155 if options.no_internal:
156 gradle_args.append('-Pno_internal')
157 if options.only_internal:
158 gradle_args.append('-Ponly_internal')
159 if options.all_tests:
160 gradle_args.append('-Pall_tests')
161 if options.tool:
162 gradle_args.append('-Ptool=%s' % options.tool)
163 if options.one_line_per_test:
164 gradle_args.append('-Pone_line_per_test')
165 if options.jctf:
166 gradle_args.append('-Pjctf')
167 if options.only_jctf:
168 gradle_args.append('-Ponly_jctf')
169 if options.jctf_compile_only:
170 gradle_args.append('-Pjctf_compile_only')
Søren Gjesseaf1c5e22017-06-15 12:24:03 +0200171 if options.disable_assertions:
172 gradle_args.append('-Pdisable_assertions')
Sebastien Hertze2687b62017-07-25 11:16:04 +0200173 if options.with_code_coverage:
174 gradle_args.append('-Pwith_code_coverage')
Jean-Marie Henaff7b424e92017-06-15 11:02:56 +0200175 if os.name == 'nt':
176 # temporary hack
177 gradle_args.append('-Pno_internal')
178 gradle_args.append('-x')
179 gradle_args.append('createJctfTests')
180 gradle_args.append('-x')
181 gradle_args.append('jctfCommonJar')
182 gradle_args.append('-x')
183 gradle_args.append('jctfTestsClasses')
Tamas Kenezb77b7d82017-08-17 14:05:16 +0200184 if options.test_dir:
185 gradle_args.append('-Ptest_dir=' + options.test_dir)
186 if not os.path.exists(options.test_dir):
187 os.makedirs(options.test_dir)
Mikaël Peltier5c0a3232017-10-18 09:14:40 +0200188 if options.java_home:
189 gradle_args.append('-Dorg.gradle.java.home=' + options.java_home)
Ian Zerny5fffb0a2019-02-11 13:54:22 +0100190 if options.java_max_memory_size:
191 gradle_args.append('-Dorg.gradle.jvmargs=-Xmx' + options.java_max_memory_size)
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200192 if options.generate_golden_files_to:
193 gradle_args.append('-Pgenerate_golden_files_to=' + options.generate_golden_files_to)
194 if not os.path.exists(options.generate_golden_files_to):
195 os.makedirs(options.generate_golden_files_to)
196 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
197 if options.use_golden_files_in:
198 gradle_args.append('-Puse_golden_files_in=' + options.use_golden_files_in)
199 if not os.path.exists(options.use_golden_files_in):
200 os.makedirs(options.use_golden_files_in)
201 gradle_args.append('-PHEAD_sha1=' + utils.get_HEAD_sha1())
Morten Krogh-Jespersen432dd912019-01-14 13:26:35 +0100202 if (not options.no_r8lib) and options.r8lib_no_deps:
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100203 print('Cannot run tests on r8lib with and without deps. R8lib is now default target.')
Morten Krogh-Jespersen807b15f2018-12-17 14:24:22 +0100204 exit(1)
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100205 if not options.no_r8lib:
Morten Krogh-Jespersen807b15f2018-12-17 14:24:22 +0100206 gradle_args.append('-Pr8lib')
Morten Krogh-Jespersen54f196e2019-01-14 16:10:08 +0100207 # Force gradle to build a version of r8lib without dependencies for
208 # BootstrapCurrentEqualityTest.
209 gradle_args.append('R8LibNoDeps')
Morten Krogh-Jespersen807b15f2018-12-17 14:24:22 +0100210 if options.r8lib_no_deps:
211 gradle_args.append('-Pr8lib_no_deps')
212
Morten Krogh-Jespersen54f196e2019-01-14 16:10:08 +0100213 # Build an R8 with dependencies for bootstrapping tests before adding test sources.
214 gradle_args.append('r8WithRelocatedDeps')
215
Sebastien Hertze2687b62017-07-25 11:16:04 +0200216 # Add Gradle tasks
217 gradle_args.append('cleanTest')
218 gradle_args.append('test')
Ian Zerny24398bc2019-02-22 11:59:18 +0100219 if options.fail_fast:
220 gradle_args.append('--fail-fast')
221 if options.failed:
222 args = compute_failed_tests(args)
223 if args is None:
224 return 1
225 if len(args) == 0:
226 print "No failing tests"
227 return 0
Sebastien Hertz0f4e7fb2017-10-02 11:33:45 +0200228 # Test filtering. Must always follow the 'test' task.
229 for testFilter in args:
Sebastien Hertze2687b62017-07-25 11:16:04 +0200230 gradle_args.append('--tests')
Sebastien Hertz0f4e7fb2017-10-02 11:33:45 +0200231 gradle_args.append(testFilter)
Sebastien Hertze2687b62017-07-25 11:16:04 +0200232 if options.with_code_coverage:
233 # Create Jacoco report after tests.
234 gradle_args.append('jacocoTestReport')
235
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200236 if options.use_golden_files_in:
237 sha1 = '%s' % utils.get_HEAD_sha1()
238 with utils.ChangedWorkingDirectory(options.use_golden_files_in):
239 utils.download_file_from_cloud_storage(
240 'gs://r8-test-results/golden-files/%s.tar.gz' % sha1,
241 '%s.tar.gz' % sha1)
242 utils.unpack_archive('%s.tar.gz' % sha1)
243
Rico Windda6836e2018-12-07 12:32:03 +0100244 if utils.is_bot() and not utils.IsWindows():
245 timestamp_file = os.path.join(utils.BUILD, 'last_test_time')
246 if os.path.exists(timestamp_file):
247 os.remove(timestamp_file)
248 gradle_args.append('-Pupdate_test_timestamp=' + timestamp_file)
249 thread.start_new_thread(timeout_handler, (timestamp_file,))
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200250
Ian Zerny24398bc2019-02-22 11:59:18 +0100251 rotate_test_reports()
252
Ian Zerny324d7612019-03-20 10:52:28 +0100253 if options.only_jctf:
254 # Note: not setting -Pruntimes will run with all available runtimes.
255 return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
256 return 0
257
Sebastien Hertze2687b62017-07-25 11:16:04 +0200258 # Now run tests on selected runtime(s).
Mads Ager418d1ca2017-05-22 09:35:49 +0200259 vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
Rico Wind124b2712019-02-28 13:49:25 +0100260
Mads Ager418d1ca2017-05-22 09:35:49 +0200261 for art_vm in vms_to_test:
Ian Zerny4dfd5a52019-03-12 07:56:11 +0100262 vm_suffix = "_" + options.dex_vm_kind if art_vm != "default" else ""
Ian Zerny324d7612019-03-20 10:52:28 +0100263 runtimes = ['dex-' + art_vm]
264 # Only append the "none" runtime and JVMs if running on the "default" DEX VM.
265 if art_vm == "default":
clementbera1757ec02019-04-27 12:48:37 +0200266 runtimes.extend(['jdk8', 'jdk9', 'jdk11', 'none'])
Ian Zerny4dfd5a52019-03-12 07:56:11 +0100267 return_code = gradle.RunGradle(
268 gradle_args + [
269 '-Pdex_vm=%s' % art_vm + vm_suffix,
Ian Zerny324d7612019-03-20 10:52:28 +0100270 '-Pruntimes=%s' % ':'.join(runtimes),
271 ],
Ian Zerny4dfd5a52019-03-12 07:56:11 +0100272 throw_on_failure=False)
Jean-Marie Henaff7a64eec2018-05-31 15:30:35 +0200273 if options.generate_golden_files_to:
274 sha1 = '%s' % utils.get_HEAD_sha1()
275 with utils.ChangedWorkingDirectory(options.generate_golden_files_to):
276 archive = utils.create_archive(sha1)
277 utils.upload_file_to_cloud_storage(archive,
278 'gs://r8-test-results/golden-files/' + archive)
279
Rico Winda94f01c2017-06-27 10:32:34 +0200280 if return_code != 0:
Rico Winddce9c872017-08-14 14:49:04 +0200281 if options.archive_failures and os.name != 'nt':
Rico Wind06487ac2018-12-10 09:09:19 +0100282 archive_failures()
Rico Winda94f01c2017-06-27 10:32:34 +0200283 return return_code
Mads Ager418d1ca2017-05-22 09:35:49 +0200284
Jinseong Jeon9749d172017-09-19 00:25:01 -0700285 return 0
286
Rico Windda6836e2018-12-07 12:32:03 +0100287
288def print_jstacks():
289 processes = subprocess.check_output(['ps', 'aux'])
290 for l in processes.splitlines():
291 if 'java' in l and 'openjdk' in l:
292 # Example line:
293 # ricow 184313 2.6 0.0 36839068 31808 ? Sl 09:53 0:00 /us..
294 columns = l.split()
295 pid = columns[1]
296 return_value = subprocess.call(['jstack', pid])
297 if return_value:
298 print('Could not jstack %s' % l)
Rico Windda6836e2018-12-07 12:32:03 +0100299
300def get_time_from_file(timestamp_file):
301 if os.path.exists(timestamp_file):
302 timestamp = os.stat(timestamp_file).st_mtime
303 print('TIMEOUT HANDLER timestamp: %s' % (timestamp))
Rico Windda6836e2018-12-07 12:32:03 +0100304 sys.stdout.flush()
305 return timestamp
306 else:
307 print('TIMEOUT HANDLER no timestamp file yet')
Rico Windda6836e2018-12-07 12:32:03 +0100308 sys.stdout.flush()
309 return None
310
311def timeout_handler(timestamp_file):
312 last_timestamp = None
313 while True:
314 time.sleep(TIMEOUT_HANDLER_PERIOD)
315 new_timestamp = get_time_from_file(timestamp_file)
316 if last_timestamp and new_timestamp == last_timestamp:
317 print_jstacks()
318 last_timestamp = new_timestamp
319
Ian Zerny24398bc2019-02-22 11:59:18 +0100320def report_dir_path(index):
321 if index is 0:
322 return REPORTS_PATH
323 return '%s%d' % (REPORTS_PATH, index)
324
325def report_index_path(index):
326 return os.path.join(report_dir_path(index), *REPORT_INDEX)
327
328# Rotate test results so previous results are still accessible.
329def rotate_test_reports():
330 if not os.path.exists(report_dir_path(0)):
331 return
332 i = 1
333 while i < NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
334 i += 1
335 if i == NUMBER_OF_TEST_REPORTS and os.path.exists(report_dir_path(i)):
336 shutil.rmtree(report_dir_path(i))
337 while i > 0:
338 shutil.move(report_dir_path(i - 1), report_dir_path(i))
339 i -= 1
340
341def compute_failed_tests(args):
342 if len(args) > 1:
343 print "Running with --failed can take an optional path to a report index (or report number)."
344 return None
345 report = report_index_path(0)
346 # If the default report does not exist, fall back to the previous report as it may be a failed
347 # gradle run which has already moved the report to report1, but did not produce a new report.
348 if not os.path.exists(report):
349 report1 = report_index_path(1)
350 if os.path.exists(report1):
351 report = report1
352 if len(args) == 1:
353 try:
354 # try to parse the arg as a report index.
355 index = int(args[0])
356 report = report_index_path(index)
357 except ValueError:
358 # if integer parsing failed assume it is a report file path.
359 report = args[0]
360 if not os.path.exists(report):
361 print "Can't re-run failing, no report at:", report
362 return None
363 print "Reading failed tests in", report
364 failing = set()
365 inFailedSection = False
366 for line in file(report):
367 l = line.strip()
368 if l == "<h2>Failed tests</h2>":
369 inFailedSection = True
370 elif l.startswith("<h2>"):
371 inFailedSection = False
372 prefix = '<a href="classes/'
373 if inFailedSection and l.startswith(prefix):
374 href = l[len(prefix):l.index('">')]
375 # Ignore enties ending with .html which are test classes, not test methods.
376 if not href.endswith('.html'):
377 # Remove the .html and anchor separateor, also, a classMethod test is the static
378 # setup failing so rerun the full class of tests.
379 test = href.replace('.html','').replace('#', '.').replace('.classMethod', '')
380 failing.add(test)
381 return list(failing)
382
Mads Ager418d1ca2017-05-22 09:35:49 +0200383if __name__ == '__main__':
Stephan Herhutd24b1b72017-08-24 15:09:36 +0200384 return_code = Main()
385 if return_code != 0:
386 notify.notify("Tests failed.")
387 else:
388 notify.notify("Tests passed.")
389 sys.exit(return_code)