blob: 282b6cc98d79bc37ab3c05d962956a89c79f5693 [file] [log] [blame]
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -07001#!/usr/bin/env python3.4
Aart Bik7593b992016-08-17 16:51:12 -07002#
3# Copyright (C) 2016 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
17import abc
18import argparse
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070019import filecmp
20
21from glob import glob
22
23import os
24import shlex
25import shutil
Aart Bik7593b992016-08-17 16:51:12 -070026import subprocess
27import sys
Aart Bik7593b992016-08-17 16:51:12 -070028
29from tempfile import mkdtemp
Aart Bik7593b992016-08-17 16:51:12 -070030
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070031
32sys.path.append(os.path.dirname(os.path.dirname(__file__)))
33
34from bisection_search.common import RetCode
35from bisection_search.common import CommandListToCommandString
36from bisection_search.common import FatalError
37from bisection_search.common import GetEnvVariableOrError
38from bisection_search.common import RunCommandForOutput
39from bisection_search.common import DeviceTestEnv
40
41# Return codes supported by bisection bug search.
42BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
Aart Bik7593b992016-08-17 16:51:12 -070043
44#
45# Utility methods.
46#
47
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070048
49def RunCommand(cmd, out, err, timeout=5):
Aart Bik7593b992016-08-17 16:51:12 -070050 """Executes a command, and returns its return code.
51
52 Args:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070053 cmd: list of strings, a command to execute
Aart Bik7593b992016-08-17 16:51:12 -070054 out: string, file name to open for stdout (or None)
55 err: string, file name to open for stderr (or None)
56 timeout: int, time out in seconds
57 Returns:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070058 RetCode, return code of running command (forced RetCode.TIMEOUT
59 on timeout)
Aart Bik7593b992016-08-17 16:51:12 -070060 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070061 devnull = subprocess.DEVNULL
62 outf = devnull
63 if out is not None:
Aart Bik7593b992016-08-17 16:51:12 -070064 outf = open(out, mode='w')
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070065 errf = devnull
66 if err is not None:
Aart Bik7593b992016-08-17 16:51:12 -070067 errf = open(err, mode='w')
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070068 (_, _, retcode) = RunCommandForOutput(cmd, None, outf, errf, timeout)
69 if outf != devnull:
Aart Bik7593b992016-08-17 16:51:12 -070070 outf.close()
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070071 if errf != devnull:
Aart Bik7593b992016-08-17 16:51:12 -070072 errf.close()
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070073 return retcode
74
Aart Bik7593b992016-08-17 16:51:12 -070075
76def GetJackClassPath():
77 """Returns Jack's classpath."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070078 top = GetEnvVariableOrError('ANDROID_BUILD_TOP')
Aart Bik7593b992016-08-17 16:51:12 -070079 libdir = top + '/out/host/common/obj/JAVA_LIBRARIES'
80 return libdir + '/core-libart-hostdex_intermediates/classes.jack:' \
81 + libdir + '/core-oj-hostdex_intermediates/classes.jack'
82
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070083
Aart Bikb16d4132016-08-19 15:45:11 -070084def GetExecutionModeRunner(device, mode):
Aart Bik7593b992016-08-17 16:51:12 -070085 """Returns a runner for the given execution mode.
86
87 Args:
Aart Bikb16d4132016-08-19 15:45:11 -070088 device: string, target device serial number (or None)
Aart Bik7593b992016-08-17 16:51:12 -070089 mode: string, execution mode
90 Returns:
91 TestRunner with given execution mode
92 Raises:
93 FatalError: error for unknown execution mode
94 """
95 if mode == 'ri':
96 return TestRunnerRIOnHost()
97 if mode == 'hint':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070098 return TestRunnerArtIntOnHost()
Aart Bik7593b992016-08-17 16:51:12 -070099 if mode == 'hopt':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700100 return TestRunnerArtOptOnHost()
Aart Bik7593b992016-08-17 16:51:12 -0700101 if mode == 'tint':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700102 return TestRunnerArtIntOnTarget(device)
Aart Bik7593b992016-08-17 16:51:12 -0700103 if mode == 'topt':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700104 return TestRunnerArtOptOnTarget(device)
Aart Bik7593b992016-08-17 16:51:12 -0700105 raise FatalError('Unknown execution mode')
106
Aart Bik7593b992016-08-17 16:51:12 -0700107#
108# Execution mode classes.
109#
110
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700111
Aart Bik7593b992016-08-17 16:51:12 -0700112class TestRunner(object):
113 """Abstraction for running a test in a particular execution mode."""
114 __meta_class__ = abc.ABCMeta
115
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700116 @abc.abstractproperty
117 def description(self):
Aart Bik7593b992016-08-17 16:51:12 -0700118 """Returns a description string of the execution mode."""
Aart Bik7593b992016-08-17 16:51:12 -0700119
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700120 @abc.abstractproperty
121 def id(self):
Aart Bik7593b992016-08-17 16:51:12 -0700122 """Returns a short string that uniquely identifies the execution mode."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700123
124 @property
125 def output_file(self):
126 return self.id + '_out.txt'
127
128 @abc.abstractmethod
129 def GetBisectionSearchArgs(self):
130 """Get arguments to pass to bisection search tool.
131
132 Returns:
133 list of strings - arguments for bisection search tool, or None if
134 runner is not bisectable
135 """
Aart Bik7593b992016-08-17 16:51:12 -0700136
137 @abc.abstractmethod
138 def CompileAndRunTest(self):
139 """Compile and run the generated test.
140
141 Ensures that the current Test.java in the temporary directory is compiled
142 and executed under the current execution mode. On success, transfers the
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700143 generated output to the file self.output_file in the temporary directory.
Aart Bik7593b992016-08-17 16:51:12 -0700144
145 Most nonzero return codes are assumed non-divergent, since systems may
146 exit in different ways. This is enforced by normalizing return codes.
147
148 Returns:
149 normalized return code
150 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700151
Aart Bik7593b992016-08-17 16:51:12 -0700152
153class TestRunnerRIOnHost(TestRunner):
154 """Concrete test runner of the reference implementation on host."""
155
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700156 @property
157 def description(self):
158 return 'RI on host'
159
160 @property
161 def id(self):
162 return 'RI'
Aart Bik7593b992016-08-17 16:51:12 -0700163
164 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700165 if RunCommand(['javac', 'Test.java'],
166 out=None, err=None, timeout=30) == RetCode.SUCCESS:
167 retc = RunCommand(['java', 'Test'], self.output_file, err=None)
Aart Bik7593b992016-08-17 16:51:12 -0700168 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700169 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700170 return retc
171
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700172 def GetBisectionSearchArgs(self):
173 return None
Aart Bik7593b992016-08-17 16:51:12 -0700174
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700175
176class TestRunnerArtOnHost(TestRunner):
177 """Abstract test runner of Art on host."""
178
179 def __init__(self, extra_args=None):
Aart Bik7593b992016-08-17 16:51:12 -0700180 """Constructor for the Art on host tester.
181
182 Args:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700183 extra_args: list of strings, extra arguments for dalvikvm
Aart Bik7593b992016-08-17 16:51:12 -0700184 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700185 self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
186 if extra_args is not None:
187 self._art_cmd += extra_args
188 self._art_cmd.append('Test')
189 self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
190 'Test.java']
Aart Bik7593b992016-08-17 16:51:12 -0700191
192 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700193 if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
194 timeout=30) == RetCode.SUCCESS:
195 retc = RunCommand(self._art_cmd, self.output_file, 'arterr.txt')
Aart Bik7593b992016-08-17 16:51:12 -0700196 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700197 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700198 return retc
199
Aart Bik7593b992016-08-17 16:51:12 -0700200
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700201class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
202 """Concrete test runner of interpreter mode Art on host."""
203
204 def __init__(self):
205 """Constructor."""
206 super().__init__(['-Xint'])
207
208 @property
209 def description(self):
210 return 'Art interpreter on host'
211
212 @property
213 def id(self):
214 return 'HInt'
215
216 def GetBisectionSearchArgs(self):
217 return None
218
219
220class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
221 """Concrete test runner of optimizing compiler mode Art on host."""
222
223 def __init__(self):
224 """Constructor."""
225 super().__init__(None)
226
227 @property
228 def description(self):
229 return 'Art optimizing on host'
230
231 @property
232 def id(self):
233 return 'HOpt'
234
235 def GetBisectionSearchArgs(self):
236 cmd_str = CommandListToCommandString(
237 self._art_cmd[0:2] + ['{ARGS}'] + self._art_cmd[2:])
238 return ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
239
240
241class TestRunnerArtOnTarget(TestRunner):
242 """Abstract test runner of Art on target."""
243
244 def __init__(self, device, extra_args=None):
Aart Bik7593b992016-08-17 16:51:12 -0700245 """Constructor for the Art on target tester.
246
247 Args:
Aart Bikb16d4132016-08-19 15:45:11 -0700248 device: string, target device serial number (or None)
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700249 extra_args: list of strings, extra arguments for dalvikvm
Aart Bik7593b992016-08-17 16:51:12 -0700250 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700251 self._test_env = DeviceTestEnv('javafuzz_', specific_device=device)
252 self._dalvik_cmd = ['dalvikvm']
253 if extra_args is not None:
254 self._dalvik_cmd += extra_args
255 self._device = device
256 self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
257 'Test.java']
258 self._device_classpath = None
Aart Bik7593b992016-08-17 16:51:12 -0700259
260 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700261 if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
262 timeout=30) == RetCode.SUCCESS:
263 self._device_classpath = self._test_env.PushClasspath('classes.dex')
264 cmd = self._dalvik_cmd + ['-cp', self._device_classpath, 'Test']
265 (output, retc) = self._test_env.RunCommand(
266 cmd, {'ANDROID_LOG_TAGS': '*:s'})
267 with open(self.output_file, 'w') as run_out:
268 run_out.write(output)
Aart Bik7593b992016-08-17 16:51:12 -0700269 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700270 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700271 return retc
272
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700273 def GetBisectionSearchArgs(self):
274 cmd_str = CommandListToCommandString(
275 self._dalvik_cmd + ['-cp',self._device_classpath, 'Test'])
276 cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
277 if self._device:
278 cmd += ['--device-serial', self._device]
279 else:
280 cmd.append('--device')
281 return cmd
282
283
284class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
285 """Concrete test runner of interpreter mode Art on target."""
286
287 def __init__(self, device):
288 """Constructor.
289
290 Args:
291 device: string, target device serial number (or None)
292 """
293 super().__init__(device, ['-Xint'])
294
295 @property
296 def description(self):
297 return 'Art interpreter on target'
298
299 @property
300 def id(self):
301 return 'TInt'
302
303 def GetBisectionSearchArgs(self):
304 return None
305
306
307class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
308 """Concrete test runner of optimizing compiler mode Art on target."""
309
310 def __init__(self, device):
311 """Constructor.
312
313 Args:
314 device: string, target device serial number (or None)
315 """
316 super().__init__(device, None)
317
318 @property
319 def description(self):
320 return 'Art optimizing on target'
321
322 @property
323 def id(self):
324 return 'TOpt'
325
326 def GetBisectionSearchArgs(self):
327 cmd_str = CommandListToCommandString(
328 self._dalvik_cmd + ['-cp', self._device_classpath, 'Test'])
329 cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
330 if self._device:
331 cmd += ['--device-serial', self._device]
332 else:
333 cmd.append('--device')
334 return cmd
335
336
Aart Bik7593b992016-08-17 16:51:12 -0700337#
338# Tester classes.
339#
340
Aart Bik7593b992016-08-17 16:51:12 -0700341
342class JavaFuzzTester(object):
343 """Tester that runs JavaFuzz many times and report divergences."""
344
Aart Bikb16d4132016-08-19 15:45:11 -0700345 def __init__(self, num_tests, device, mode1, mode2):
Aart Bik7593b992016-08-17 16:51:12 -0700346 """Constructor for the tester.
347
348 Args:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700349 num_tests: int, number of tests to run
350 device: string, target device serial number (or None)
351 mode1: string, execution mode for first runner
352 mode2: string, execution mode for second runner
Aart Bik7593b992016-08-17 16:51:12 -0700353 """
354 self._num_tests = num_tests
Aart Bikb16d4132016-08-19 15:45:11 -0700355 self._device = device
356 self._runner1 = GetExecutionModeRunner(device, mode1)
357 self._runner2 = GetExecutionModeRunner(device, mode2)
Aart Bik7593b992016-08-17 16:51:12 -0700358 self._save_dir = None
359 self._tmp_dir = None
360 # Statistics.
361 self._test = 0
362 self._num_success = 0
363 self._num_not_compiled = 0
364 self._num_not_run = 0
365 self._num_timed_out = 0
366 self._num_divergences = 0
367
368 def __enter__(self):
369 """On entry, enters new temp directory after saving current directory.
370
371 Raises:
372 FatalError: error when temp directory cannot be constructed
373 """
374 self._save_dir = os.getcwd()
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700375 self._results_dir = mkdtemp(dir='/tmp/')
376 self._tmp_dir = mkdtemp(dir=self._results_dir)
377 if self._tmp_dir is None or self._results_dir is None:
Aart Bik7593b992016-08-17 16:51:12 -0700378 raise FatalError('Cannot obtain temp directory')
379 os.chdir(self._tmp_dir)
380 return self
381
382 def __exit__(self, etype, evalue, etraceback):
383 """On exit, re-enters previously saved current directory and cleans up."""
384 os.chdir(self._save_dir)
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700385 shutil.rmtree(self._tmp_dir)
Aart Bik7593b992016-08-17 16:51:12 -0700386 if self._num_divergences == 0:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700387 shutil.rmtree(self._results_dir)
Aart Bik7593b992016-08-17 16:51:12 -0700388
389 def Run(self):
390 """Runs JavaFuzz many times and report divergences."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700391 print()
392 print('**\n**** JavaFuzz Testing\n**')
393 print()
394 print('#Tests :', self._num_tests)
395 print('Device :', self._device)
396 print('Directory :', self._results_dir)
397 print('Exec-mode1:', self._runner1.description)
398 print('Exec-mode2:', self._runner2.description)
Aart Bik9d537312016-09-15 10:42:02 -0700399 print()
Aart Bik7593b992016-08-17 16:51:12 -0700400 self.ShowStats()
401 for self._test in range(1, self._num_tests + 1):
402 self.RunJavaFuzzTest()
403 self.ShowStats()
404 if self._num_divergences == 0:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700405 print('\n\nsuccess (no divergences)\n')
Aart Bik7593b992016-08-17 16:51:12 -0700406 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700407 print('\n\nfailure (divergences)\n')
Aart Bik7593b992016-08-17 16:51:12 -0700408
409 def ShowStats(self):
410 """Shows current statistics (on same line) while tester is running."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700411 print('\rTests:', self._test, \
412 'Success:', self._num_success, \
413 'Not-compiled:', self._num_not_compiled, \
414 'Not-run:', self._num_not_run, \
415 'Timed-out:', self._num_timed_out, \
416 'Divergences:', self._num_divergences, end='')
Aart Bik7593b992016-08-17 16:51:12 -0700417 sys.stdout.flush()
418
419 def RunJavaFuzzTest(self):
420 """Runs a single JavaFuzz test, comparing two execution modes."""
421 self.ConstructTest()
422 retc1 = self._runner1.CompileAndRunTest()
423 retc2 = self._runner2.CompileAndRunTest()
424 self.CheckForDivergence(retc1, retc2)
425 self.CleanupTest()
426
427 def ConstructTest(self):
428 """Use JavaFuzz to generate next Test.java test.
429
430 Raises:
431 FatalError: error when javafuzz fails
432 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700433 if RunCommand(['javafuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
Aart Bik7593b992016-08-17 16:51:12 -0700434 raise FatalError('Unexpected error while running JavaFuzz')
435
436 def CheckForDivergence(self, retc1, retc2):
437 """Checks for divergences and updates statistics.
438
439 Args:
440 retc1: int, normalized return code of first runner
441 retc2: int, normalized return code of second runner
442 """
443 if retc1 == retc2:
444 # Non-divergent in return code.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700445 if retc1 == RetCode.SUCCESS:
Aart Bik7593b992016-08-17 16:51:12 -0700446 # Both compilations and runs were successful, inspect generated output.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700447 runner1_out = self._runner1.output_file
448 runner2_out = self._runner2.output_file
449 if not filecmp.cmp(runner1_out, runner2_out, shallow=False):
450 self.ReportDivergence(retc1, retc2, is_output_divergence=True)
Aart Bik7593b992016-08-17 16:51:12 -0700451 else:
452 self._num_success += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700453 elif retc1 == RetCode.TIMEOUT:
Aart Bik7593b992016-08-17 16:51:12 -0700454 self._num_timed_out += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700455 elif retc1 == RetCode.NOTCOMPILED:
Aart Bik7593b992016-08-17 16:51:12 -0700456 self._num_not_compiled += 1
457 else:
458 self._num_not_run += 1
459 else:
460 # Divergent in return code.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700461 self.ReportDivergence(retc1, retc2, is_output_divergence=False)
Aart Bik7593b992016-08-17 16:51:12 -0700462
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700463 def GetCurrentDivergenceDir(self):
464 return self._results_dir + '/divergence' + str(self._num_divergences)
465
466 def ReportDivergence(self, retc1, retc2, is_output_divergence):
Aart Bik7593b992016-08-17 16:51:12 -0700467 """Reports and saves a divergence."""
468 self._num_divergences += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700469 print('\n' + str(self._num_divergences), end='')
470 if is_output_divergence:
471 print(' divergence in output')
472 else:
473 print(' divergence in return code: ' + retc1.name + ' vs. ' +
474 retc2.name)
Aart Bik7593b992016-08-17 16:51:12 -0700475 # Save.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700476 ddir = self.GetCurrentDivergenceDir()
477 os.mkdir(ddir)
478 for f in glob('*.txt') + ['Test.java']:
479 shutil.copy(f, ddir)
480 # Maybe run bisection bug search.
481 if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
482 self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
483
484 def RunBisectionSearch(self, args, expected_retcode, expected_output,
485 runner_id):
486 ddir = self.GetCurrentDivergenceDir()
487 outfile_path = ddir + '/' + runner_id + '_bisection_out.txt'
488 logfile_path = ddir + '/' + runner_id + '_bisection_log.txt'
489 errfile_path = ddir + '/' + runner_id + '_bisection_err.txt'
490 args = list(args) + ['--logfile', logfile_path, '--cleanup']
491 args += ['--expected-retcode', expected_retcode.name]
492 if expected_output:
493 args += ['--expected-output', expected_output]
494 bisection_search_path = os.path.join(
495 GetEnvVariableOrError('ANDROID_BUILD_TOP'),
496 'art/tools/bisection_search/bisection_search.py')
497 if RunCommand([bisection_search_path] + args, out=outfile_path,
498 err=errfile_path, timeout=300) == RetCode.TIMEOUT:
499 print('Bisection search TIMEOUT')
500
501 def MaybeBisectDivergence(self, retc1, retc2, is_output_divergence):
502 bisection_args1 = self._runner1.GetBisectionSearchArgs()
503 bisection_args2 = self._runner2.GetBisectionSearchArgs()
504 if is_output_divergence:
505 maybe_output1 = self._runner1.output_file
506 maybe_output2 = self._runner2.output_file
507 else:
508 maybe_output1 = maybe_output2 = None
509 if bisection_args1 is not None:
510 self.RunBisectionSearch(bisection_args1, retc2, maybe_output2,
511 self._runner1.id)
512 if bisection_args2 is not None:
513 self.RunBisectionSearch(bisection_args2, retc1, maybe_output1,
514 self._runner2.id)
Aart Bik7593b992016-08-17 16:51:12 -0700515
516 def CleanupTest(self):
517 """Cleans up after a single test run."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700518 for file_name in os.listdir(self._tmp_dir):
519 file_path = os.path.join(self._tmp_dir, file_name)
520 if os.path.isfile(file_path):
521 os.unlink(file_path)
522 elif os.path.isdir(file_path):
523 shutil.rmtree(file_path)
Aart Bik7593b992016-08-17 16:51:12 -0700524
525
526def main():
527 # Handle arguments.
528 parser = argparse.ArgumentParser()
529 parser.add_argument('--num_tests', default=10000,
530 type=int, help='number of tests to run')
Aart Bikb16d4132016-08-19 15:45:11 -0700531 parser.add_argument('--device', help='target device serial number')
Aart Bik7593b992016-08-17 16:51:12 -0700532 parser.add_argument('--mode1', default='ri',
533 help='execution mode 1 (default: ri)')
534 parser.add_argument('--mode2', default='hopt',
535 help='execution mode 2 (default: hopt)')
536 args = parser.parse_args()
537 if args.mode1 == args.mode2:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700538 raise FatalError('Identical execution modes given')
Aart Bik7593b992016-08-17 16:51:12 -0700539 # Run the JavaFuzz tester.
Aart Bikb16d4132016-08-19 15:45:11 -0700540 with JavaFuzzTester(args.num_tests, args.device,
541 args.mode1, args.mode2) as fuzzer:
Aart Bik7593b992016-08-17 16:51:12 -0700542 fuzzer.Run()
543
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700544if __name__ == '__main__':
Aart Bik7593b992016-08-17 16:51:12 -0700545 main()