1 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import contextlib 6 import fcntl 7 import glob 8 import logging 9 import os 10 import re 11 import shutil 12 13 import common 14 from autotest_lib.client.bin import test, utils 15 from autotest_lib.client.common_lib import error 16 from autotest_lib.client.cros import constants, cros_logging 17 18 19 class CrashTest(test.test): 20 """ 21 This class deals with running crash tests, which are tests which crash a 22 user-space program (or the whole machine) and generate a core dump. We 23 want to check that the correct crash dump is available and can be 24 retrieved. 25 26 Chromium OS has a crash sender which checks for new crash data and sends 27 it to a server. This crash data is used to track software quality and find 28 bugs. The system crash sender normally is always running, but can be paused 29 by creating _PAUSE_FILE. When crash sender sees this, it pauses operation. 30 31 The pid of the system crash sender is stored in _CRASH_SENDER_RUN_PATH so 32 we can use this to kill the system crash sender for when we want to run 33 our own. 34 35 For testing purposes we sometimes want to run the crash sender manually. 36 In this case we can set 'OVERRIDE_PAUSE_SENDING=1' in the environment and 37 run the crash sender manually (as a child process). 38 39 Also for testing we sometimes want to mock out the crash sender, and just 40 have it pretend to succeed or fail. The _MOCK_CRASH_SENDING file is used 41 for this. If it doesn't exist, then the crash sender runs normally. If 42 it exists but is empty, the crash sender will succeed (but actually do 43 nothing). If the file contains something, then the crash sender will fail. 44 45 If the user consents to sending crash tests, then the _CONSENT_FILE will 46 exist in the home directory. This test needs to create this file for the 47 crash sending to work. 48 49 Crash reports are rate limited to a certain number of reports each 24 50 hours. If the maximum number has already been sent then reports are held 51 until later. This is administered by a directory _CRASH_SENDER_RATE_DIR 52 which contains one temporary file for each time a report is sent. 53 54 The class provides the ability to push a consent file. This disables 55 consent for this test but allows it to be popped back at later. This 56 makes nested tests easier. If _automatic_consent_saving is True (the 57 default) then consent will be pushed at the start and popped at the end. 58 59 Interesting variables: 60 _log_reader: the log reader used for reading log files 61 _leave_crash_sending: True to enable crash sending on exit from the 62 test, False to disable it. (Default True). 63 _automatic_consent_saving: True to push the consent at the start of 64 the test and pop it afterwards. (Default True). 65 66 Useful places to look for more information are: 67 68 chromeos/src/platform/crash-reporter/crash_sender 69 - sender script which crash crash reporter to create reports, then 70 71 chromeos/src/platform/crash-reporter/ 72 - crash reporter program 73 """ 74 75 76 _CONSENT_FILE = '/home/chronos/Consent To Send Stats' 77 _CORE_PATTERN = '/proc/sys/kernel/core_pattern' 78 _CRASH_REPORTER_PATH = '/sbin/crash_reporter' 79 _CRASH_SENDER_PATH = '/sbin/crash_sender' 80 _CRASH_SENDER_RATE_DIR = '/var/lib/crash_sender' 81 _CRASH_SENDER_RUN_PATH = '/run/crash_sender.pid' 82 _CRASH_SENDER_LOCK_PATH = '/run/lock/crash_sender' 83 _CRASH_RUN_STATE_DIR = '/run/crash_reporter' 84 _CRASH_TEST_IN_PROGRESS = _CRASH_RUN_STATE_DIR + '/crash-test-in-progress' 85 _MOCK_CRASH_SENDING = _CRASH_RUN_STATE_DIR + '/mock-crash-sending' 86 _PAUSE_FILE = '/var/lib/crash_sender_paused' 87 _SYSTEM_CRASH_DIR = '/var/spool/crash' 88 _FALLBACK_USER_CRASH_DIR = '/home/chronos/crash' 89 _USER_CRASH_DIRS = '/home/chronos/u-*/crash' 90 _USER_CRASH_DIR_REGEX = re.compile('/home/chronos/u-([a-f0-9]+)/crash') 91 92 # Use the same file format as crash does normally: 93 # <basename>.#.#.#.meta 94 _FAKE_TEST_BASENAME = 'fake.1.2.3' 95 96 def _set_system_sending(self, is_enabled): 97 """Sets whether or not the system crash_sender is allowed to run. 98 99 This is done by creating or removing _PAUSE_FILE. 100 101 crash_sender may still be allowed to run if _set_child_sending is 102 called with True and it is run as a child process. 103 104 @param is_enabled: True to enable crash_sender, False to disable it. 105 """ 106 if is_enabled: 107 if os.path.exists(self._PAUSE_FILE): 108 os.remove(self._PAUSE_FILE) 109 else: 110 utils.system('touch ' + self._PAUSE_FILE) 111 112 113 def _set_child_sending(self, is_enabled): 114 """Overrides crash sending enabling for child processes. 115 116 When the system crash sender is disabled this test can manually run 117 the crash sender as a child process. Normally this would do nothing, 118 but this function sets up crash_sender to ignore its disabled status 119 and do its job. 120 121 @param is_enabled: True to enable crash sending for child processes. 122 """ 123 if is_enabled: 124 os.environ['OVERRIDE_PAUSE_SENDING'] = "1" 125 else: 126 del os.environ['OVERRIDE_PAUSE_SENDING'] 127 128 129 def _set_force_official(self, is_enabled): 130 """Sets whether or not reports will upload for unofficial versions. 131 132 Normally, crash reports are only uploaded for official build 133 versions. If the override is set, however, they will also be 134 uploaded for unofficial versions. 135 136 @param is_enabled: True to enable uploading for unofficial versions. 137 """ 138 if is_enabled: 139 os.environ['FORCE_OFFICIAL'] = "1" 140 elif os.environ.get('FORCE_OFFICIAL'): 141 del os.environ['FORCE_OFFICIAL'] 142 143 144 def _set_mock_developer_mode(self, is_enabled): 145 """Sets whether or not we should pretend we booted in developer mode. 146 147 @param is_enabled: True to pretend we are in developer mode. 148 """ 149 if is_enabled: 150 os.environ['MOCK_DEVELOPER_MODE'] = "1" 151 elif os.environ.get('MOCK_DEVELOPER_MODE'): 152 del os.environ['MOCK_DEVELOPER_MODE'] 153 154 155 def _reset_rate_limiting(self): 156 """Reset the count of crash reports sent today. 157 158 This clears the contents of the rate limiting directory which has 159 the effect of reseting our count of crash reports sent. 160 """ 161 utils.system('rm -rf ' + self._CRASH_SENDER_RATE_DIR) 162 163 164 def _clear_spooled_crashes(self): 165 """Clears system and user crash directories. 166 167 This will remove all crash reports which are waiting to be sent. 168 """ 169 utils.system('rm -rf ' + self._SYSTEM_CRASH_DIR) 170 utils.system('rm -rf %s %s' % (self._USER_CRASH_DIRS, 171 self._FALLBACK_USER_CRASH_DIR)) 172 173 174 def _kill_running_sender(self): 175 """Kill the the crash_sender process if running. 176 177 We use the PID file to find the process ID, then kill it with signal 9. 178 """ 179 if not os.path.exists(self._CRASH_SENDER_RUN_PATH): 180 return 181 running_pid = int(utils.read_file(self._CRASH_SENDER_RUN_PATH)) 182 logging.warning('Detected running crash sender (%d), killing', 183 running_pid) 184 utils.system('kill -9 %d' % running_pid) 185 os.remove(self._CRASH_SENDER_RUN_PATH) 186 187 188 def _set_sending_mock(self, mock_enabled, send_success=True): 189 """Enables / disables mocking of the sending process. 190 191 This uses the _MOCK_CRASH_SENDING file to achieve its aims. See notes 192 at the top. 193 194 @param mock_enabled: If True, mocking is enabled, else it is disabled. 195 @param send_success: If mock_enabled this is True for the mocking to 196 indicate success, False to indicate failure. 197 """ 198 if mock_enabled: 199 if send_success: 200 data = '' 201 else: 202 data = '1' 203 logging.info('Setting sending mock') 204 utils.open_write_close(self._MOCK_CRASH_SENDING, data) 205 else: 206 utils.system('rm -f ' + self._MOCK_CRASH_SENDING) 207 208 209 def _set_consent(self, has_consent): 210 """Sets whether or not we have consent to send crash reports. 211 212 This creates or deletes the _CONSENT_FILE to control whether 213 crash_sender will consider that it has consent to send crash reports. 214 It also copies a policy blob with the proper policy setting. 215 216 @param has_consent: True to indicate consent, False otherwise 217 """ 218 autotest_cros_dir = os.path.join(os.path.dirname(__file__), '..') 219 if has_consent: 220 if os.path.isdir(constants.WHITELIST_DIR): 221 # Create policy file that enables metrics/consent. 222 shutil.copy('%s/mock_metrics_on.policy' % autotest_cros_dir, 223 constants.SIGNED_POLICY_FILE) 224 shutil.copy('%s/mock_metrics_owner.key' % autotest_cros_dir, 225 constants.OWNER_KEY_FILE) 226 # Create deprecated consent file. This is created *after* the 227 # policy file in order to avoid a race condition where chrome 228 # might remove the consent file if the policy's not set yet. 229 # We create it as a temp file first in order to make the creation 230 # of the consent file, owned by chronos, atomic. 231 # See crosbug.com/18413. 232 temp_file = self._CONSENT_FILE + '.tmp'; 233 utils.open_write_close(temp_file, 'test-consent') 234 utils.system('chown chronos:chronos "%s"' % (temp_file)) 235 shutil.move(temp_file, self._CONSENT_FILE) 236 logging.info('Created ' + self._CONSENT_FILE) 237 else: 238 if os.path.isdir(constants.WHITELIST_DIR): 239 # Create policy file that disables metrics/consent. 240 shutil.copy('%s/mock_metrics_off.policy' % autotest_cros_dir, 241 constants.SIGNED_POLICY_FILE) 242 shutil.copy('%s/mock_metrics_owner.key' % autotest_cros_dir, 243 constants.OWNER_KEY_FILE) 244 # Remove deprecated consent file. 245 utils.system('rm -f "%s"' % (self._CONSENT_FILE)) 246 247 248 def _set_crash_test_in_progress(self, in_progress): 249 if in_progress: 250 utils.open_write_close(self._CRASH_TEST_IN_PROGRESS, 'in-progress') 251 logging.info('Created ' + self._CRASH_TEST_IN_PROGRESS) 252 else: 253 utils.system('rm -f "%s"' % (self._CRASH_TEST_IN_PROGRESS)) 254 255 256 def _get_pushed_consent_file_path(self): 257 """Returns filename of the pushed consent file.""" 258 return os.path.join(self.bindir, 'pushed_consent') 259 260 261 def _get_pushed_policy_file_path(self): 262 """Returns filename of the pushed policy file.""" 263 return os.path.join(self.bindir, 'pushed_policy') 264 265 266 def _get_pushed_owner_key_file_path(self): 267 """Returns filename of the pushed owner.key file.""" 268 return os.path.join(self.bindir, 'pushed_owner_key') 269 270 271 def _push_consent(self): 272 """Push the consent file, thus disabling consent. 273 274 The consent files can be created in the new test if required. Call 275 _pop_consent() to restore the original state. 276 """ 277 if os.path.exists(self._CONSENT_FILE): 278 shutil.move(self._CONSENT_FILE, 279 self._get_pushed_consent_file_path()) 280 if os.path.exists(constants.SIGNED_POLICY_FILE): 281 shutil.move(constants.SIGNED_POLICY_FILE, 282 self._get_pushed_policy_file_path()) 283 if os.path.exists(constants.OWNER_KEY_FILE): 284 shutil.move(constants.OWNER_KEY_FILE, 285 self._get_pushed_owner_key_file_path()) 286 287 288 def _pop_consent(self): 289 """Pop the consent files, enabling/disabling consent as it was before 290 we pushed the consent.""" 291 if os.path.exists(self._get_pushed_consent_file_path()): 292 shutil.move(self._get_pushed_consent_file_path(), 293 self._CONSENT_FILE) 294 else: 295 utils.system('rm -f "%s"' % self._CONSENT_FILE) 296 if os.path.exists(self._get_pushed_policy_file_path()): 297 shutil.move(self._get_pushed_policy_file_path(), 298 constants.SIGNED_POLICY_FILE) 299 else: 300 utils.system('rm -f "%s"' % constants.SIGNED_POLICY_FILE) 301 if os.path.exists(self._get_pushed_owner_key_file_path()): 302 shutil.move(self._get_pushed_owner_key_file_path(), 303 constants.OWNER_KEY_FILE) 304 else: 305 utils.system('rm -f "%s"' % constants.OWNER_KEY_FILE) 306 307 308 def _get_crash_dir(self, username, force_user_crash_dir=False): 309 """Returns crash directory for process running as the given user. 310 311 @param username: Unix user of the crashing process. 312 @param force_user_crash_dir: Regardless of |username|, return the crash 313 directory of the current user session, or 314 the fallback directory if no sessions. 315 """ 316 if username == 'root' and not force_user_crash_dir: 317 return self._SYSTEM_CRASH_DIR 318 else: 319 dirs = glob.glob(self._USER_CRASH_DIRS) 320 return dirs[0] if dirs else self._FALLBACK_USER_CRASH_DIR 321 322 323 def _canonicalize_crash_dir(self, crash_dir): 324 """Converts /home/chronos crash directory to /home/user counterpart. 325 326 @param crash_dir: A path of the form /home/chronos/u-<hash>/crash. 327 @returns /home/user/<hash>/crash, or |crash_dir| on form mismatch. 328 """ 329 match = re.match(self._USER_CRASH_DIR_REGEX, crash_dir) 330 return ('/home/user/%s/crash' % match.group(1)) if match else crash_dir 331 332 333 def _initialize_crash_reporter(self): 334 """Start up the crash reporter.""" 335 utils.system('%s --init' % self._CRASH_REPORTER_PATH) 336 # Completely disable crash_reporter from generating crash dumps 337 # while any tests are running, otherwise a crashy system can make 338 # these tests flaky. 339 self.enable_crash_filtering('none') 340 341 342 def get_crash_dir_name(self, name): 343 """Return the full path for |name| inside the system crash directory.""" 344 return os.path.join(self._SYSTEM_CRASH_DIR, name) 345 346 347 def write_crash_dir_entry(self, name, contents): 348 """Writes an empty file to the system crash directory. 349 350 This writes a file to _SYSTEM_CRASH_DIR with the given name. This is 351 used to insert new crash dump files for testing purposes. 352 353 @param name: Name of file to write. 354 @param contents: String to write to the file. 355 """ 356 entry = self.get_crash_dir_name(name) 357 if not os.path.exists(self._SYSTEM_CRASH_DIR): 358 os.makedirs(self._SYSTEM_CRASH_DIR) 359 utils.open_write_close(entry, contents) 360 return entry 361 362 363 def write_fake_meta(self, name, exec_name, payload, log=None, 364 complete=True): 365 """Writes a fake meta entry to the system crash directory. 366 367 @param name: Name of file to write. 368 @param exec_name: Value for exec_name item. 369 @param payload: Value for payload item. 370 @param log: Value for log item. 371 @param complete: True to close off the record, otherwise leave it 372 incomplete. 373 """ 374 last_line = '' 375 if complete: 376 last_line = 'done=1\n' 377 contents = ('exec_name=%s\n' 378 'ver=my_ver\n' 379 'payload=%s\n' 380 '%s' % (exec_name, payload, 381 last_line)) 382 if log: 383 contents = ('log=%s\n' % log) + contents 384 return self.write_crash_dir_entry(name, contents) 385 386 387 def _prepare_sender_one_crash(self, 388 send_success, 389 reports_enabled, 390 report): 391 """Create metadata for a fake crash report. 392 393 This enabled mocking of the crash sender, then creates a fake 394 crash report for testing purposes. 395 396 @param send_success: True to make the crash_sender success, False to 397 make it fail. 398 @param reports_enabled: True to enable consent to that reports will be 399 sent. 400 @param report: Report to use for crash, if None we create one. 401 """ 402 self._set_sending_mock(mock_enabled=True, send_success=send_success) 403 self._set_consent(reports_enabled) 404 if report is None: 405 # Use the same file format as crash does normally: 406 # <basename>.#.#.#.meta 407 payload = self.write_crash_dir_entry( 408 '%s.dmp' % self._FAKE_TEST_BASENAME, '') 409 report = self.write_fake_meta( 410 '%s.meta' % self._FAKE_TEST_BASENAME, 'fake', payload) 411 return report 412 413 414 def _parse_sender_output(self, output): 415 """Parse the log output from the crash_sender script. 416 417 This script can run on the logs from either a mocked or true 418 crash send. 419 420 @param output: output from the script 421 422 @returns A dictionary with these values: 423 error_type: an error type, if given 424 exec_name: name of executable which crashed 425 image_type: type of image ("dev","force-official",...), if given 426 boot_mode: current boot mode ("dev",...), if given 427 meta_path: path to the report metadata file 428 output: the output from the script, copied 429 report_kind: kind of report sent (minidump vs kernel) 430 send_attempt: did the script attempt to send a crash. 431 send_success: if it attempted, was the crash send successful. 432 sig: signature of the report, if given. 433 sleep_time: if it attempted, how long did it sleep before 434 sending (if mocked, how long would it have slept) 435 """ 436 sleep_match = re.search('Scheduled to send in (\d+)s', output) 437 send_attempt = sleep_match is not None 438 if send_attempt: 439 sleep_time = int(sleep_match.group(1)) 440 else: 441 sleep_time = None 442 443 meta_match = re.search('Metadata: (\S+) \((\S+)\)', output) 444 if meta_match: 445 meta_path = meta_match.group(1) 446 report_kind = meta_match.group(2) 447 else: 448 meta_path = None 449 report_kind = None 450 451 payload_match = re.search('Payload: (\S+)', output) 452 if payload_match: 453 report_payload = payload_match.group(1) 454 else: 455 report_payload = None 456 457 exec_name_match = re.search('Exec name: (\S+)', output) 458 if exec_name_match: 459 exec_name = exec_name_match.group(1) 460 else: 461 exec_name = None 462 463 sig_match = re.search('sig: (\S+)', output) 464 if sig_match: 465 sig = sig_match.group(1) 466 else: 467 sig = None 468 469 error_type_match = re.search('Error type: (\S+)', output) 470 if error_type_match: 471 error_type = error_type_match.group(1) 472 else: 473 error_type = None 474 475 image_type_match = re.search('Image type: (\S+)', output) 476 if image_type_match: 477 image_type = image_type_match.group(1) 478 else: 479 image_type = None 480 481 boot_mode_match = re.search('Boot mode: (\S+)', output) 482 if boot_mode_match: 483 boot_mode = boot_mode_match.group(1) 484 else: 485 boot_mode = None 486 487 send_success = 'Mocking successful send' in output 488 return {'exec_name': exec_name, 489 'report_kind': report_kind, 490 'meta_path': meta_path, 491 'report_payload': report_payload, 492 'send_attempt': send_attempt, 493 'send_success': send_success, 494 'sig': sig, 495 'error_type': error_type, 496 'image_type': image_type, 497 'boot_mode': boot_mode, 498 'sleep_time': sleep_time, 499 'output': output} 500 501 502 def wait_for_sender_completion(self): 503 """Wait for crash_sender to complete. 504 505 Wait for no crash_sender's last message to be placed in the 506 system log before continuing and for the process to finish. 507 Otherwise we might get only part of the output.""" 508 utils.poll_for_condition( 509 lambda: self._log_reader.can_find('crash_sender done.'), 510 timeout=60, 511 exception=error.TestError( 512 'Timeout waiting for crash_sender to emit done: ' + 513 self._log_reader.get_logs())) 514 utils.poll_for_condition( 515 lambda: utils.system('pgrep crash_sender', 516 ignore_status=True) != 0, 517 timeout=60, 518 exception=error.TestError( 519 'Timeout waiting for crash_sender to finish: ' + 520 self._log_reader.get_logs())) 521 522 523 def _call_sender_one_crash(self, 524 send_success=True, 525 reports_enabled=True, 526 report=None, 527 should_fail=False): 528 """Call the crash sender script to mock upload one crash. 529 530 @param send_success: Mock a successful send if true 531 @param reports_enabled: Has the user consented to sending crash reports. 532 @param report: report to use for crash, if None we create one. 533 534 @returns a dictionary describing the result with the keys 535 from _parse_sender_output, as well as: 536 report_exists: does the minidump still exist after calling 537 send script 538 rate_count: how many crashes have been uploaded in the past 539 24 hours. 540 """ 541 report = self._prepare_sender_one_crash(send_success, 542 reports_enabled, 543 report) 544 self._log_reader.set_start_by_current() 545 script_output = "" 546 try: 547 script_output = utils.system_output( 548 '%s 2>&1' % self._CRASH_SENDER_PATH, 549 ignore_status=should_fail) 550 except error.CmdError as err: 551 raise error.TestFail('"%s" returned an unexpected non-zero ' 552 'value (%s).' 553 % (err.command, err.result_obj.exit_status)) 554 555 self.wait_for_sender_completion() 556 output = self._log_reader.get_logs() 557 logging.debug('Crash sender message output:\n' + output) 558 559 if script_output != '': 560 logging.debug('crash_sender stdout/stderr: ' + script_output) 561 562 if os.path.exists(report): 563 report_exists = True 564 os.remove(report) 565 else: 566 report_exists = False 567 if os.path.exists(self._CRASH_SENDER_RATE_DIR): 568 rate_count = len(os.listdir(self._CRASH_SENDER_RATE_DIR)) 569 else: 570 rate_count = 0 571 572 result = self._parse_sender_output(output) 573 result['report_exists'] = report_exists 574 result['rate_count'] = rate_count 575 576 # Show the result for debugging but remove 'output' key 577 # since it's large and earlier in debug output. 578 debug_result = dict(result) 579 del debug_result['output'] 580 logging.debug('Result of send (besides output): %s', debug_result) 581 582 return result 583 584 585 def _replace_crash_reporter_filter_in(self, new_parameter): 586 """Replaces the --filter_in= parameter of the crash reporter. 587 588 The kernel is set up to call the crash reporter with the core dump 589 as stdin when a process dies. This function adds a filter to the 590 command line used to call the crash reporter. This is used to ignore 591 crashes in which we have no interest. 592 593 This removes any --filter_in= parameter and optionally replaces it 594 with a new one. 595 596 @param new_parameter: This is parameter to add to the command line 597 instead of the --filter_in=... that was there. 598 """ 599 core_pattern = utils.read_file(self._CORE_PATTERN)[:-1] 600 core_pattern = re.sub('--filter_in=\S*\s*', '', 601 core_pattern).rstrip() 602 if new_parameter: 603 core_pattern += ' ' + new_parameter 604 utils.system('echo "%s" > %s' % (core_pattern, self._CORE_PATTERN)) 605 606 607 def enable_crash_filtering(self, name): 608 """Add a --filter_in argument to the kernel core dump cmdline. 609 610 @param name: Filter text to use. This is passed as a --filter_in 611 argument to the crash reporter. 612 """ 613 self._replace_crash_reporter_filter_in('--filter_in=' + name) 614 615 616 def disable_crash_filtering(self): 617 """Remove the --filter_in argument from the kernel core dump cmdline. 618 619 Next time the crash reporter is invoked (due to a crash) it will not 620 receive a --filter_in paramter.""" 621 self._replace_crash_reporter_filter_in('') 622 623 624 @contextlib.contextmanager 625 def hold_crash_lock(self): 626 """A context manager to hold the crash sender lock.""" 627 with open(self._CRASH_SENDER_LOCK_PATH, 'w+') as f: 628 fcntl.flock(f.fileno(), fcntl.LOCK_EX) 629 try: 630 yield 631 finally: 632 fcntl.flock(f.fileno(), fcntl.LOCK_UN) 633 634 635 def initialize(self): 636 """Initalize the test.""" 637 test.test.initialize(self) 638 self._log_reader = cros_logging.make_system_log_reader() 639 self._leave_crash_sending = True 640 self._automatic_consent_saving = True 641 self.enable_crash_filtering('none') 642 self._set_crash_test_in_progress(True) 643 644 645 def cleanup(self): 646 """Cleanup after the test. 647 648 We reset things back to the way we think they should be. This is 649 intended to allow the system to continue normal operation. 650 651 Some variables silently change the behavior: 652 _automatic_consent_saving: if True, we pop the consent file. 653 _leave_crash_sending: True to enable crash sending, False to 654 disable it 655 """ 656 self._reset_rate_limiting() 657 self._clear_spooled_crashes() 658 self._set_system_sending(self._leave_crash_sending) 659 self._set_sending_mock(mock_enabled=False) 660 if self._automatic_consent_saving: 661 self._pop_consent() 662 self.disable_crash_filtering() 663 self._set_crash_test_in_progress(False) 664 test.test.cleanup(self) 665 666 667 def run_crash_tests(self, 668 test_names, 669 initialize_crash_reporter=False, 670 clear_spool_first=True, 671 must_run_all=True): 672 """Run crash tests defined in this class. 673 674 @param test_names: Array of test names. 675 @param initialize_crash_reporter: Should set up crash reporter for every 676 run. 677 @param clear_spool_first: Clear all spooled user/system crashes before 678 starting the test. 679 @param must_run_all: Should make sure every test in this class is 680 mentioned in test_names. 681 """ 682 if self._automatic_consent_saving: 683 self._push_consent() 684 685 if must_run_all: 686 # Sanity check test_names is complete 687 for attr in dir(self): 688 if attr.find('_test_') == 0: 689 test_name = attr[6:] 690 if not test_name in test_names: 691 raise error.TestError('Test %s is missing' % test_name) 692 693 for test_name in test_names: 694 logging.info(('=' * 20) + ('Running %s' % test_name) + ('=' * 20)) 695 if initialize_crash_reporter: 696 self._initialize_crash_reporter() 697 # Disable crash_sender from running, kill off any running ones, but 698 # set environment so crash_sender may run as a child process. 699 self._set_system_sending(False) 700 self._set_child_sending(True) 701 self._kill_running_sender() 702 self._reset_rate_limiting() 703 # Default to not overriding for unofficial versions. 704 self._set_force_official(False) 705 # Default to not pretending we're in developer mode. 706 self._set_mock_developer_mode(False) 707 if clear_spool_first: 708 self._clear_spooled_crashes() 709 710 # Call the test function 711 getattr(self, '_test_' + test_name)() 712 713 # Clear the intentional crashes, so that the server won't automatically 714 # report crash as failure. 715 self._clear_spooled_crashes() 716