blob: cf2364b5e6127b93ad233ea94e052933dd1e9d51 [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
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070020import os
21import shlex
22import shutil
Aart Bik7593b992016-08-17 16:51:12 -070023import sys
Aart Bik7593b992016-08-17 16:51:12 -070024
Aart Bike0347482016-09-20 14:34:13 -070025from glob import glob
Aart Bik7593b992016-08-17 16:51:12 -070026from tempfile import mkdtemp
Aart Bik7593b992016-08-17 16:51:12 -070027
Wojciech Staszkiewiczf64837d2016-09-15 11:41:16 -070028sys.path.append(os.path.dirname(os.path.dirname(
29 os.path.realpath(__file__))))
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070030
Aart Bike0347482016-09-20 14:34:13 -070031from common.common import RetCode
32from common.common import CommandListToCommandString
33from common.common import FatalError
34from common.common import GetJackClassPath
35from common.common import GetEnvVariableOrError
36from common.common import RunCommand
37from common.common import DeviceTestEnv
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070038
39# Return codes supported by bisection bug search.
40BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
Aart Bik7593b992016-08-17 16:51:12 -070041
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070042
Aart Bikb16d4132016-08-19 15:45:11 -070043def GetExecutionModeRunner(device, mode):
Aart Bik7593b992016-08-17 16:51:12 -070044 """Returns a runner for the given execution mode.
45
46 Args:
Aart Bikb16d4132016-08-19 15:45:11 -070047 device: string, target device serial number (or None)
Aart Bik7593b992016-08-17 16:51:12 -070048 mode: string, execution mode
49 Returns:
50 TestRunner with given execution mode
51 Raises:
52 FatalError: error for unknown execution mode
53 """
54 if mode == 'ri':
55 return TestRunnerRIOnHost()
56 if mode == 'hint':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070057 return TestRunnerArtIntOnHost()
Aart Bik7593b992016-08-17 16:51:12 -070058 if mode == 'hopt':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070059 return TestRunnerArtOptOnHost()
Aart Bik7593b992016-08-17 16:51:12 -070060 if mode == 'tint':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070061 return TestRunnerArtIntOnTarget(device)
Aart Bik7593b992016-08-17 16:51:12 -070062 if mode == 'topt':
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070063 return TestRunnerArtOptOnTarget(device)
Aart Bik7593b992016-08-17 16:51:12 -070064 raise FatalError('Unknown execution mode')
65
Aart Bike0347482016-09-20 14:34:13 -070066
Aart Bik7593b992016-08-17 16:51:12 -070067#
68# Execution mode classes.
69#
70
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070071
Aart Bik7593b992016-08-17 16:51:12 -070072class TestRunner(object):
73 """Abstraction for running a test in a particular execution mode."""
74 __meta_class__ = abc.ABCMeta
75
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070076 @abc.abstractproperty
77 def description(self):
Aart Bik7593b992016-08-17 16:51:12 -070078 """Returns a description string of the execution mode."""
Aart Bik7593b992016-08-17 16:51:12 -070079
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070080 @abc.abstractproperty
81 def id(self):
Aart Bik7593b992016-08-17 16:51:12 -070082 """Returns a short string that uniquely identifies the execution mode."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -070083
84 @property
85 def output_file(self):
86 return self.id + '_out.txt'
87
88 @abc.abstractmethod
89 def GetBisectionSearchArgs(self):
90 """Get arguments to pass to bisection search tool.
91
92 Returns:
93 list of strings - arguments for bisection search tool, or None if
94 runner is not bisectable
95 """
Aart Bik7593b992016-08-17 16:51:12 -070096
97 @abc.abstractmethod
98 def CompileAndRunTest(self):
99 """Compile and run the generated test.
100
101 Ensures that the current Test.java in the temporary directory is compiled
102 and executed under the current execution mode. On success, transfers the
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700103 generated output to the file self.output_file in the temporary directory.
Aart Bik7593b992016-08-17 16:51:12 -0700104
105 Most nonzero return codes are assumed non-divergent, since systems may
106 exit in different ways. This is enforced by normalizing return codes.
107
108 Returns:
109 normalized return code
110 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700111
Aart Bik7593b992016-08-17 16:51:12 -0700112
113class TestRunnerRIOnHost(TestRunner):
114 """Concrete test runner of the reference implementation on host."""
115
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700116 @property
117 def description(self):
118 return 'RI on host'
119
120 @property
121 def id(self):
122 return 'RI'
Aart Bik7593b992016-08-17 16:51:12 -0700123
124 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700125 if RunCommand(['javac', 'Test.java'],
126 out=None, err=None, timeout=30) == RetCode.SUCCESS:
127 retc = RunCommand(['java', 'Test'], self.output_file, err=None)
Aart Bik7593b992016-08-17 16:51:12 -0700128 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700129 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700130 return retc
131
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700132 def GetBisectionSearchArgs(self):
133 return None
Aart Bik7593b992016-08-17 16:51:12 -0700134
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700135
136class TestRunnerArtOnHost(TestRunner):
137 """Abstract test runner of Art on host."""
138
139 def __init__(self, extra_args=None):
Aart Bik7593b992016-08-17 16:51:12 -0700140 """Constructor for the Art on host tester.
141
142 Args:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700143 extra_args: list of strings, extra arguments for dalvikvm
Aart Bik7593b992016-08-17 16:51:12 -0700144 """
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700145 self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
146 if extra_args is not None:
147 self._art_cmd += extra_args
148 self._art_cmd.append('Test')
149 self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
150 'Test.java']
Aart Bik7593b992016-08-17 16:51:12 -0700151
152 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700153 if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
154 timeout=30) == RetCode.SUCCESS:
155 retc = RunCommand(self._art_cmd, self.output_file, 'arterr.txt')
Aart Bik7593b992016-08-17 16:51:12 -0700156 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700157 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700158 return retc
159
Aart Bik7593b992016-08-17 16:51:12 -0700160
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700161class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
162 """Concrete test runner of interpreter mode Art on host."""
163
164 def __init__(self):
165 """Constructor."""
166 super().__init__(['-Xint'])
167
168 @property
169 def description(self):
170 return 'Art interpreter on host'
171
172 @property
173 def id(self):
174 return 'HInt'
175
176 def GetBisectionSearchArgs(self):
177 return None
178
179
180class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
181 """Concrete test runner of optimizing compiler mode Art on host."""
182
183 def __init__(self):
184 """Constructor."""
185 super().__init__(None)
186
187 @property
188 def description(self):
189 return 'Art optimizing on host'
190
191 @property
192 def id(self):
193 return 'HOpt'
194
195 def GetBisectionSearchArgs(self):
196 cmd_str = CommandListToCommandString(
197 self._art_cmd[0:2] + ['{ARGS}'] + self._art_cmd[2:])
198 return ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
199
200
201class TestRunnerArtOnTarget(TestRunner):
202 """Abstract test runner of Art on target."""
203
204 def __init__(self, device, extra_args=None):
Aart Bik7593b992016-08-17 16:51:12 -0700205 """Constructor for the Art on target tester.
206
207 Args:
Aart Bikb16d4132016-08-19 15:45:11 -0700208 device: string, target device serial number (or None)
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700209 extra_args: list of strings, extra arguments for dalvikvm
Aart Bik7593b992016-08-17 16:51:12 -0700210 """
Aart Bik842a4f32016-09-21 15:45:18 -0700211 self._test_env = DeviceTestEnv('jfuzz_', specific_device=device)
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700212 self._dalvik_cmd = ['dalvikvm']
213 if extra_args is not None:
214 self._dalvik_cmd += extra_args
215 self._device = device
216 self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
217 'Test.java']
218 self._device_classpath = None
Aart Bik7593b992016-08-17 16:51:12 -0700219
220 def CompileAndRunTest(self):
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700221 if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
222 timeout=30) == RetCode.SUCCESS:
223 self._device_classpath = self._test_env.PushClasspath('classes.dex')
224 cmd = self._dalvik_cmd + ['-cp', self._device_classpath, 'Test']
225 (output, retc) = self._test_env.RunCommand(
226 cmd, {'ANDROID_LOG_TAGS': '*:s'})
227 with open(self.output_file, 'w') as run_out:
228 run_out.write(output)
Aart Bik7593b992016-08-17 16:51:12 -0700229 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700230 retc = RetCode.NOTCOMPILED
Aart Bik7593b992016-08-17 16:51:12 -0700231 return retc
232
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700233 def GetBisectionSearchArgs(self):
234 cmd_str = CommandListToCommandString(
235 self._dalvik_cmd + ['-cp',self._device_classpath, 'Test'])
236 cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
237 if self._device:
238 cmd += ['--device-serial', self._device]
239 else:
240 cmd.append('--device')
241 return cmd
242
243
244class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
245 """Concrete test runner of interpreter mode Art on target."""
246
247 def __init__(self, device):
248 """Constructor.
249
250 Args:
251 device: string, target device serial number (or None)
252 """
253 super().__init__(device, ['-Xint'])
254
255 @property
256 def description(self):
257 return 'Art interpreter on target'
258
259 @property
260 def id(self):
261 return 'TInt'
262
263 def GetBisectionSearchArgs(self):
264 return None
265
266
267class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
268 """Concrete test runner of optimizing compiler mode Art on target."""
269
270 def __init__(self, device):
271 """Constructor.
272
273 Args:
274 device: string, target device serial number (or None)
275 """
276 super().__init__(device, None)
277
278 @property
279 def description(self):
280 return 'Art optimizing on target'
281
282 @property
283 def id(self):
284 return 'TOpt'
285
286 def GetBisectionSearchArgs(self):
287 cmd_str = CommandListToCommandString(
288 self._dalvik_cmd + ['-cp', self._device_classpath, 'Test'])
289 cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
290 if self._device:
291 cmd += ['--device-serial', self._device]
292 else:
293 cmd.append('--device')
294 return cmd
295
296
Aart Bik7593b992016-08-17 16:51:12 -0700297#
Aart Bike0347482016-09-20 14:34:13 -0700298# Tester class.
Aart Bik7593b992016-08-17 16:51:12 -0700299#
300
Aart Bik7593b992016-08-17 16:51:12 -0700301
Aart Bik842a4f32016-09-21 15:45:18 -0700302class JFuzzTester(object):
303 """Tester that runs JFuzz many times and report divergences."""
Aart Bik7593b992016-08-17 16:51:12 -0700304
Aart Bikb16d4132016-08-19 15:45:11 -0700305 def __init__(self, num_tests, device, mode1, mode2):
Aart Bik7593b992016-08-17 16:51:12 -0700306 """Constructor for the tester.
307
308 Args:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700309 num_tests: int, number of tests to run
310 device: string, target device serial number (or None)
311 mode1: string, execution mode for first runner
312 mode2: string, execution mode for second runner
Aart Bik7593b992016-08-17 16:51:12 -0700313 """
314 self._num_tests = num_tests
Aart Bikb16d4132016-08-19 15:45:11 -0700315 self._device = device
316 self._runner1 = GetExecutionModeRunner(device, mode1)
317 self._runner2 = GetExecutionModeRunner(device, mode2)
Aart Bik7593b992016-08-17 16:51:12 -0700318 self._save_dir = None
Aart Bike0347482016-09-20 14:34:13 -0700319 self._results_dir = None
Aart Bik842a4f32016-09-21 15:45:18 -0700320 self._jfuzz_dir = None
Aart Bik7593b992016-08-17 16:51:12 -0700321 # Statistics.
322 self._test = 0
323 self._num_success = 0
324 self._num_not_compiled = 0
325 self._num_not_run = 0
326 self._num_timed_out = 0
327 self._num_divergences = 0
328
329 def __enter__(self):
330 """On entry, enters new temp directory after saving current directory.
331
332 Raises:
333 FatalError: error when temp directory cannot be constructed
334 """
335 self._save_dir = os.getcwd()
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700336 self._results_dir = mkdtemp(dir='/tmp/')
Aart Bik842a4f32016-09-21 15:45:18 -0700337 self._jfuzz_dir = mkdtemp(dir=self._results_dir)
338 if self._results_dir is None or self._jfuzz_dir is None:
Aart Bik7593b992016-08-17 16:51:12 -0700339 raise FatalError('Cannot obtain temp directory')
Aart Bik842a4f32016-09-21 15:45:18 -0700340 os.chdir(self._jfuzz_dir)
Aart Bik7593b992016-08-17 16:51:12 -0700341 return self
342
343 def __exit__(self, etype, evalue, etraceback):
344 """On exit, re-enters previously saved current directory and cleans up."""
345 os.chdir(self._save_dir)
Aart Bik842a4f32016-09-21 15:45:18 -0700346 shutil.rmtree(self._jfuzz_dir)
Aart Bik7593b992016-08-17 16:51:12 -0700347 if self._num_divergences == 0:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700348 shutil.rmtree(self._results_dir)
Aart Bik7593b992016-08-17 16:51:12 -0700349
350 def Run(self):
Aart Bik842a4f32016-09-21 15:45:18 -0700351 """Runs JFuzz many times and report divergences."""
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700352 print()
Aart Bik842a4f32016-09-21 15:45:18 -0700353 print('**\n**** JFuzz Testing\n**')
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700354 print()
355 print('#Tests :', self._num_tests)
356 print('Device :', self._device)
357 print('Directory :', self._results_dir)
358 print('Exec-mode1:', self._runner1.description)
359 print('Exec-mode2:', self._runner2.description)
Aart Bik9d537312016-09-15 10:42:02 -0700360 print()
Aart Bik7593b992016-08-17 16:51:12 -0700361 self.ShowStats()
362 for self._test in range(1, self._num_tests + 1):
Aart Bik842a4f32016-09-21 15:45:18 -0700363 self.RunJFuzzTest()
Aart Bik7593b992016-08-17 16:51:12 -0700364 self.ShowStats()
365 if self._num_divergences == 0:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700366 print('\n\nsuccess (no divergences)\n')
Aart Bik7593b992016-08-17 16:51:12 -0700367 else:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700368 print('\n\nfailure (divergences)\n')
Aart Bik7593b992016-08-17 16:51:12 -0700369
370 def ShowStats(self):
371 """Shows current statistics (on same line) while tester is running."""
Aart Bike0347482016-09-20 14:34:13 -0700372 print('\rTests:', self._test,
373 'Success:', self._num_success,
374 'Not-compiled:', self._num_not_compiled,
375 'Not-run:', self._num_not_run,
376 'Timed-out:', self._num_timed_out,
377 'Divergences:', self._num_divergences,
378 end='')
Aart Bik7593b992016-08-17 16:51:12 -0700379 sys.stdout.flush()
380
Aart Bik842a4f32016-09-21 15:45:18 -0700381 def RunJFuzzTest(self):
382 """Runs a single JFuzz test, comparing two execution modes."""
Aart Bik7593b992016-08-17 16:51:12 -0700383 self.ConstructTest()
384 retc1 = self._runner1.CompileAndRunTest()
385 retc2 = self._runner2.CompileAndRunTest()
386 self.CheckForDivergence(retc1, retc2)
387 self.CleanupTest()
388
389 def ConstructTest(self):
Aart Bik842a4f32016-09-21 15:45:18 -0700390 """Use JFuzz to generate next Test.java test.
Aart Bik7593b992016-08-17 16:51:12 -0700391
392 Raises:
Aart Bik842a4f32016-09-21 15:45:18 -0700393 FatalError: error when jfuzz fails
Aart Bik7593b992016-08-17 16:51:12 -0700394 """
Aart Bik842a4f32016-09-21 15:45:18 -0700395 if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
396 raise FatalError('Unexpected error while running JFuzz')
Aart Bik7593b992016-08-17 16:51:12 -0700397
398 def CheckForDivergence(self, retc1, retc2):
399 """Checks for divergences and updates statistics.
400
401 Args:
402 retc1: int, normalized return code of first runner
403 retc2: int, normalized return code of second runner
404 """
405 if retc1 == retc2:
406 # Non-divergent in return code.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700407 if retc1 == RetCode.SUCCESS:
Aart Bik7593b992016-08-17 16:51:12 -0700408 # Both compilations and runs were successful, inspect generated output.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700409 runner1_out = self._runner1.output_file
410 runner2_out = self._runner2.output_file
411 if not filecmp.cmp(runner1_out, runner2_out, shallow=False):
412 self.ReportDivergence(retc1, retc2, is_output_divergence=True)
Aart Bik7593b992016-08-17 16:51:12 -0700413 else:
414 self._num_success += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700415 elif retc1 == RetCode.TIMEOUT:
Aart Bik7593b992016-08-17 16:51:12 -0700416 self._num_timed_out += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700417 elif retc1 == RetCode.NOTCOMPILED:
Aart Bik7593b992016-08-17 16:51:12 -0700418 self._num_not_compiled += 1
419 else:
420 self._num_not_run += 1
421 else:
422 # Divergent in return code.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700423 self.ReportDivergence(retc1, retc2, is_output_divergence=False)
Aart Bik7593b992016-08-17 16:51:12 -0700424
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700425 def GetCurrentDivergenceDir(self):
426 return self._results_dir + '/divergence' + str(self._num_divergences)
427
428 def ReportDivergence(self, retc1, retc2, is_output_divergence):
Aart Bik7593b992016-08-17 16:51:12 -0700429 """Reports and saves a divergence."""
430 self._num_divergences += 1
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700431 print('\n' + str(self._num_divergences), end='')
432 if is_output_divergence:
433 print(' divergence in output')
434 else:
435 print(' divergence in return code: ' + retc1.name + ' vs. ' +
436 retc2.name)
Aart Bik7593b992016-08-17 16:51:12 -0700437 # Save.
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700438 ddir = self.GetCurrentDivergenceDir()
439 os.mkdir(ddir)
440 for f in glob('*.txt') + ['Test.java']:
441 shutil.copy(f, ddir)
442 # Maybe run bisection bug search.
443 if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
444 self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
445
446 def RunBisectionSearch(self, args, expected_retcode, expected_output,
447 runner_id):
448 ddir = self.GetCurrentDivergenceDir()
449 outfile_path = ddir + '/' + runner_id + '_bisection_out.txt'
450 logfile_path = ddir + '/' + runner_id + '_bisection_log.txt'
451 errfile_path = ddir + '/' + runner_id + '_bisection_err.txt'
452 args = list(args) + ['--logfile', logfile_path, '--cleanup']
453 args += ['--expected-retcode', expected_retcode.name]
454 if expected_output:
455 args += ['--expected-output', expected_output]
456 bisection_search_path = os.path.join(
457 GetEnvVariableOrError('ANDROID_BUILD_TOP'),
458 'art/tools/bisection_search/bisection_search.py')
459 if RunCommand([bisection_search_path] + args, out=outfile_path,
460 err=errfile_path, timeout=300) == RetCode.TIMEOUT:
461 print('Bisection search TIMEOUT')
462
463 def MaybeBisectDivergence(self, retc1, retc2, is_output_divergence):
464 bisection_args1 = self._runner1.GetBisectionSearchArgs()
465 bisection_args2 = self._runner2.GetBisectionSearchArgs()
466 if is_output_divergence:
467 maybe_output1 = self._runner1.output_file
468 maybe_output2 = self._runner2.output_file
469 else:
470 maybe_output1 = maybe_output2 = None
471 if bisection_args1 is not None:
472 self.RunBisectionSearch(bisection_args1, retc2, maybe_output2,
473 self._runner1.id)
474 if bisection_args2 is not None:
475 self.RunBisectionSearch(bisection_args2, retc1, maybe_output1,
476 self._runner2.id)
Aart Bik7593b992016-08-17 16:51:12 -0700477
478 def CleanupTest(self):
479 """Cleans up after a single test run."""
Aart Bik842a4f32016-09-21 15:45:18 -0700480 for file_name in os.listdir(self._jfuzz_dir):
481 file_path = os.path.join(self._jfuzz_dir, file_name)
Aart Bike0347482016-09-20 14:34:13 -0700482 if os.path.isfile(file_path):
483 os.unlink(file_path)
484 elif os.path.isdir(file_path):
485 shutil.rmtree(file_path)
Aart Bik7593b992016-08-17 16:51:12 -0700486
487
488def main():
489 # Handle arguments.
490 parser = argparse.ArgumentParser()
491 parser.add_argument('--num_tests', default=10000,
492 type=int, help='number of tests to run')
Aart Bikb16d4132016-08-19 15:45:11 -0700493 parser.add_argument('--device', help='target device serial number')
Aart Bik7593b992016-08-17 16:51:12 -0700494 parser.add_argument('--mode1', default='ri',
495 help='execution mode 1 (default: ri)')
496 parser.add_argument('--mode2', default='hopt',
497 help='execution mode 2 (default: hopt)')
498 args = parser.parse_args()
499 if args.mode1 == args.mode2:
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700500 raise FatalError('Identical execution modes given')
Aart Bik842a4f32016-09-21 15:45:18 -0700501 # Run the JFuzz tester.
502 with JFuzzTester(args.num_tests, args.device,
Aart Bikb16d4132016-08-19 15:45:11 -0700503 args.mode1, args.mode2) as fuzzer:
Aart Bik7593b992016-08-17 16:51:12 -0700504 fuzzer.Run()
505
Wojciech Staszkiewicz0d0fd4a2016-09-07 18:52:52 -0700506if __name__ == '__main__':
Aart Bik7593b992016-08-17 16:51:12 -0700507 main()