1# Copyright (c) 2010 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 5import grp, logging, os, pwd, re, stat, subprocess 6from signal import SIGSEGV 7from autotest_lib.client.bin import utils 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.cros import crash_test, cros_ui, upstart 10 11 12_COLLECTION_ERROR_SIGNATURE = 'crash_reporter-user-collection' 13_CORE2MD_PATH = '/usr/bin/core2md' 14_LEAVE_CORE_PATH = '/root/.leave_core' 15_MAX_CRASH_DIRECTORY_SIZE = 32 16 17 18class logging_UserCrash(crash_test.CrashTest): 19 version = 1 20 21 22 def setup(self): 23 os.chdir(self.srcdir) 24 utils.make('clean') 25 utils.make('all') 26 27 28 def _test_reporter_startup(self): 29 """Test that the core_pattern is set up by crash reporter.""" 30 # Turn off crash filtering so we see the original setting. 31 self.disable_crash_filtering() 32 output = utils.read_file(self._CORE_PATTERN).rstrip() 33 expected_core_pattern = ('|%s --user=%%P:%%s:%%u:%%e' % 34 self._CRASH_REPORTER_PATH) 35 if output != expected_core_pattern: 36 raise error.TestFail('core pattern should have been %s, not %s' % 37 (expected_core_pattern, output)) 38 39 self._log_reader.set_start_by_reboot(-1) 40 41 if not self._log_reader.can_find('Enabling user crash handling'): 42 raise error.TestFail( 43 'user space crash handling was not started during last boot') 44 45 46 def _test_reporter_shutdown(self): 47 """Test the crash_reporter shutdown code works.""" 48 self._log_reader.set_start_by_current() 49 utils.system('%s --clean_shutdown' % self._CRASH_REPORTER_PATH) 50 output = utils.read_file(self._CORE_PATTERN).rstrip() 51 if output != 'core': 52 raise error.TestFail('core pattern should have been core, not %s' % 53 output) 54 55 56 def _prepare_crasher(self): 57 """Extract the crasher and set its permissions. 58 59 crasher is only gzipped to subvert Portage stripping. 60 """ 61 self._crasher_path = os.path.join(self.srcdir, 'crasher_nobreakpad') 62 utils.system('cd %s; tar xzf crasher.tgz-unmasked' % 63 self.srcdir) 64 # Make sure all users (specifically chronos) have access to 65 # this directory and its decendents in order to run crasher 66 # executable as different users. 67 utils.system('chmod -R a+rx ' + self.bindir) 68 69 70 def _populate_symbols(self): 71 """Set up Breakpad's symbol structure. 72 73 Breakpad's minidump processor expects symbols to be in a directory 74 hierarchy: 75 <symbol-root>/<module_name>/<file_id>/<module_name>.sym 76 """ 77 # Dump the symbols from the crasher 78 self._symbol_dir = os.path.join(self.srcdir, 'symbols') 79 utils.system('rm -rf %s' % self._symbol_dir) 80 os.mkdir(self._symbol_dir) 81 82 basename = os.path.basename(self._crasher_path) 83 utils.system('/usr/bin/dump_syms %s > %s.sym' % 84 (self._crasher_path, 85 basename)) 86 sym_name = '%s.sym' % basename 87 symbols = utils.read_file(sym_name) 88 # First line should be like: 89 # MODULE Linux x86 7BC3323FBDBA2002601FA5BA3186D6540 crasher_XXX 90 # or 91 # MODULE Linux arm C2FE4895B203D87DD4D9227D5209F7890 crasher_XXX 92 first_line = symbols.split('\n')[0] 93 tokens = first_line.split() 94 if tokens[0] != 'MODULE' or tokens[1] != 'Linux': 95 raise error.TestError('Unexpected symbols format: %s', 96 first_line) 97 file_id = tokens[3] 98 target_dir = os.path.join(self._symbol_dir, basename, file_id) 99 os.makedirs(target_dir) 100 os.rename(sym_name, os.path.join(target_dir, sym_name)) 101 102 103 def _is_frame_in_stack(self, frame_index, module_name, 104 function_name, file_name, 105 line_number, stack): 106 """Search for frame entries in the given stack dump text. 107 108 A frame entry looks like (alone on a line): 109 16 crasher_nobreakpad!main [crasher.cc : 21 + 0xb] 110 111 Args: 112 frame_index: number of the stack frame (0 is innermost frame) 113 module_name: name of the module (executable or dso) 114 function_name: name of the function in the stack 115 file_name: name of the file containing the function 116 line_number: line number 117 stack: text string of stack frame entries on separate lines. 118 119 Returns: 120 Boolean indicating if an exact match is present. 121 122 Note: 123 We do not care about the full function signature - ie, is it 124 foo or foo(ClassA *). These are present in function names 125 pulled by dump_syms for Stabs but not for DWARF. 126 """ 127 regexp = (r'\n\s*%d\s+%s!%s.*\[\s*%s\s*:\s*%d\s.*\]' % 128 (frame_index, module_name, 129 function_name, file_name, 130 line_number)) 131 logging.info('Searching for regexp ' + regexp) 132 return re.search(regexp, stack) is not None 133 134 135 def _verify_stack(self, stack, basename, from_crash_reporter): 136 logging.debug('Crash stackwalk was: %s' % stack) 137 138 # Should identify cause as SIGSEGV at address 0x16 139 match = re.search(r'Crash reason:\s+(.*)', stack) 140 expected_address = '0x16' 141 if from_crash_reporter: 142 # We cannot yet determine the crash address when coming 143 # through core files via crash_reporter. 144 expected_address = '0x0' 145 if not match or match.group(1) != 'SIGSEGV': 146 raise error.TestFail('Did not identify SIGSEGV cause') 147 match = re.search(r'Crash address:\s+(.*)', stack) 148 if not match or match.group(1) != expected_address: 149 raise error.TestFail('Did not identify crash address %s' % 150 expected_address) 151 152 # Should identify crash at *(char*)0x16 assignment line 153 if not self._is_frame_in_stack(0, basename, 154 'recbomb', 'bomb.cc', 9, stack): 155 raise error.TestFail('Did not show crash line on stack') 156 157 # Should identify recursion line which is on the stack 158 # for 15 levels 159 if not self._is_frame_in_stack(15, basename, 'recbomb', 160 'bomb.cc', 12, stack): 161 raise error.TestFail('Did not show recursion line on stack') 162 163 # Should identify main line 164 if not self._is_frame_in_stack(16, basename, 'main', 165 'crasher.cc', 20, stack): 166 raise error.TestFail('Did not show main on stack') 167 168 169 def _run_crasher_process(self, username, cause_crash=True, consent=True, 170 crasher_path=None): 171 """Runs the crasher process. 172 173 Will wait up to 5 seconds for crash_reporter to report the crash. 174 crash_reporter_caught will be marked as true when the "Received crash 175 notification message..." appears. While associated logs are likely to be 176 available at this point, the function does not guarantee this. 177 178 Args: 179 username: runs as given user 180 extra_args: additional parameters to pass to crasher process 181 182 Returns: 183 A dictionary with keys: 184 returncode: return code of the crasher 185 crashed: did the crasher return segv error code 186 crash_reporter_caught: did crash_reporter catch a segv 187 output: stderr/stdout output of the crasher process 188 """ 189 if crasher_path is None: crasher_path = self._crasher_path 190 self.enable_crash_filtering(os.path.basename(crasher_path)) 191 192 if username != 'root': 193 crasher_command = ['su', username, '-c'] 194 expected_result = 128 + SIGSEGV 195 else: 196 crasher_command = [] 197 expected_result = -SIGSEGV 198 199 crasher_command.append(crasher_path) 200 basename = os.path.basename(crasher_path) 201 if not cause_crash: 202 crasher_command.append('--nocrash') 203 self._set_consent(consent) 204 crasher = subprocess.Popen(crasher_command, 205 stdout=subprocess.PIPE, 206 stderr=subprocess.PIPE) 207 output = crasher.communicate()[1] 208 logging.debug('Output from %s: %s' % 209 (crasher_command, output)) 210 211 # Grab the pid from the process output. We can't just use 212 # crasher.pid unfortunately because that may be the PID of su. 213 match = re.search(r'pid=(\d+)', output) 214 if not match: 215 raise error.TestFail('Could not find pid output from crasher: %s' % 216 output) 217 pid = int(match.group(1)) 218 219 expected_uid = pwd.getpwnam(username)[2] 220 if consent: 221 handled_string = 'handling' 222 else: 223 handled_string = 'ignoring - no consent' 224 expected_message = ( 225 'Received crash notification for %s[%d] sig 11, user %d (%s)' % 226 (basename, pid, expected_uid, handled_string)) 227 228 # Wait until no crash_reporter is running. 229 utils.poll_for_condition( 230 lambda: utils.system('pgrep -f crash_reporter.*:%s' % basename, 231 ignore_status=True) != 0, 232 timeout=10, 233 exception=error.TestError( 234 'Timeout waiting for crash_reporter to finish: ' + 235 self._log_reader.get_logs())) 236 237 logging.debug('crash_reporter_caught message: ' + expected_message) 238 is_caught = False 239 try: 240 utils.poll_for_condition( 241 lambda: self._log_reader.can_find(expected_message), 242 timeout=5) 243 is_caught = True 244 except utils.TimeoutError: 245 pass 246 247 result = {'crashed': crasher.returncode == expected_result, 248 'crash_reporter_caught': is_caught, 249 'output': output, 250 'returncode': crasher.returncode} 251 logging.debug('Crasher process result: %s' % result) 252 return result 253 254 255 def _check_crash_directory_permissions(self, crash_dir): 256 stat_info = os.stat(crash_dir) 257 user = pwd.getpwuid(stat_info.st_uid)[0] 258 group = grp.getgrgid(stat_info.st_gid)[0] 259 mode = stat.S_IMODE(stat_info.st_mode) 260 261 if crash_dir == '/var/spool/crash': 262 expected_user = 'root' 263 expected_group = 'root' 264 expected_mode = 01755 265 else: 266 expected_user = 'chronos' 267 expected_group = 'chronos' 268 expected_mode = 0755 269 270 if user != expected_user or group != expected_group: 271 raise error.TestFail( 272 'Expected %s.%s ownership of %s (actual %s.%s)' % 273 (expected_user, expected_group, crash_dir, user, group)) 274 if mode != expected_mode: 275 raise error.TestFail( 276 'Expected %s to have mode %o (actual %o)' % 277 (crash_dir, expected_mode, mode)) 278 279 280 def _check_minidump_stackwalk(self, minidump_path, basename, 281 from_crash_reporter): 282 # Now stackwalk the minidump 283 stack = utils.system_output('/usr/bin/minidump_stackwalk %s %s' % 284 (minidump_path, self._symbol_dir)) 285 self._verify_stack(stack, basename, from_crash_reporter) 286 287 288 def _check_generated_report_sending(self, meta_path, payload_path, 289 username, exec_name, report_kind, 290 expected_sig=None): 291 # Now check that the sending works 292 result = self._call_sender_one_crash( 293 username=username, 294 report=os.path.basename(payload_path)) 295 if (not result['send_attempt'] or not result['send_success'] or 296 result['report_exists']): 297 raise error.TestFail('Report not sent properly') 298 if result['exec_name'] != exec_name: 299 raise error.TestFail('Executable name incorrect') 300 if result['report_kind'] != report_kind: 301 raise error.TestFail('Expected a minidump report') 302 if result['report_payload'] != payload_path: 303 raise error.TestFail('Sent the wrong minidump payload') 304 if result['meta_path'] != meta_path: 305 raise error.TestFail('Used the wrong meta file') 306 if expected_sig is None: 307 if result['sig'] is not None: 308 raise error.TestFail('Report should not have signature') 309 else: 310 if not 'sig' in result or result['sig'] != expected_sig: 311 raise error.TestFail('Report signature mismatch: %s vs %s' % 312 (result['sig'], expected_sig)) 313 314 # Check version matches. 315 lsb_release = utils.read_file('/etc/lsb-release') 316 version_match = re.search(r'CHROMEOS_RELEASE_VERSION=(.*)', lsb_release) 317 if not ('Version: %s' % version_match.group(1)) in result['output']: 318 raise error.TestFail('Did not find version %s in log output' % 319 version_match.group(1)) 320 321 322 def _run_crasher_process_and_analyze(self, username, 323 cause_crash=True, consent=True, 324 crasher_path=None): 325 self._log_reader.set_start_by_current() 326 327 if crasher_path is None: crasher_path = self._crasher_path 328 result = self._run_crasher_process(username, cause_crash=cause_crash, 329 consent=consent, 330 crasher_path=crasher_path) 331 332 if not result['crashed'] or not result['crash_reporter_caught']: 333 return result; 334 335 crash_dir = self._get_crash_dir(username) 336 337 if not consent: 338 if os.path.exists(crash_dir): 339 raise error.TestFail('Crash directory should not exist') 340 return result 341 342 crash_contents = os.listdir(crash_dir) 343 basename = os.path.basename(crasher_path) 344 345 breakpad_minidump = None 346 crash_reporter_minidump = None 347 crash_reporter_meta = None 348 crash_reporter_log = None 349 350 self._check_crash_directory_permissions(crash_dir) 351 352 logging.debug('Contents in %s: %s' % (crash_dir, crash_contents)) 353 354 for filename in crash_contents: 355 if filename.endswith('.core'): 356 # Ignore core files. We'll test them later. 357 pass 358 elif (filename.startswith(basename) and 359 filename.endswith('.dmp')): 360 # This appears to be a minidump created by the crash reporter. 361 if not crash_reporter_minidump is None: 362 raise error.TestFail('Crash reporter wrote multiple ' 363 'minidumps') 364 crash_reporter_minidump = os.path.join(crash_dir, filename) 365 elif (filename.startswith(basename) and 366 filename.endswith('.meta')): 367 if not crash_reporter_meta is None: 368 raise error.TestFail('Crash reporter wrote multiple ' 369 'meta files') 370 crash_reporter_meta = os.path.join(crash_dir, filename) 371 elif (filename.startswith(basename) and 372 filename.endswith('.log')): 373 if not crash_reporter_log is None: 374 raise error.TestFail('Crash reporter wrote multiple ' 375 'log files') 376 crash_reporter_log = os.path.join(crash_dir, filename) 377 else: 378 # This appears to be a breakpad created minidump. 379 if not breakpad_minidump is None: 380 raise error.TestFail('Breakpad wrote multimpe minidumps') 381 breakpad_minidump = os.path.join(crash_dir, filename) 382 383 if breakpad_minidump: 384 raise error.TestFail('%s did generate breakpad minidump' % basename) 385 386 if not crash_reporter_meta: 387 raise error.TestFail('crash reporter did not generate meta') 388 389 result['minidump'] = crash_reporter_minidump 390 result['basename'] = basename 391 result['meta'] = crash_reporter_meta 392 result['log'] = crash_reporter_log 393 return result 394 395 396 def _check_crashed_and_caught(self, result): 397 if not result['crashed']: 398 raise error.TestFail('crasher did not do its job of crashing: %d' % 399 result['returncode']) 400 401 if not result['crash_reporter_caught']: 402 logging.debug('Messages that should have included segv: %s' % 403 self._log_reader.get_logs()) 404 raise error.TestFail('Did not find segv message') 405 406 407 def _check_crashing_process(self, username, consent=True): 408 result = self._run_crasher_process_and_analyze(username, 409 consent=consent) 410 411 self._check_crashed_and_caught(result) 412 413 if not consent: 414 return 415 416 if not result['minidump']: 417 raise error.TestFail('crash reporter did not generate minidump') 418 419 if not self._log_reader.can_find('Stored minidump to ' + 420 result['minidump']): 421 raise error.TestFail('crash reporter did not announce minidump') 422 423 self._check_minidump_stackwalk(result['minidump'], 424 result['basename'], 425 from_crash_reporter=True) 426 self._check_generated_report_sending(result['meta'], 427 result['minidump'], 428 username, 429 result['basename'], 430 'minidump') 431 432 def _test_no_crash(self): 433 """Test a program linked against libcrash_dumper can exit normally.""" 434 self._log_reader.set_start_by_current() 435 result = self._run_crasher_process_and_analyze(username='root', 436 cause_crash=False) 437 if (result['crashed'] or 438 result['crash_reporter_caught'] or 439 result['returncode'] != 0): 440 raise error.TestFail('Normal exit of program with dumper failed') 441 442 443 def _test_chronos_crasher(self): 444 """Test a user space crash when running as chronos is handled.""" 445 self._check_crashing_process('chronos') 446 447 448 def _test_chronos_crasher_no_consent(self): 449 """Test that without consent no files are stored.""" 450 results = self._check_crashing_process('chronos', consent=False) 451 452 453 def _test_root_crasher(self): 454 """Test a user space crash when running as root is handled.""" 455 self._check_crashing_process('root') 456 457 458 def _test_root_crasher_no_consent(self): 459 """Test that without consent no files are stored.""" 460 results = self._check_crashing_process('root', consent=False) 461 462 463 def _check_filter_crasher(self, should_receive): 464 self._log_reader.set_start_by_current() 465 crasher_basename = os.path.basename(self._crasher_path) 466 utils.system(self._crasher_path, ignore_status=True); 467 if should_receive: 468 to_find = 'Received crash notification for ' + crasher_basename 469 else: 470 to_find = 'Ignoring crash from ' + crasher_basename 471 utils.poll_for_condition( 472 lambda: self._log_reader.can_find(to_find), 473 timeout=10, 474 exception=error.TestError( 475 'Timeout waiting for: ' + to_find + ' in ' + 476 self._log_reader.get_logs())) 477 478 479 def _test_crash_filtering(self): 480 """Test that crash filtering (a feature needed for testing) works.""" 481 crasher_basename = os.path.basename(self._crasher_path) 482 self._log_reader.set_start_by_current() 483 484 self.enable_crash_filtering('none') 485 self._check_filter_crasher(False) 486 487 self.enable_crash_filtering('sleep') 488 self._check_filter_crasher(False) 489 490 self.disable_crash_filtering() 491 self._check_filter_crasher(True) 492 493 494 def _test_max_enqueued_crashes(self): 495 """Test that _MAX_CRASH_DIRECTORY_SIZE is enforced.""" 496 self._log_reader.set_start_by_current() 497 username = 'root' 498 499 crash_dir = self._get_crash_dir(username) 500 full_message = ('Crash directory %s already full with %d pending ' 501 'reports' % (crash_dir, _MAX_CRASH_DIRECTORY_SIZE)) 502 503 # Fill up the queue. 504 for i in range(0, _MAX_CRASH_DIRECTORY_SIZE): 505 result = self._run_crasher_process(username) 506 if not result['crashed']: 507 raise error.TestFail('failure while setting up queue: %d' % 508 result['returncode']) 509 if self._log_reader.can_find(full_message): 510 raise error.TestFail('unexpected full message: ' + full_message) 511 512 crash_dir_size = len(os.listdir(crash_dir)) 513 # For debugging 514 utils.system('ls -l %s' % crash_dir) 515 logging.info('Crash directory had %d entries' % crash_dir_size) 516 517 # Crash a bunch more times, but make sure no new reports 518 # are enqueued. 519 for i in range(0, 10): 520 self._log_reader.set_start_by_current() 521 result = self._run_crasher_process(username) 522 logging.info('New log messages: %s' % self._log_reader.get_logs()) 523 if not result['crashed']: 524 raise error.TestFail('failure after setting up queue: %d' % 525 result['returncode']) 526 utils.poll_for_condition( 527 lambda: self._log_reader.can_find(full_message), 528 timeout=20, 529 exception=error.TestFail('expected full message: ' + 530 full_message)) 531 if crash_dir_size != len(os.listdir(crash_dir)): 532 utils.system('ls -l %s' % crash_dir) 533 raise error.TestFail('expected no new files (now %d were %d)', 534 len(os.listdir(crash_dir)), 535 crash_dir_size) 536 537 538 def _check_collection_failure(self, test_option, failure_string): 539 # Add parameter to core_pattern. 540 old_core_pattern = utils.read_file(self._CORE_PATTERN)[:-1] 541 try: 542 utils.system('echo "%s %s" > %s' % (old_core_pattern, test_option, 543 self._CORE_PATTERN)) 544 result = self._run_crasher_process_and_analyze('root', 545 consent=True) 546 self._check_crashed_and_caught(result) 547 if not self._log_reader.can_find(failure_string): 548 raise error.TestFail('Did not find fail string in log %s' % 549 failure_string) 550 if result['minidump']: 551 raise error.TestFail('failed collection resulted in minidump') 552 if not result['log']: 553 raise error.TestFail('failed collection had no log') 554 log_contents = utils.read_file(result['log']) 555 logging.debug('Log contents were: ' + log_contents) 556 if not failure_string in log_contents: 557 raise error.TestFail('Expected logged error ' 558 '\"%s\" was \"%s\"' % 559 (failure_string, log_contents)) 560 # Verify we are generating appropriate diagnostic output. 561 if ((not '===ps output===' in log_contents) or 562 (not '===meminfo===' in log_contents)): 563 raise error.TestFail('Expected full logs, got: ' + log_contents) 564 self._check_generated_report_sending(result['meta'], 565 result['log'], 566 'root', 567 result['basename'], 568 'log', 569 _COLLECTION_ERROR_SIGNATURE) 570 finally: 571 utils.system('echo "%s" > %s' % (old_core_pattern, 572 self._CORE_PATTERN)) 573 574 575 def _test_core2md_failure(self): 576 self._check_collection_failure('--core2md_failure', 577 'Problem during %s [result=1]: Usage:' % 578 _CORE2MD_PATH) 579 580 581 def _test_internal_directory_failure(self): 582 self._check_collection_failure('--directory_failure', 583 'Purposefully failing to create') 584 585 586 def _test_crash_logs_creation(self): 587 logs_triggering_crasher = os.path.join(os.path.dirname(self.bindir), 588 'crash_log_test') 589 # Copy crasher_path to a test location with correct mode and a 590 # special name to trigger crash log creation. 591 utils.system('cp -a "%s" "%s"' % (self._crasher_path, 592 logs_triggering_crasher)) 593 result = self._run_crasher_process_and_analyze( 594 'root', crasher_path=logs_triggering_crasher) 595 self._check_crashed_and_caught(result) 596 contents = utils.read_file(result['log']) 597 if contents != 'hello world\n': 598 raise error.TestFail('Crash log contents unexpected: %s' % contents) 599 if not ('log=' + result['log']) in utils.read_file(result['meta']): 600 raise error.TestFail('Meta file does not reference log') 601 602 603 def _test_crash_log_infinite_recursion(self): 604 recursion_triggering_crasher = os.path.join( 605 os.path.dirname(self.bindir), 'crash_log_recursion_test') 606 # The configuration file hardcodes this path, so make sure it's still 607 # the same. 608 if (recursion_triggering_crasher != 609 '/usr/local/autotest/tests/crash_log_recursion_test'): 610 raise error.TestError('Path to recursion test changed') 611 # Copy crasher_path to a test location with correct mode and a 612 # special name to trigger crash log creation. 613 utils.system('cp -a "%s" "%s"' % (self._crasher_path, 614 recursion_triggering_crasher)) 615 # Simply completing this command means that we avoided 616 # infinite recursion. 617 result = self._run_crasher_process( 618 'root', crasher_path=recursion_triggering_crasher) 619 620 621 def _check_core_file_persisting(self, expect_persist): 622 self._log_reader.set_start_by_current() 623 624 result = self._run_crasher_process('root') 625 626 if not result['crashed']: 627 raise error.TestFail('crasher did not crash') 628 629 crash_contents = os.listdir(self._get_crash_dir('root')) 630 631 logging.debug('Contents of crash directory: %s', crash_contents) 632 logging.debug('Log messages: %s' % self._log_reader.get_logs()) 633 634 if expect_persist: 635 if not self._log_reader.can_find('Leaving core file at'): 636 raise error.TestFail('Missing log message') 637 expected_core_files = 1 638 else: 639 if self._log_reader.can_find('Leaving core file at'): 640 raise error.TestFail('Unexpected log message') 641 expected_core_files = 0 642 643 dmp_files = 0 644 core_files = 0 645 for filename in crash_contents: 646 if filename.endswith('.dmp'): 647 dmp_files += 1 648 if filename.endswith('.core'): 649 core_files += 1 650 651 if dmp_files != 1: 652 raise error.TestFail('Should have been exactly 1 dmp file') 653 if core_files != expected_core_files: 654 raise error.TestFail('Should have been exactly %d core files' % 655 expected_core_files) 656 657 658 def _test_core_file_removed_in_production(self): 659 """Test that core files do not stick around for production builds.""" 660 # Avoid remounting / rw by instead creating a tmpfs in /root and 661 # populating it with everything but the 662 utils.system('tar -cvz -C /root -f /tmp/root.tgz .') 663 utils.system('mount -t tmpfs tmpfs /root') 664 try: 665 utils.system('tar -xvz -C /root -f /tmp/root.tgz .') 666 os.remove(_LEAVE_CORE_PATH) 667 if os.path.exists(_LEAVE_CORE_PATH): 668 raise error.TestFail('.leave_core file did not disappear') 669 self._check_core_file_persisting(False) 670 finally: 671 os.system('umount /root') 672 673 674 def initialize(self): 675 super(logging_UserCrash, self).initialize() 676 677 # If the device has a GUI, return the device to the sign-in screen, as 678 # some tests will fail inside a user session. 679 if upstart.has_service('ui'): 680 cros_ui.restart() 681 682 683 # TODO(kmixter): Test crashing a process as ntp or some other 684 # non-root, non-chronos user. 685 686 def run_once(self): 687 self._prepare_crasher() 688 self._populate_symbols() 689 690 # Run the test once without re-initializing 691 # to catch problems with the default crash reporting setup 692 self.run_crash_tests(['reporter_startup'], 693 initialize_crash_reporter=False, 694 must_run_all=False) 695 696 self.run_crash_tests(['reporter_startup', 697 'reporter_shutdown', 698 'no_crash', 699 'chronos_crasher', 700 'chronos_crasher_no_consent', 701 'root_crasher', 702 'root_crasher_no_consent', 703 'crash_filtering', 704 'max_enqueued_crashes', 705 'core2md_failure', 706 'internal_directory_failure', 707 'crash_logs_creation', 708 'crash_log_infinite_recursion', 709 'core_file_removed_in_production'], 710 initialize_crash_reporter=True) 711