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

Side by Side Diff: chrome/test/kasko/hang_watcher_integration_test.py

Issue 1543803005: Added an integration test for kasko hang reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 12 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
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """A Windows-only end-to-end integration test for Kasko, Chrome and Crashpad. 6 """A Windows-only end-to-end integration test for the Kasko hang watcher.
7 7
8 This test ensures that the interface between Kasko and Chrome and Crashpad works 8 This test ensures that Kasko is able to detect when Chrome is hanged and to
9 as expected. The test causes Kasko to set certain crash keys and invoke a crash 9 generate a report. The report is then delivered to a locally hosted test crash
10 report, which is in turn delivered to a locally hosted test crash server. If the 10 server. If a crash report is received then all is well.
11 crash report is received intact with the expected crash keys then all is well.
12 11
13 Note that this test only works against non-component Release and Official builds 12 Note that this test only works against non-component Release and Official builds
14 of Chrome with Chrome branding, and attempting to use it with anything else will 13 of Chrome with Chrome branding, and attempting to use it with anything else will
15 most likely lead to constant failures. 14 most likely lead to constant failures.
16 15
17 Typical usage (assuming in root 'src' directory): 16 Typical usage (assuming in root 'src' directory):
18 17
19 - generate project files with the following GYP variables: 18 - generate project files with the following GYP variables:
20 branding=Chrome syzyasan=1 win_z7=0 chromium_win_pch=0 19 branding=Chrome kasko=1 kasko_hang_reports=1
21 - build the release Chrome binaries: 20 - build the release Chrome binaries and driver:
22 ninja -C out\Release chrome.exe 21 ninja -C out\Release chrome.exe
22 ninja -C out\Release chromedriver.exe
23 - run the test: 23 - run the test:
24 python chrome/test/kasko/kasko_integration_test.py --chrome-dir=out/Release 24 python chrome/test/kasko/kasko_integration_test.py
25 25
26 Many of the components in this test could be reused in other end-to-end crash 26 Many of the components in this test could be reused in other end-to-end crash
27 testing. Feel free to open them up for reuse, but please CC chrisha@chromium.org 27 testing. Feel free to open them up for reuse, but please CC chrisha@chromium.org
28 on any associated reviews or bugs! 28 on any associated reviews or bugs!
29 """ 29 """
30 30
31 import BaseHTTPServer 31 import BaseHTTPServer
32 import cgi 32 import cgi
33 import logging 33 import logging
34 import os 34 import os
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 343
344 return t 344 return t
345 345
346 346
347 def _GetProcessCreationDate(pid): 347 def _GetProcessCreationDate(pid):
348 """Returns the process creation date as local unix epoch time.""" 348 """Returns the process creation date as local unix epoch time."""
349 wmi = win32com.client.GetObject('winmgmts:') 349 wmi = win32com.client.GetObject('winmgmts:')
350 procs = wmi.ExecQuery( 350 procs = wmi.ExecQuery(
351 'select CreationDate from Win32_Process where ProcessId = %s' % pid) 351 'select CreationDate from Win32_Process where ProcessId = %s' % pid)
352 for proc in procs: 352 for proc in procs:
353 return _WmiTimeToLocalEpoch(proc.Properties_['CreationDate'].Value) 353 print _WmiTimeToLocalEpoch(proc.Properties_('CreationDate').Value)
354 return _WmiTimeToLocalEpoch(proc.Properties_('CreationDate').Value)
354 raise Exception('Unable to find process with PID %d.' % pid) 355 raise Exception('Unable to find process with PID %d.' % pid)
355 356
356 357
357 def _ShutdownChildren(parent_pid, child_exe, started_after, started_before, 358 def _ShutdownChildren(parent_pid, child_exe, started_after, started_before,
358 timeout=_DEFAULT_TIMEOUT, force=False): 359 timeout=_DEFAULT_TIMEOUT, force=False):
359 """Shuts down any lingering child processes of a given parent. 360 """Shuts down any lingering child processes of a given parent.
360 361
361 This is an inherently racy thing to do as process IDs are aggressively reused 362 This is an inherently racy thing to do as process IDs are aggressively reused
362 on Windows. Filtering by a valid known |started_after| and |started_before| 363 on Windows. Filtering by a valid known |started_after| and |started_before|
363 timestamp, as well as by the executable of the child process resolves this 364 timestamp, as well as by the executable of the child process resolves this
364 issue. Ugh. 365 issue. Ugh.
365 """ 366 """
366 started = time.time() 367 started = time.time()
367 wmi = win32com.client.GetObject('winmgmts:') 368 wmi = win32com.client.GetObject('winmgmts:')
368 _LOGGER.debug('Shutting down lingering children processes.') 369 _LOGGER.debug('Shutting down lingering children processes.')
369 for proc in wmi.InstancesOf('Win32_Process'): 370 for proc in wmi.InstancesOf('Win32_Process'):
370 if proc.Properties_['ParentProcessId'].Value != parent_pid: 371 if proc.Properties_('ParentProcessId').Value != parent_pid:
Patrick Monette 2015/12/23 17:24:46 chrisha: Does this work on your PC?
371 continue 372 continue
372 if proc.Properties_['ExecutablePath'].Value != child_exe: 373 if proc.Properties_('ExecutablePath').Value != child_exe:
373 continue 374 continue
374 t = _WmiTimeToLocalEpoch(proc.Properties_['CreationDate'].Value) 375 t = _WmiTimeToLocalEpoch(proc.Properties_('CreationDate').Value)
375 if t <= started_after or t >= started_before: 376 if t <= started_after or t >= started_before:
376 continue 377 continue
377 pid = proc.Properties_['ProcessId'].Value 378 pid = proc.Properties_('ProcessId').Value
378 remaining = max(0, started + timeout - time.time()) 379 remaining = max(0, started + timeout - time.time())
379 _ShutdownProcess(pid, remaining, force=force) 380 _ShutdownProcess(pid, remaining, force=force)
380 381
381 382
382 class _ChromeInstance(object): 383 class _ChromeInstance(object):
383 """A class encapsulating a running instance of Chrome for testing.""" 384 """A class encapsulating a running instance of Chrome for testing."""
384 385
385 def __init__(self, chromedriver, chrome, user_data_dir): 386 def __init__(self, chromedriver, chrome, user_data_dir):
386 self.chromedriver_ = os.path.abspath(chromedriver) 387 self.chromedriver_ = os.path.abspath(chromedriver)
387 self.chrome_ = os.path.abspath(chrome) 388 self.chrome_ = os.path.abspath(chrome)
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 525
525 # Launch the test server. 526 # Launch the test server.
526 server = _CrashServer() 527 server = _CrashServer()
527 with _ScopedStartStop(server): 528 with _ScopedStartStop(server):
528 _LOGGER.info('Started server on port %d', server.port) 529 _LOGGER.info('Started server on port %d', server.port)
529 530
530 # Configure the environment so Chrome can find the test crash server. 531 # Configure the environment so Chrome can find the test crash server.
531 os.environ['KASKO_CRASH_SERVER_URL'] = ( 532 os.environ['KASKO_CRASH_SERVER_URL'] = (
532 'http://127.0.0.1:%d/crash' % server.port) 533 'http://127.0.0.1:%d/crash' % server.port)
533 534
534 # Launch Chrome and navigate it to the test URL. 535 # Launch Chrome and navigate to the hang URL.
535 chrome = _ChromeInstance(options.chromedriver, options.chrome, 536 chrome = _ChromeInstance(options.chromedriver, options.chrome,
536 user_data_dir) 537 user_data_dir)
537 with _ScopedStartStop(chrome): 538 with _ScopedStartStop(chrome):
538 _LOGGER.info('Navigating to Kasko debug URL') 539 _LOGGER.info('Navigating to the hang debug url')
539 chrome.navigate_to('chrome://kasko/send-report') 540 chrome.navigate_to('chrome://uithreadhang')
540 541
541 _LOGGER.info('Waiting for Kasko report') 542 _LOGGER.info('Waiting for Kasko report')
542 if not server.wait_for_report(10):
543 raise Exception('No Kasko report received.')
544 543
545 report = server.crash(0) 544 # The report can take as long as 80 seconds to be generated because
546 for (key, value) in report.iteritems(): 545 # the polling is done every 60 seconds and the watcher gives 20
547 val = value[0] 546 # seconds to Chrome to ping back before being considered hanged.
548 if (len(val) < 64): 547 if not server.wait_for_report(120):
549 _LOGGER.debug('Got crashkey "%s": "%s"', key, val) 548 raise Exception('No Kasko report received')
550 else: 549
551 _LOGGER.debug('Got crashkey "%s": ...%d bytes...', key, len(val)) 550 _LOGGER.info('Received Kasko report successfully')
552 kasko_key = 'kasko-set-crash-key-value-impl' 551 # TODO(pmonette): Verify that the report contains the crash keys that
553 if kasko_key not in report: 552 # are expected when they will work.
554 _LOGGER.error('Missing expected "%s" crash key.', kasko_key)
555 raise Exception('SendCrashKeyValueImpl integration appears broken.')
556 553
557 return 0 554 return 0
558 555
559 556
560 if __name__ == '__main__': 557 if __name__ == '__main__':
561 sys.exit(Main()) 558 sys.exit(Main())
OLDNEW
« no previous file with comments | « chrome/chrome_watcher/chrome_watcher_main_api.h ('k') | chrome/test/kasko/kasko_integration_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698