Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: tools/testrunner/local/progress.py

Issue 1171943002: [test] Refactoring - Use subject/observer pattern for progress indicators. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/testrunner/local/execution.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2012 the V8 project authors. All rights reserved. 1 # Copyright 2012 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without 2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are 3 # modification, are permitted provided that the following conditions are
4 # met: 4 # met:
5 # 5 #
6 # * Redistributions of source code must retain the above copyright 6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer. 7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above 8 # * Redistributions in binary form must reproduce the above
9 # copyright notice, this list of conditions and the following 9 # copyright notice, this list of conditions and the following
10 # disclaimer in the documentation and/or other materials provided 10 # disclaimer in the documentation and/or other materials provided
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 for part in command: 42 for part in command:
43 if ' ' in part: 43 if ' ' in part:
44 # Escape spaces. We may need to escape more characters for this 44 # Escape spaces. We may need to escape more characters for this
45 # to work properly. 45 # to work properly.
46 parts.append('"%s"' % part) 46 parts.append('"%s"' % part)
47 else: 47 else:
48 parts.append(part) 48 parts.append(part)
49 return " ".join(parts) 49 return " ".join(parts)
50 50
51 51
52 class IndicatorNotifier:
tandrii(chromium) 2015/06/09 09:18:01 inherit from "(object)"
Michael Achenbach 2015/06/09 12:47:14 Done.
53 """Holds a list of progress indicators and notifies them all on events."""
54 def __init__(self):
55 self.indicators = []
56
57 def register(self, indicator):
tandrii(chromium) 2015/06/09 09:18:01 nit: maybe Register for consistency with code arou
Michael Achenbach 2015/06/09 12:47:14 Done.
58 self.indicators.append(indicator)
59
60 def __getattr__(self, func_name):
61 """Generic event."""
tandrii(chromium) 2015/06/09 09:18:01 how about: """Generic event dispatcher.""" ? and
Michael Achenbach 2015/06/09 12:47:14 now changed design...
62 def func(*args, **kwargs):
63 for indicator in self.indicators:
64 getattr(indicator, func_name)(*args, **kwargs)
tandrii(chromium) 2015/06/09 09:18:01 maybe also add setattr(self, func_name, func) ?
Michael Achenbach 2015/06/09 12:47:14 now changed design...
65 return func
66
67
52 class ProgressIndicator(object): 68 class ProgressIndicator(object):
53 69
54 def __init__(self): 70 def SetRunner(self, runner):
tandrii(chromium) 2015/06/09 09:18:01 IMO, I'd keep the constructor. Am I right that Se
Jakob Kummerow 2015/06/09 09:49:51 Agreed. The constructor exists mostly for document
tandrii(chromium) 2015/06/09 10:14:34 I don't think setattr above will change anything,
Michael Achenbach 2015/06/09 12:47:14 I keep the constructor, but I also need the setter
tandrii(chromium) 2015/06/09 13:24:45 Acknowledged.
55 self.runner = None 71 self.runner = runner
56 72
57 def Starting(self): 73 def Starting(self):
58 pass 74 pass
59 75
60 def Done(self): 76 def Done(self):
61 pass 77 pass
62 78
63 def AboutToRun(self, test): 79 def AboutToRun(self, test):
64 pass 80 pass
65 81
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 'stderr': '%s', 260 'stderr': '%s',
245 } 261 }
246 super(MonochromeProgressIndicator, self).__init__(templates) 262 super(MonochromeProgressIndicator, self).__init__(templates)
247 263
248 def ClearLine(self, last_line_length): 264 def ClearLine(self, last_line_length):
249 print ("\r" + (" " * last_line_length) + "\r"), 265 print ("\r" + (" " * last_line_length) + "\r"),
250 266
251 267
252 class JUnitTestProgressIndicator(ProgressIndicator): 268 class JUnitTestProgressIndicator(ProgressIndicator):
253 269
254 def __init__(self, progress_indicator, junitout, junittestsuite): 270 def __init__(self, junitout, junittestsuite):
255 self.progress_indicator = progress_indicator
256 self.outputter = junit_output.JUnitTestOutput(junittestsuite) 271 self.outputter = junit_output.JUnitTestOutput(junittestsuite)
257 if junitout: 272 if junitout:
258 self.outfile = open(junitout, "w") 273 self.outfile = open(junitout, "w")
259 else: 274 else:
260 self.outfile = sys.stdout 275 self.outfile = sys.stdout
261 276
262 def Starting(self):
263 self.progress_indicator.runner = self.runner
264 self.progress_indicator.Starting()
265
266 def Done(self): 277 def Done(self):
267 self.progress_indicator.Done()
268 self.outputter.FinishAndWrite(self.outfile) 278 self.outputter.FinishAndWrite(self.outfile)
269 if self.outfile != sys.stdout: 279 if self.outfile != sys.stdout:
270 self.outfile.close() 280 self.outfile.close()
271 281
272 def AboutToRun(self, test):
273 self.progress_indicator.AboutToRun(test)
274
275 def HasRun(self, test, has_unexpected_output): 282 def HasRun(self, test, has_unexpected_output):
276 self.progress_indicator.HasRun(test, has_unexpected_output)
277 fail_text = "" 283 fail_text = ""
278 if has_unexpected_output: 284 if has_unexpected_output:
279 stdout = test.output.stdout.strip() 285 stdout = test.output.stdout.strip()
280 if len(stdout): 286 if len(stdout):
281 fail_text += "stdout:\n%s\n" % stdout 287 fail_text += "stdout:\n%s\n" % stdout
282 stderr = test.output.stderr.strip() 288 stderr = test.output.stderr.strip()
283 if len(stderr): 289 if len(stderr):
284 fail_text += "stderr:\n%s\n" % stderr 290 fail_text += "stderr:\n%s\n" % stderr
285 fail_text += "Command: %s" % EscapeCommand(self.runner.GetCommand(test)) 291 fail_text += "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
286 if test.output.HasCrashed(): 292 if test.output.HasCrashed():
287 fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code 293 fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code
288 if test.output.HasTimedOut(): 294 if test.output.HasTimedOut():
289 fail_text += "--- TIMEOUT ---" 295 fail_text += "--- TIMEOUT ---"
290 self.outputter.HasRunTest( 296 self.outputter.HasRunTest(
291 [test.GetLabel()] + self.runner.context.mode_flags + test.flags, 297 [test.GetLabel()] + self.runner.context.mode_flags + test.flags,
292 test.duration, 298 test.duration,
293 fail_text) 299 fail_text)
294 300
295 def Heartbeat(self):
296 self.progress_indicator.Heartbeat()
297 301
298 class JsonTestProgressIndicator(ProgressIndicator): 302 class JsonTestProgressIndicator(ProgressIndicator):
299 303
300 def __init__(self, progress_indicator, json_test_results, arch, mode): 304 def __init__(self, json_test_results, arch, mode):
301 self.progress_indicator = progress_indicator
302 self.json_test_results = json_test_results 305 self.json_test_results = json_test_results
303 self.arch = arch 306 self.arch = arch
304 self.mode = mode 307 self.mode = mode
305 self.results = [] 308 self.results = []
306 self.tests = [] 309 self.tests = []
307 310
308 def Starting(self):
309 self.progress_indicator.runner = self.runner
310 self.progress_indicator.Starting()
311
312 def Done(self): 311 def Done(self):
313 self.progress_indicator.Done()
314 complete_results = [] 312 complete_results = []
315 if os.path.exists(self.json_test_results): 313 if os.path.exists(self.json_test_results):
316 with open(self.json_test_results, "r") as f: 314 with open(self.json_test_results, "r") as f:
317 # Buildbot might start out with an empty file. 315 # Buildbot might start out with an empty file.
318 complete_results = json.loads(f.read() or "[]") 316 complete_results = json.loads(f.read() or "[]")
319 317
320 # Sort tests by duration. 318 # Sort tests by duration.
321 timed_tests = [t for t in self.tests if t.duration is not None] 319 timed_tests = [t for t in self.tests if t.duration is not None]
322 timed_tests.sort(lambda a, b: cmp(b.duration, a.duration)) 320 timed_tests.sort(lambda a, b: cmp(b.duration, a.duration))
323 slowest_tests = [ 321 slowest_tests = [
324 { 322 {
325 "name": test.GetLabel(), 323 "name": test.GetLabel(),
326 "flags": test.flags, 324 "flags": test.flags,
327 "command": EscapeCommand(self.runner.GetCommand(test)).replace( 325 "command": EscapeCommand(self.runner.GetCommand(test)).replace(
328 ABS_PATH_PREFIX, ""), 326 ABS_PATH_PREFIX, ""),
329 "duration": test.duration, 327 "duration": test.duration,
330 } for test in timed_tests[:20] 328 } for test in timed_tests[:20]
331 ] 329 ]
332 330
333 complete_results.append({ 331 complete_results.append({
334 "arch": self.arch, 332 "arch": self.arch,
335 "mode": self.mode, 333 "mode": self.mode,
336 "results": self.results, 334 "results": self.results,
337 "slowest_tests": slowest_tests, 335 "slowest_tests": slowest_tests,
338 }) 336 })
339 337
340 with open(self.json_test_results, "w") as f: 338 with open(self.json_test_results, "w") as f:
341 f.write(json.dumps(complete_results)) 339 f.write(json.dumps(complete_results))
342 340
343 def AboutToRun(self, test):
344 self.progress_indicator.AboutToRun(test)
345
346 def HasRun(self, test, has_unexpected_output): 341 def HasRun(self, test, has_unexpected_output):
347 self.progress_indicator.HasRun(test, has_unexpected_output)
348 # Buffer all tests for sorting the durations in the end. 342 # Buffer all tests for sorting the durations in the end.
349 self.tests.append(test) 343 self.tests.append(test)
350 if not has_unexpected_output: 344 if not has_unexpected_output:
351 # Omit tests that run as expected. Passing tests of reruns after failures 345 # Omit tests that run as expected. Passing tests of reruns after failures
352 # will have unexpected_output to be reported here has well. 346 # will have unexpected_output to be reported here has well.
353 return 347 return
354 348
355 self.results.append({ 349 self.results.append({
356 "name": test.GetLabel(), 350 "name": test.GetLabel(),
357 "flags": test.flags, 351 "flags": test.flags,
358 "command": EscapeCommand(self.runner.GetCommand(test)).replace( 352 "command": EscapeCommand(self.runner.GetCommand(test)).replace(
359 ABS_PATH_PREFIX, ""), 353 ABS_PATH_PREFIX, ""),
360 "run": test.run, 354 "run": test.run,
361 "stdout": test.output.stdout, 355 "stdout": test.output.stdout,
362 "stderr": test.output.stderr, 356 "stderr": test.output.stderr,
363 "exit_code": test.output.exit_code, 357 "exit_code": test.output.exit_code,
364 "result": test.suite.GetOutcome(test), 358 "result": test.suite.GetOutcome(test),
365 "expected": list(test.outcomes or ["PASS"]), 359 "expected": list(test.outcomes or ["PASS"]),
366 "duration": test.duration, 360 "duration": test.duration,
367 }) 361 })
368 362
369 def Heartbeat(self):
370 self.progress_indicator.Heartbeat()
371
372 363
373 PROGRESS_INDICATORS = { 364 PROGRESS_INDICATORS = {
374 'verbose': VerboseProgressIndicator, 365 'verbose': VerboseProgressIndicator,
375 'dots': DotsProgressIndicator, 366 'dots': DotsProgressIndicator,
376 'color': ColorProgressIndicator, 367 'color': ColorProgressIndicator,
377 'mono': MonochromeProgressIndicator 368 'mono': MonochromeProgressIndicator
378 } 369 }
OLDNEW
« no previous file with comments | « tools/testrunner/local/execution.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698