blob: 7fdd9e969ba511fb87bc5a1c3a82c71c3c367c0e [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"""
47import fnmatch
48import itertools
49import json
50from optparse import OptionParser
51import 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
440 if is_test_disabled(test, test_variant):
441 test_skipped = True
442 else:
443 test_skipped = False
Alex Light11b3d922017-02-08 10:45:12 -0800444 proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
445 script_output = proc.stdout.read().strip()
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000446 test_passed = not proc.wait()
447
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000448 if not test_skipped:
449 if test_passed:
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000450 print_test_info(test_name, 'PASS')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000451 else:
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000452 failed_tests.append(test_name)
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000453 if not env.ART_TEST_KEEP_GOING:
454 stop_testrunner = True
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000455 print_test_info(test_name, 'FAIL', ('%s\n%s') % (
456 command, script_output))
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000457 elif not dry_run:
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000458 print_test_info(test_name, 'SKIP')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000459 skipped_tests.append(test_name)
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000460 else:
461 print_test_info(test_name, '')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000462 semaphore.release()
463
464
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000465def print_test_info(test_name, result, failed_test_info=""):
466 """Print the continous test information
467
468 If verbose is set to True, it continuously prints test status information
469 on a new line.
470 If verbose is set to False, it keeps on erasing test
471 information by overriding it with the latest test information. Also,
472 in this case it stictly makes sure that the information length doesn't
473 exceed the console width. It does so by shortening the test_name.
474
475 When a test fails, it prints the output of the run-test script and
476 command used to invoke the script. It doesn't override the failing
477 test information in either of the cases.
478 """
479 global test_count
480 info = ''
481 if not verbose:
482 # Without --verbose, the testrunner erases passing test info. It
483 # does that by overriding the printed text with white spaces all across
484 # the console width.
485 console_width = int(os.popen('stty size', 'r').read().split()[1])
486 info = '\r' + ' ' * console_width + '\r'
487 print_mutex.acquire()
488 test_count += 1
489 percent = (test_count * 100) / total_test_count
490 progress_info = ('[ %d%% %d/%d ]') % (
491 percent,
492 test_count,
493 total_test_count)
494
495 if result == "FAIL":
496 info += ('%s %s %s\n%s\n') % (
497 progress_info,
498 test_name,
499 COLOR_ERROR + 'FAIL' + COLOR_NORMAL,
500 failed_test_info)
501 else:
502 result_text = ''
503 if result == 'PASS':
504 result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL
505 elif result == 'SKIP':
506 result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL
507
508 if verbose:
509 info += ('%s %s %s\n') % (
510 progress_info,
511 test_name,
512 result_text)
513 else:
514 total_output_length = 2 # Two spaces
515 total_output_length += len(progress_info)
516 total_output_length += len(result)
517 allowed_test_length = console_width - total_output_length
518 test_name_len = len(test_name)
519 if allowed_test_length < test_name_len:
520 test_name = ('%s...%s') % (
521 test_name[:(allowed_test_length - 3)/2],
522 test_name[-(allowed_test_length - 3)/2:])
523 info += ('%s %s %s') % (
524 progress_info,
525 test_name,
526 result_text)
527 print_text(info)
528 print_mutex.release()
529
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000530def get_disabled_test_info():
531 """Generate set of known failures.
532
533 It parses the art/test/knownfailures.json file to generate the list of
534 disabled tests.
535
536 Returns:
537 The method returns a dict of tests mapped to the variants list
538 for which the test should not be run.
539 """
540 known_failures_file = env.ANDROID_BUILD_TOP + '/art/test/knownfailures.json'
541 with open(known_failures_file) as known_failures_json:
542 known_failures_info = json.loads(known_failures_json.read())
543
544 disabled_test_info = {}
545 for failure in known_failures_info:
546 tests = failure.get('test')
547 if tests:
548 tests = [tests]
549 else:
550 tests = failure.get('tests', [])
551 variants = parse_variants(failure.get('variant'))
552 env_vars = failure.get('env_vars')
553 if check_env_vars(env_vars):
554 for test in tests:
555 if test in disabled_test_info:
556 disabled_test_info[test] = disabled_test_info[test].union(variants)
557 else:
558 disabled_test_info[test] = variants
559 return disabled_test_info
560
561
562def check_env_vars(env_vars):
563 """Checks if the env variables are set as required to run the test.
564
565 Returns:
566 True if all the env variables are set as required, otherwise False.
567 """
568
569 if not env_vars:
570 return True
571 for key in env_vars:
572 if env.get_env(key) != env_vars.get(key):
573 return False
574 return True
575
576
577def is_test_disabled(test, variant_set):
578 """Checks if the test along with the variant_set is disabled.
579
580 Args:
581 test: The name of the test as in art/test directory.
582 variant_set: Variants to be used for the test.
583 Returns:
584 True, if the test is disabled.
585 """
586 if dry_run:
587 return True
588 variants_list = DISABLED_TEST_CONTAINER.get(test, {})
589 for variants in variants_list:
590 variants_present = True
591 for variant in variants:
592 if variant not in variant_set:
593 variants_present = False
594 break
595 if variants_present:
596 return True
597 return False
598
599
600def parse_variants(variants):
601 """Parse variants fetched from art/test/knownfailures.json.
602 """
603 if not variants:
604 variants = ''
605 for variant in TOTAL_VARIANTS_SET:
606 variants += variant
607 variants += '|'
608 variants = variants[:-1]
609 variant_list = set()
610 or_variants = variants.split('|')
611 for or_variant in or_variants:
612 and_variants = or_variant.split('&')
613 variant = set()
614 for and_variant in and_variants:
615 and_variant = and_variant.strip()
616 variant.add(and_variant)
617 variant_list.add(frozenset(variant))
618 return variant_list
619
620def print_text(output):
621 sys.stdout.write(output)
622 sys.stdout.flush()
623
624def print_analysis():
625 if not verbose:
Shubham Ajmera14d340c2017-02-15 18:49:10 +0000626 # Without --verbose, the testrunner erases passing test info. It
627 # does that by overriding the printed text with white spaces all across
628 # the console width.
629 console_width = int(os.popen('stty size', 'r').read().split()[1])
630 eraser_text = '\r' + ' ' * console_width + '\r'
631 print_text(eraser_text)
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000632 if skipped_tests:
633 print_text(COLOR_SKIP + 'SKIPPED TESTS' + COLOR_NORMAL + '\n')
634 for test in skipped_tests:
635 print_text(test + '\n')
636 print_text('\n')
637
638 if failed_tests:
639 print_text(COLOR_ERROR + 'FAILED TESTS' + COLOR_NORMAL + '\n')
640 for test in failed_tests:
641 print_text(test + '\n')
642
643
644def parse_test_name(test_name):
645 """Parses the testname provided by the user.
646 It supports two types of test_name:
647 1) Like 001-HelloWorld. In this case, it will just verify if the test actually
648 exists and if it does, it returns the testname.
649 2) Like test-art-host-run-test-debug-prebuild-interpreter-no-relocate-ntrace-cms-checkjni-picimage-npictest-ndebuggable-001-HelloWorld32
650 In this case, it will parse all the variants and check if they are placed
651 correctly. If yes, it will set the various VARIANT_TYPES to use the
652 variants required to run the test. Again, it returns the test_name
653 without the variant information like 001-HelloWorld.
654 """
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000655 test_set = set()
656 for test in RUN_TEST_SET:
657 if test.startswith(test_name):
658 test_set.add(test)
659 if test_set:
660 return test_set
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000661
662 regex = '^test-art-'
663 regex += '(' + '|'.join(VARIANT_TYPE_DICT['target']) + ')-'
664 regex += 'run-test-'
665 regex += '(' + '|'.join(VARIANT_TYPE_DICT['run']) + ')-'
666 regex += '(' + '|'.join(VARIANT_TYPE_DICT['prebuild']) + ')-'
667 regex += '(' + '|'.join(VARIANT_TYPE_DICT['compiler']) + ')-'
668 regex += '(' + '|'.join(VARIANT_TYPE_DICT['relocate']) + ')-'
669 regex += '(' + '|'.join(VARIANT_TYPE_DICT['trace']) + ')-'
670 regex += '(' + '|'.join(VARIANT_TYPE_DICT['gc']) + ')-'
671 regex += '(' + '|'.join(VARIANT_TYPE_DICT['jni']) + ')-'
672 regex += '(' + '|'.join(VARIANT_TYPE_DICT['image']) + ')-'
673 regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-'
674 regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-'
675 regex += '(' + '|'.join(RUN_TEST_SET) + ')'
676 regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
677 match = re.match(regex, test_name)
678 if match:
679 TARGET_TYPES.add(match.group(1))
680 RUN_TYPES.add(match.group(2))
681 PREBUILD_TYPES.add(match.group(3))
682 COMPILER_TYPES.add(match.group(4))
683 RELOCATE_TYPES.add(match.group(5))
684 TRACE_TYPES.add(match.group(6))
685 GC_TYPES.add(match.group(7))
686 JNI_TYPES.add(match.group(8))
687 IMAGE_TYPES.add(match.group(9))
688 PICTEST_TYPES.add(match.group(10))
689 DEBUGGABLE_TYPES.add(match.group(11))
690 ADDRESS_SIZES.add(match.group(13))
691 return {match.group(12)}
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000692 raise ValueError(test_name + " is not a valid test")
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000693
694
695def parse_option():
696 global verbose
697 global dry_run
698 global n_thread
699 global build
700 global gdb
701 global gdb_arg
702
703 parser = OptionParser()
704 parser.add_option('-t', '--test', dest='test', help='name of the test')
705 parser.add_option('-j', type='int', dest='n_thread')
706 for variant in TOTAL_VARIANTS_SET:
707 flag = '--' + variant
708 flag_dest = variant.replace('-', '_')
709 if variant == '32' or variant == '64':
710 flag_dest = 'n' + flag_dest
711 parser.add_option(flag, action='store_true', dest=flag_dest)
712 parser.add_option('--verbose', '-v', action='store_true', dest='verbose')
713 parser.add_option('--dry-run', action='store_true', dest='dry_run')
714 parser.add_option('-b', '--build-dependencies', action='store_true', dest='build')
715 parser.add_option('--gdb', action='store_true', dest='gdb')
716 parser.add_option('--gdb-arg', dest='gdb_arg')
717
718 options = parser.parse_args()[0]
719 test = ''
720 if options.test:
721 test = parse_test_name(options.test)
722 if options.pictest:
723 PICTEST_TYPES.add('pictest')
724 if options.ndebug:
725 RUN_TYPES.add('ndebug')
726 if options.interp_ac:
727 COMPILER_TYPES.add('interp-ac')
728 if options.picimage:
729 IMAGE_TYPES.add('picimage')
730 if options.n64:
731 ADDRESS_SIZES.add('64')
732 if options.interpreter:
733 COMPILER_TYPES.add('interpreter')
734 if options.jni:
735 JNI_TYPES.add('jni')
736 if options.relocate_npatchoat:
737 RELOCATE_TYPES.add('relocate-npatchoat')
738 if options.no_prebuild:
739 PREBUILD_TYPES.add('no-prebuild')
740 if options.npictest:
741 PICTEST_TYPES.add('npictest')
742 if options.no_dex2oat:
743 PREBUILD_TYPES.add('no-dex2oat')
744 if options.jit:
745 COMPILER_TYPES.add('jit')
746 if options.relocate:
747 RELOCATE_TYPES.add('relocate')
748 if options.ndebuggable:
749 DEBUGGABLE_TYPES.add('ndebuggable')
750 if options.no_image:
751 IMAGE_TYPES.add('no-image')
752 if options.optimizing:
753 COMPILER_TYPES.add('optimizing')
754 if options.trace:
755 TRACE_TYPES.add('trace')
756 if options.gcstress:
757 GC_TYPES.add('gcstress')
758 if options.no_relocate:
759 RELOCATE_TYPES.add('no-relocate')
760 if options.target:
761 TARGET_TYPES.add('target')
762 if options.forcecopy:
763 JNI_TYPES.add('forcecopy')
764 if options.n32:
765 ADDRESS_SIZES.add('32')
766 if options.host:
767 TARGET_TYPES.add('host')
768 if options.gcverify:
769 GC_TYPES.add('gcverify')
770 if options.debuggable:
771 DEBUGGABLE_TYPES.add('debuggable')
772 if options.prebuild:
773 PREBUILD_TYPES.add('prebuild')
774 if options.debug:
775 RUN_TYPES.add('debug')
776 if options.checkjni:
777 JNI_TYPES.add('checkjni')
778 if options.ntrace:
779 TRACE_TYPES.add('ntrace')
780 if options.cms:
781 GC_TYPES.add('cms')
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000782 if options.multipicimage:
783 IMAGE_TYPES.add('multipicimage')
784 if options.verbose:
785 verbose = True
786 if options.n_thread:
787 n_thread = max(1, options.n_thread)
788 if options.dry_run:
789 dry_run = True
790 verbose = True
791 if options.build:
792 build = True
793 if options.gdb:
794 n_thread = 1
795 gdb = True
796 if options.gdb_arg:
797 gdb_arg = options.gdb_arg
798
799 return test
800
801def main():
802 gather_test_info()
803 user_requested_test = parse_option()
804 setup_test_env()
805 if build:
806 build_targets = ''
807 if 'host' in TARGET_TYPES:
808 build_targets += 'test-art-host-run-test-dependencies'
809 if 'target' in TARGET_TYPES:
810 build_targets += 'test-art-target-run-test-dependencies'
Shubham Ajmera06cde292017-02-10 23:15:05 +0000811 build_command = 'make'
812 build_command += ' -j' + str(n_thread)
813 build_command += ' -C ' + env.ANDROID_BUILD_TOP
814 build_command += ' ' + build_targets
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000815 if subprocess.call(build_command.split()):
816 sys.exit(1)
817 if user_requested_test:
818 test_runner_thread = threading.Thread(target=run_tests, args=(user_requested_test,))
819 else:
820 test_runner_thread = threading.Thread(target=run_tests, args=(RUN_TEST_SET,))
821 test_runner_thread.daemon = True
822 try:
823 test_runner_thread.start()
824 while threading.active_count() > 1:
825 time.sleep(0.1)
826 print_analysis()
827 if failed_tests:
828 sys.exit(1)
829 sys.exit(0)
830 except SystemExit:
831 pass
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000832 except Exception, e:
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000833 print_analysis()
Shubham Ajmerafaf12502017-02-15 17:19:44 +0000834 print_text(str(e))
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000835 sys.exit(1)
836
Shubham Ajmera65adb8b2017-02-06 16:04:25 +0000837if __name__ == '__main__':
838 main()