blob: c22b0be9f4cf8fcde6602264cc3b2e9c0326865c [file] [log] [blame]
Shubham Ajmera65adb8b2017-02-06 16:04:25 +00001#!/usr/bin/env python
2#
3# Copyright 2017, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""ART Run-Test TestRunner
18
19The testrunner runs the ART run-tests by simply invoking the script.
20It fetches the list of eligible tests from art/test directory, and list of
21disabled tests from art/test/knownfailures.json. It runs the tests by
22invoking art/test/run-test script and checks the exit value to decide if the
23test passed or failed.
24
25Before invoking the script, first build all the tests dependencies.
26There are two major build targets for building target and host tests
27dependencies:
281) test-art-host-run-test
292) test-art-target-run-test
30
31There are various options to invoke the script which are:
32-t: Either the test name as in art/test or the test name including the variant
33 information. Eg, "-t 001-HelloWorld",
34 "-t test-art-host-run-test-debug-prebuild-optimizing-relocate-ntrace-cms-checkjni-picimage-npictest-ndebuggable-001-HelloWorld32"
35-j: Number of thread workers to be used. Eg - "-j64"
36--dry-run: Instead of running the test name, just print its name.
37--verbose
38-b / --build-dependencies: to build the dependencies before running the test
39
40To specify any specific variants for the test, use --<<variant-name>>.
41For eg, for compiler type as optimizing, use --optimizing.
42
43
44In the end, the script will print the failed and skipped tests if any.
45
46"""
Alex Light7a1ccf82017-02-21 09:52:34 -080047import argparse
Shubham Ajmera65adb8b2017-02-06 16:04:25 +000048import fnmatch
49import itertools
50import json
Shubham Ajmera65adb8b2017-02-06 16:04:25 +000051import os
52import re
53import subprocess
54import sys
55import threading
56import time
57
58import env
59
60TARGET_TYPES = set()
61RUN_TYPES = set()
62PREBUILD_TYPES = set()
63COMPILER_TYPES = set()
64RELOCATE_TYPES = set()
65TRACE_TYPES = set()
66GC_TYPES = set()
67JNI_TYPES = set()
68IMAGE_TYPES = set()
69PICTEST_TYPES = set()
70DEBUGGABLE_TYPES = set()
71ADDRESS_SIZES = set()
72OPTIMIZING_COMPILER_TYPES = set()
73ADDRESS_SIZES_TARGET = {'host': set(), 'target': set()}
74
75# DISABLED_TEST_CONTAINER holds information about the disabled tests. It is a map
76# that has key as the test name (like 001-HelloWorld), and value as set of
77# variants that the test is disabled for.
78DISABLED_TEST_CONTAINER = {}
79
80# The Dict contains the list of all possible variants for a given type. For example,
81# for key TARGET, the value would be target and host. The list is used to parse
82# the test name given as the argument to run.
83VARIANT_TYPE_DICT = {}
84
85# The set contains all the variants of each time.
86TOTAL_VARIANTS_SET = set()
87
88# The colors are used in the output. When a test passes, COLOR_PASS is used,
89# and so on.
90COLOR_ERROR = '\033[91m'
91COLOR_PASS = '\033[92m'
92COLOR_SKIP = '\033[93m'
93COLOR_NORMAL = '\033[0m'
94
95# The mutex object is used by the threads for exclusive access of test_count
96# to make any changes in its value.
97test_count_mutex = threading.Lock()
Shubham Ajmera14d340c2017-02-15 18:49:10 +000098
Shubham Ajmera65adb8b2017-02-06 16:04:25 +000099# The set contains the list of all the possible run tests that are in art/test
100# directory.
101RUN_TEST_SET = set()
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000102
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000103# The semaphore object is used by the testrunner to limit the number of
104# threads to the user requested concurrency value.
105semaphore = threading.Semaphore(1)
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000106
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000107# The mutex object is used to provide exclusive access to a thread to print
108# its output.
109print_mutex = threading.Lock()
110failed_tests = []
111skipped_tests = []
112
113# Flags
114n_thread = 1
115test_count = 0
116total_test_count = 0
117verbose = False
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000118dry_run = False
119build = False
120gdb = False
121gdb_arg = ''
122stop_testrunner = False
123
124def gather_test_info():
125 """The method gathers test information about the test to be run which includes
126 generating the list of total tests from the art/test directory and the list
127 of disabled test. It also maps various variants to types.
128 """
129 global TOTAL_VARIANTS_SET
130 global DISABLED_TEST_CONTAINER
131 # TODO: Avoid duplication of the variant names in different lists.
132 VARIANT_TYPE_DICT['pictest'] = {'pictest', 'npictest'}
133 VARIANT_TYPE_DICT['run'] = {'ndebug', 'debug'}
134 VARIANT_TYPE_DICT['target'] = {'target', 'host'}
135 VARIANT_TYPE_DICT['trace'] = {'trace', 'ntrace', 'stream'}
Richard Uhlerbb00f812017-02-16 14:21:10 +0000136 VARIANT_TYPE_DICT['image'] = {'picimage', 'no-image', 'multipicimage'}
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000137 VARIANT_TYPE_DICT['debuggable'] = {'ndebuggable', 'debuggable'}
138 VARIANT_TYPE_DICT['gc'] = {'gcstress', 'gcverify', 'cms'}
139 VARIANT_TYPE_DICT['prebuild'] = {'no-prebuild', 'no-dex2oat', 'prebuild'}
140 VARIANT_TYPE_DICT['relocate'] = {'relocate-npatchoat', 'relocate', 'no-relocate'}
141 VARIANT_TYPE_DICT['jni'] = {'jni', 'forcecopy', 'checkjni'}
142 VARIANT_TYPE_DICT['address_sizes'] = {'64', '32'}
143 VARIANT_TYPE_DICT['compiler'] = {'interp-ac', 'interpreter', 'jit', 'optimizing',
144 'regalloc_gc'}
145
146 for v_type in VARIANT_TYPE_DICT:
147 TOTAL_VARIANTS_SET = TOTAL_VARIANTS_SET.union(VARIANT_TYPE_DICT.get(v_type))
148
149 test_dir = env.ANDROID_BUILD_TOP + '/art/test'
150 for f in os.listdir(test_dir):
151 if fnmatch.fnmatch(f, '[0-9]*'):
152 RUN_TEST_SET.add(f)
153 DISABLED_TEST_CONTAINER = get_disabled_test_info()
154
155
156def setup_test_env():
157 """The method sets default value for the various variants of the tests if they
158 are already not set.
159 """
160 if env.ART_TEST_BISECTION:
161 env.ART_TEST_RUN_TEST_NO_PREBUILD = True
162 env.ART_TEST_RUN_TEST_PREBUILD = False
163 # Bisection search writes to standard output.
164 env.ART_TEST_QUIET = False
165
166 if not TARGET_TYPES:
167 TARGET_TYPES.add('host')
168 TARGET_TYPES.add('target')
169
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000170 if env.ART_TEST_RUN_TEST_NO_PREBUILD:
171 PREBUILD_TYPES.add('no-prebuild')
172 if env.ART_TEST_RUN_TEST_NO_DEX2OAT:
173 PREBUILD_TYPES.add('no-dex2oat')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000174 if env.ART_TEST_RUN_TEST_PREBUILD or not PREBUILD_TYPES: # Default
175 PREBUILD_TYPES.add('prebuild')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000176
177 if env.ART_TEST_INTERPRETER_ACCESS_CHECKS:
178 COMPILER_TYPES.add('interp-ac')
179 if env.ART_TEST_INTERPRETER:
180 COMPILER_TYPES.add('interpreter')
181 if env.ART_TEST_JIT:
182 COMPILER_TYPES.add('jit')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000183 if env.ART_TEST_OPTIMIZING_GRAPH_COLOR:
184 COMPILER_TYPES.add('regalloc_gc')
185 OPTIMIZING_COMPILER_TYPES.add('regalloc_gc')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000186 if env.ART_TEST_OPTIMIZING or not COMPILER_TYPES: # Default
187 COMPILER_TYPES.add('optimizing')
188 OPTIMIZING_COMPILER_TYPES.add('optimizing')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000189
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000190 if env.ART_TEST_RUN_TEST_RELOCATE:
191 RELOCATE_TYPES.add('relocate')
192 if env.ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT:
193 RELOCATE_TYPES.add('relocate-npatchoat')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000194 if not RELOCATE_TYPES: # Default
195 RELOCATE_TYPES.add('no-relocate')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000196
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000197 if env.ART_TEST_TRACE:
198 TRACE_TYPES.add('trace')
199 if env.ART_TEST_TRACE_STREAM:
200 TRACE_TYPES.add('stream')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000201 if not TRACE_TYPES: # Default
202 TRACE_TYPES.add('ntrace')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000203
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000204 if env.ART_TEST_GC_STRESS:
205 GC_TYPES.add('gcstress')
206 if env.ART_TEST_GC_VERIFY:
207 GC_TYPES.add('gcverify')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000208 if not GC_TYPES: # Default
209 GC_TYPES.add('cms')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000210
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000211 if env.ART_TEST_JNI_FORCECOPY:
212 JNI_TYPES.add('forcecopy')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000213 if not JNI_TYPES: # Default
214 JNI_TYPES.add('checkjni')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000215
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000216 if env.ART_TEST_RUN_TEST_NO_IMAGE:
217 IMAGE_TYPES.add('no-image')
218 if env.ART_TEST_RUN_TEST_MULTI_IMAGE:
219 IMAGE_TYPES.add('multipicimage')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000220 if env.ART_TEST_RUN_TEST_IMAGE or not IMAGE_TYPES: # Default
221 IMAGE_TYPES.add('picimage')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000222
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000223 if env.ART_TEST_PIC_TEST:
224 PICTEST_TYPES.add('pictest')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000225 if not PICTEST_TYPES: # Default
226 PICTEST_TYPES.add('npictest')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000227
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000228 if env.ART_TEST_RUN_TEST_NDEBUG:
229 RUN_TYPES.add('ndebug')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000230 if env.ART_TEST_RUN_TEST_DEBUG or not RUN_TYPES: # Default
231 RUN_TYPES.add('debug')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000232
233 if env.ART_TEST_RUN_TEST_DEBUGGABLE:
234 DEBUGGABLE_TYPES.add('debuggable')
Shubham Ajmera4b8c53d2017-02-15 16:38:16 +0000235 if not DEBUGGABLE_TYPES: # Default
236 DEBUGGABLE_TYPES.add('ndebuggable')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000237
238 if not ADDRESS_SIZES:
239 ADDRESS_SIZES_TARGET['target'].add(env.ART_PHONY_TEST_TARGET_SUFFIX)
240 ADDRESS_SIZES_TARGET['host'].add(env.ART_PHONY_TEST_HOST_SUFFIX)
241 if env.ART_TEST_RUN_TEST_2ND_ARCH:
242 ADDRESS_SIZES_TARGET['host'].add(env._2ND_ART_PHONY_TEST_HOST_SUFFIX)
243 ADDRESS_SIZES_TARGET['target'].add(env._2ND_ART_PHONY_TEST_TARGET_SUFFIX)
244 else:
245 ADDRESS_SIZES_TARGET['host'] = ADDRESS_SIZES_TARGET['host'].union(ADDRESS_SIZES)
246 ADDRESS_SIZES_TARGET['target'] = ADDRESS_SIZES_TARGET['target'].union(ADDRESS_SIZES)
247
248 global semaphore
249 semaphore = threading.Semaphore(n_thread)
250
251
252def run_tests(tests):
253 """Creates thread workers to run the tests.
254
255 The method generates command and thread worker to run the tests. Depending on
256 the user input for the number of threads to be used, the method uses a
257 semaphore object to keep a count in control for the thread workers. When a new
258 worker is created, it acquires the semaphore object, and when the number of
259 workers reaches the maximum allowed concurrency, the method wait for an
260 existing thread worker to release the semaphore object. Worker releases the
261 semaphore object when they finish printing the output.
262
263 Args:
264 tests: The set of tests to be run.
265 """
266 options_all = ''
267 global total_test_count
268 total_test_count = len(tests)
269 total_test_count *= len(RUN_TYPES)
270 total_test_count *= len(PREBUILD_TYPES)
271 total_test_count *= len(RELOCATE_TYPES)
272 total_test_count *= len(TRACE_TYPES)
273 total_test_count *= len(GC_TYPES)
274 total_test_count *= len(JNI_TYPES)
275 total_test_count *= len(IMAGE_TYPES)
276 total_test_count *= len(PICTEST_TYPES)
277 total_test_count *= len(DEBUGGABLE_TYPES)
278 total_test_count *= len(COMPILER_TYPES)
279 target_address_combinations = 0
280 for target in TARGET_TYPES:
281 for address_size in ADDRESS_SIZES_TARGET[target]:
282 target_address_combinations += 1
283 total_test_count *= target_address_combinations
284
285 if env.ART_TEST_WITH_STRACE:
286 options_all += ' --strace'
287
288 if env.ART_TEST_RUN_TEST_ALWAYS_CLEAN:
289 options_all += ' --always-clean'
290
291 if env.ART_TEST_BISECTION:
292 options_all += ' --bisection-search'
293
294 if env.ART_TEST_ANDROID_ROOT:
295 options_all += ' --android-root ' + env.ART_TEST_ANDROID_ROOT
296
297 if gdb:
298 options_all += ' --gdb'
299 if gdb_arg:
300 options_all += ' --gdb-arg ' + gdb_arg
301
302 config = itertools.product(tests, TARGET_TYPES, RUN_TYPES, PREBUILD_TYPES,
303 COMPILER_TYPES, RELOCATE_TYPES, TRACE_TYPES,
304 GC_TYPES, JNI_TYPES, IMAGE_TYPES, PICTEST_TYPES,
305 DEBUGGABLE_TYPES)
306
307 for test, target, run, prebuild, compiler, relocate, trace, gc, \
308 jni, image, pictest, debuggable in config:
309 for address_size in ADDRESS_SIZES_TARGET[target]:
310 if stop_testrunner:
311 # When ART_TEST_KEEP_GOING is set to false, then as soon as a test
312 # fails, stop_testrunner is set to True. When this happens, the method
313 # stops creating any any thread and wait for all the exising threads
314 # to end.
315 while threading.active_count() > 2:
316 time.sleep(0.1)
317 return
318 test_name = 'test-art-'
319 test_name += target + '-run-test-'
320 test_name += run + '-'
321 test_name += prebuild + '-'
322 test_name += compiler + '-'
323 test_name += relocate + '-'
324 test_name += trace + '-'
325 test_name += gc + '-'
326 test_name += jni + '-'
327 test_name += image + '-'
328 test_name += pictest + '-'
329 test_name += debuggable + '-'
330 test_name += test
331 test_name += address_size
332
333 variant_set = {target, run, prebuild, compiler, relocate, trace, gc, jni,
334 image, pictest, debuggable, address_size}
335
336 options_test = options_all
337
338 if target == 'host':
339 options_test += ' --host'
340
341 if run == 'ndebug':
342 options_test += ' -O'
343
344 if prebuild == 'prebuild':
345 options_test += ' --prebuild'
346 elif prebuild == 'no-prebuild':
347 options_test += ' --no-prebuild'
348 elif prebuild == 'no-dex2oat':
349 options_test += ' --no-prebuild --no-dex2oat'
350
351 if compiler == 'optimizing':
352 options_test += ' --optimizing'
353 elif compiler == 'regalloc_gc':
354 options_test += ' --optimizing -Xcompiler-option --register-allocation-strategy=graph-color'
355 elif compiler == 'interpreter':
356 options_test += ' --interpreter'
357 elif compiler == 'interp-ac':
358 options_test += ' --interpreter --verify-soft-fail'
359 elif compiler == 'jit':
360 options_test += ' --jit'
361
362 if relocate == 'relocate':
363 options_test += ' --relocate'
364 elif relocate == 'no-relocate':
365 options_test += ' --no-relocate'
366 elif relocate == 'relocate-npatchoat':
367 options_test += ' --relocate --no-patchoat'
368
369 if trace == 'trace':
370 options_test += ' --trace'
371 elif trace == 'stream':
372 options_test += ' --trace --stream'
373
374 if gc == 'gcverify':
375 options_test += ' --gcverify'
376 elif gc == 'gcstress':
377 options_test += ' --gcstress'
378
379 if jni == 'forcecopy':
380 options_test += ' --runtime-option -Xjniopts:forcecopy'
381 elif jni == 'checkjni':
382 options_test += ' --runtime-option -Xcheck:jni'
383
384 if image == 'no-image':
385 options_test += ' --no-image'
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000386 elif image == 'multipicimage':
387 options_test += ' --multi-image'
388
389 if pictest == 'pictest':
390 options_test += ' --pic-test'
391
392 if debuggable == 'debuggable':
393 options_test += ' --debuggable'
394
395 if address_size == '64':
396 options_test += ' --64'
397
398 if env.DEX2OAT_HOST_INSTRUCTION_SET_FEATURES:
399 options_test += ' --instruction-set-features' + env.DEX2OAT_HOST_INSTRUCTION_SET_FEATURES
400
401 elif address_size == '32':
402 if env.HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES:
403 options_test += ' --instruction-set-features ' + \
404 env.HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES
405
406 options_test = (' --output-path %s/run-test-output/%s') % (
407 env.ART_HOST_TEST_DIR, test_name) + options_test
408
409 run_test_sh = env.ANDROID_BUILD_TOP + '/art/test/run-test'
410 command = run_test_sh + ' ' + options_test + ' ' + test
411
412 semaphore.acquire()
413 worker = threading.Thread(target=run_test, args=(command, test, variant_set, test_name))
414 worker.daemon = True
415 worker.start()
416
417 while threading.active_count() > 2:
418 time.sleep(0.1)
419
420
421def run_test(command, test, test_variant, test_name):
422 """Runs the test.
423
424 It invokes art/test/run-test script to run the test. The output of the script
425 is checked, and if it ends with "Succeeded!", it assumes that the tests
426 passed, otherwise, put it in the list of failed test. Before actually running
427 the test, it also checks if the test is placed in the list of disabled tests,
428 and if yes, it skips running it, and adds the test in the list of skipped
429 tests. The method uses print_text method to actually print the output. After
430 successfully running and capturing the output for the test, it releases the
431 semaphore object.
432
433 Args:
434 command: The command to be used to invoke the script
435 test: The name of the test without the variant information.
436 test_variant: The set of variant for the test.
437 test_name: The name of the test along with the variants.
438 """
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000439 global stop_testrunner
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000440 try:
441 if is_test_disabled(test, test_variant):
442 test_skipped = True
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000443 else:
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000444 test_skipped = False
445 proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
446 script_output = proc.stdout.read().strip()
447 test_passed = not proc.wait()
448
449 if not test_skipped:
450 if test_passed:
451 print_test_info(test_name, 'PASS')
452 else:
453 failed_tests.append(test_name)
454 if not env.ART_TEST_KEEP_GOING:
455 stop_testrunner = True
456 print_test_info(test_name, 'FAIL', ('%s\n%s') % (
457 command, script_output))
458 elif not dry_run:
459 print_test_info(test_name, 'SKIP')
460 skipped_tests.append(test_name)
461 else:
462 print_test_info(test_name, '')
463 except Exception, e:
464 failed_tests.append(test_name)
465 print_text(('%s\n%s\n') % (command, str(e)))
466 finally:
467 semaphore.release()
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000468
469
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000470def print_test_info(test_name, result, failed_test_info=""):
471 """Print the continous test information
472
473 If verbose is set to True, it continuously prints test status information
474 on a new line.
475 If verbose is set to False, it keeps on erasing test
476 information by overriding it with the latest test information. Also,
477 in this case it stictly makes sure that the information length doesn't
478 exceed the console width. It does so by shortening the test_name.
479
480 When a test fails, it prints the output of the run-test script and
481 command used to invoke the script. It doesn't override the failing
482 test information in either of the cases.
483 """
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000484
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000485 global test_count
486 info = ''
487 if not verbose:
488 # Without --verbose, the testrunner erases passing test info. It
489 # does that by overriding the printed text with white spaces all across
490 # the console width.
491 console_width = int(os.popen('stty size', 'r').read().split()[1])
492 info = '\r' + ' ' * console_width + '\r'
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000493 try:
494 print_mutex.acquire()
495 test_count += 1
496 percent = (test_count * 100) / total_test_count
497 progress_info = ('[ %d%% %d/%d ]') % (
498 percent,
499 test_count,
500 total_test_count)
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000501
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000502 if result == "FAIL":
503 info += ('%s %s %s\n%s\n') % (
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000504 progress_info,
505 test_name,
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000506 COLOR_ERROR + 'FAIL' + COLOR_NORMAL,
507 failed_test_info)
508 else:
509 result_text = ''
510 if result == 'PASS':
511 result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL
512 elif result == 'SKIP':
513 result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL
514
515 if verbose:
516 info += ('%s %s %s\n') % (
517 progress_info,
518 test_name,
519 result_text)
520 else:
521 total_output_length = 2 # Two spaces
522 total_output_length += len(progress_info)
523 total_output_length += len(result)
524 allowed_test_length = console_width - total_output_length
525 test_name_len = len(test_name)
526 if allowed_test_length < test_name_len:
527 test_name = ('%s...%s') % (
528 test_name[:(allowed_test_length - 3)/2],
529 test_name[-(allowed_test_length - 3)/2:])
Alex Lightc14311c2017-02-23 17:02:46 -0800530 info += ('%s %s %s') % (
531 progress_info,
532 test_name,
533 result_text)
Shubham Ajmerabbd84332017-02-17 00:41:10 +0000534 print_text(info)
535 except Exception, e:
536 print_text(('%s\n%s\n') % (test_name, str(e)))
537 failed_tests.append(test_name)
538 finally:
539 print_mutex.release()
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000540
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000541def get_disabled_test_info():
542 """Generate set of known failures.
543
544 It parses the art/test/knownfailures.json file to generate the list of
545 disabled tests.
546
547 Returns:
548 The method returns a dict of tests mapped to the variants list
549 for which the test should not be run.
550 """
551 known_failures_file = env.ANDROID_BUILD_TOP + '/art/test/knownfailures.json'
552 with open(known_failures_file) as known_failures_json:
553 known_failures_info = json.loads(known_failures_json.read())
554
555 disabled_test_info = {}
556 for failure in known_failures_info:
557 tests = failure.get('test')
558 if tests:
559 tests = [tests]
560 else:
561 tests = failure.get('tests', [])
562 variants = parse_variants(failure.get('variant'))
563 env_vars = failure.get('env_vars')
564 if check_env_vars(env_vars):
565 for test in tests:
566 if test in disabled_test_info:
567 disabled_test_info[test] = disabled_test_info[test].union(variants)
568 else:
569 disabled_test_info[test] = variants
570 return disabled_test_info
571
572
573def check_env_vars(env_vars):
574 """Checks if the env variables are set as required to run the test.
575
576 Returns:
577 True if all the env variables are set as required, otherwise False.
578 """
579
580 if not env_vars:
581 return True
582 for key in env_vars:
583 if env.get_env(key) != env_vars.get(key):
584 return False
585 return True
586
587
588def is_test_disabled(test, variant_set):
589 """Checks if the test along with the variant_set is disabled.
590
591 Args:
592 test: The name of the test as in art/test directory.
593 variant_set: Variants to be used for the test.
594 Returns:
595 True, if the test is disabled.
596 """
597 if dry_run:
598 return True
Alex Lightbc319b22017-02-17 14:21:33 -0800599 if test in env.EXTRA_DISABLED_TESTS:
600 return True
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000601 variants_list = DISABLED_TEST_CONTAINER.get(test, {})
602 for variants in variants_list:
603 variants_present = True
604 for variant in variants:
605 if variant not in variant_set:
606 variants_present = False
607 break
608 if variants_present:
609 return True
610 return False
611
612
613def parse_variants(variants):
614 """Parse variants fetched from art/test/knownfailures.json.
615 """
616 if not variants:
617 variants = ''
618 for variant in TOTAL_VARIANTS_SET:
619 variants += variant
620 variants += '|'
621 variants = variants[:-1]
622 variant_list = set()
623 or_variants = variants.split('|')
624 for or_variant in or_variants:
625 and_variants = or_variant.split('&')
626 variant = set()
627 for and_variant in and_variants:
628 and_variant = and_variant.strip()
629 variant.add(and_variant)
630 variant_list.add(frozenset(variant))
631 return variant_list
632
633def print_text(output):
634 sys.stdout.write(output)
635 sys.stdout.flush()
636
637def print_analysis():
638 if not verbose:
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000639 # Without --verbose, the testrunner erases passing test info. It
640 # does that by overriding the printed text with white spaces all across
641 # the console width.
642 console_width = int(os.popen('stty size', 'r').read().split()[1])
643 eraser_text = '\r' + ' ' * console_width + '\r'
644 print_text(eraser_text)
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000645 if skipped_tests:
646 print_text(COLOR_SKIP + 'SKIPPED TESTS' + COLOR_NORMAL + '\n')
647 for test in skipped_tests:
648 print_text(test + '\n')
649 print_text('\n')
650
651 if failed_tests:
652 print_text(COLOR_ERROR + 'FAILED TESTS' + COLOR_NORMAL + '\n')
653 for test in failed_tests:
654 print_text(test + '\n')
655
656
657def parse_test_name(test_name):
658 """Parses the testname provided by the user.
659 It supports two types of test_name:
660 1) Like 001-HelloWorld. In this case, it will just verify if the test actually
661 exists and if it does, it returns the testname.
662 2) Like test-art-host-run-test-debug-prebuild-interpreter-no-relocate-ntrace-cms-checkjni-picimage-npictest-ndebuggable-001-HelloWorld32
663 In this case, it will parse all the variants and check if they are placed
664 correctly. If yes, it will set the various VARIANT_TYPES to use the
665 variants required to run the test. Again, it returns the test_name
666 without the variant information like 001-HelloWorld.
667 """
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000668 test_set = set()
669 for test in RUN_TEST_SET:
670 if test.startswith(test_name):
671 test_set.add(test)
672 if test_set:
673 return test_set
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000674
675 regex = '^test-art-'
676 regex += '(' + '|'.join(VARIANT_TYPE_DICT['target']) + ')-'
677 regex += 'run-test-'
678 regex += '(' + '|'.join(VARIANT_TYPE_DICT['run']) + ')-'
679 regex += '(' + '|'.join(VARIANT_TYPE_DICT['prebuild']) + ')-'
680 regex += '(' + '|'.join(VARIANT_TYPE_DICT['compiler']) + ')-'
681 regex += '(' + '|'.join(VARIANT_TYPE_DICT['relocate']) + ')-'
682 regex += '(' + '|'.join(VARIANT_TYPE_DICT['trace']) + ')-'
683 regex += '(' + '|'.join(VARIANT_TYPE_DICT['gc']) + ')-'
684 regex += '(' + '|'.join(VARIANT_TYPE_DICT['jni']) + ')-'
685 regex += '(' + '|'.join(VARIANT_TYPE_DICT['image']) + ')-'
686 regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-'
687 regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-'
688 regex += '(' + '|'.join(RUN_TEST_SET) + ')'
689 regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
690 match = re.match(regex, test_name)
691 if match:
692 TARGET_TYPES.add(match.group(1))
693 RUN_TYPES.add(match.group(2))
694 PREBUILD_TYPES.add(match.group(3))
695 COMPILER_TYPES.add(match.group(4))
696 RELOCATE_TYPES.add(match.group(5))
697 TRACE_TYPES.add(match.group(6))
698 GC_TYPES.add(match.group(7))
699 JNI_TYPES.add(match.group(8))
700 IMAGE_TYPES.add(match.group(9))
701 PICTEST_TYPES.add(match.group(10))
702 DEBUGGABLE_TYPES.add(match.group(11))
703 ADDRESS_SIZES.add(match.group(13))
704 return {match.group(12)}
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000705 raise ValueError(test_name + " is not a valid test")
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000706
707
708def parse_option():
709 global verbose
710 global dry_run
711 global n_thread
712 global build
713 global gdb
714 global gdb_arg
715
Alex Light7a1ccf82017-02-21 09:52:34 -0800716 parser = argparse.ArgumentParser(description="Runs all or a subset of the ART test suite.")
717 parser.add_argument('-t', '--test', dest='test', help='name of the test')
718 parser.add_argument('-j', type=int, dest='n_thread')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000719 for variant in TOTAL_VARIANTS_SET:
720 flag = '--' + variant
721 flag_dest = variant.replace('-', '_')
722 if variant == '32' or variant == '64':
723 flag_dest = 'n' + flag_dest
Alex Light7a1ccf82017-02-21 09:52:34 -0800724 parser.add_argument(flag, action='store_true', dest=flag_dest)
725 parser.add_argument('--verbose', '-v', action='store_true', dest='verbose')
726 parser.add_argument('--dry-run', action='store_true', dest='dry_run')
727 parser.add_argument("--skip", action="append", dest="skips", default=[],
728 help="Skip the given test in all circumstances.")
729 parser.add_argument('-b', '--build-dependencies', action='store_true', dest='build')
730 parser.add_argument('--gdb', action='store_true', dest='gdb')
731 parser.add_argument('--gdb-arg', dest='gdb_arg')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000732
Alex Light7a1ccf82017-02-21 09:52:34 -0800733 options = parser.parse_args()
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000734 test = ''
Alex Lightbc319b22017-02-17 14:21:33 -0800735 env.EXTRA_DISABLED_TESTS.update(set(options.skips))
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000736 if options.test:
737 test = parse_test_name(options.test)
738 if options.pictest:
739 PICTEST_TYPES.add('pictest')
740 if options.ndebug:
741 RUN_TYPES.add('ndebug')
742 if options.interp_ac:
743 COMPILER_TYPES.add('interp-ac')
744 if options.picimage:
745 IMAGE_TYPES.add('picimage')
746 if options.n64:
747 ADDRESS_SIZES.add('64')
748 if options.interpreter:
749 COMPILER_TYPES.add('interpreter')
750 if options.jni:
751 JNI_TYPES.add('jni')
752 if options.relocate_npatchoat:
753 RELOCATE_TYPES.add('relocate-npatchoat')
754 if options.no_prebuild:
755 PREBUILD_TYPES.add('no-prebuild')
756 if options.npictest:
757 PICTEST_TYPES.add('npictest')
758 if options.no_dex2oat:
759 PREBUILD_TYPES.add('no-dex2oat')
760 if options.jit:
761 COMPILER_TYPES.add('jit')
762 if options.relocate:
763 RELOCATE_TYPES.add('relocate')
764 if options.ndebuggable:
765 DEBUGGABLE_TYPES.add('ndebuggable')
766 if options.no_image:
767 IMAGE_TYPES.add('no-image')
768 if options.optimizing:
769 COMPILER_TYPES.add('optimizing')
770 if options.trace:
771 TRACE_TYPES.add('trace')
772 if options.gcstress:
773 GC_TYPES.add('gcstress')
774 if options.no_relocate:
775 RELOCATE_TYPES.add('no-relocate')
776 if options.target:
777 TARGET_TYPES.add('target')
778 if options.forcecopy:
779 JNI_TYPES.add('forcecopy')
780 if options.n32:
781 ADDRESS_SIZES.add('32')
782 if options.host:
783 TARGET_TYPES.add('host')
784 if options.gcverify:
785 GC_TYPES.add('gcverify')
786 if options.debuggable:
787 DEBUGGABLE_TYPES.add('debuggable')
788 if options.prebuild:
789 PREBUILD_TYPES.add('prebuild')
790 if options.debug:
791 RUN_TYPES.add('debug')
792 if options.checkjni:
793 JNI_TYPES.add('checkjni')
794 if options.ntrace:
795 TRACE_TYPES.add('ntrace')
796 if options.cms:
797 GC_TYPES.add('cms')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000798 if options.multipicimage:
799 IMAGE_TYPES.add('multipicimage')
800 if options.verbose:
801 verbose = True
802 if options.n_thread:
803 n_thread = max(1, options.n_thread)
804 if options.dry_run:
805 dry_run = True
806 verbose = True
807 if options.build:
808 build = True
809 if options.gdb:
810 n_thread = 1
811 gdb = True
812 if options.gdb_arg:
813 gdb_arg = options.gdb_arg
814
815 return test
816
817def main():
818 gather_test_info()
819 user_requested_test = parse_option()
820 setup_test_env()
821 if build:
822 build_targets = ''
823 if 'host' in TARGET_TYPES:
824 build_targets += 'test-art-host-run-test-dependencies'
825 if 'target' in TARGET_TYPES:
826 build_targets += 'test-art-target-run-test-dependencies'
Shubham Ajmera06cde292017-02-10 23:15:05 +0000827 build_command = 'make'
828 build_command += ' -j' + str(n_thread)
829 build_command += ' -C ' + env.ANDROID_BUILD_TOP
830 build_command += ' ' + build_targets
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000831 if subprocess.call(build_command.split()):
832 sys.exit(1)
833 if user_requested_test:
834 test_runner_thread = threading.Thread(target=run_tests, args=(user_requested_test,))
835 else:
836 test_runner_thread = threading.Thread(target=run_tests, args=(RUN_TEST_SET,))
837 test_runner_thread.daemon = True
838 try:
839 test_runner_thread.start()
840 while threading.active_count() > 1:
841 time.sleep(0.1)
842 print_analysis()
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000843 except Exception, e:
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000844 print_analysis()
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000845 print_text(str(e))
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000846 sys.exit(1)
Shubham Ajmerac5aae872017-02-16 19:58:59 +0000847 if failed_tests:
848 sys.exit(1)
849 sys.exit(0)
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000850
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000851if __name__ == '__main__':
852 main()