OLD | NEW |
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import grp, logging, os, pwd, re, stat, subprocess | 5 import grp, logging, os, pwd, re, stat, subprocess |
6 from signal import SIGSEGV | 6 from signal import SIGSEGV |
7 from autotest_lib.client.bin import site_crash_test, site_utils, test | 7 from autotest_lib.client.bin import site_crash_test, site_utils, test |
8 from autotest_lib.client.common_lib import error, utils | 8 from autotest_lib.client.common_lib import error, utils |
9 | 9 |
10 _COLLECTION_ERROR_SIGNATURE = 'crash_reporter-user-collection' | 10 _COLLECTION_ERROR_SIGNATURE = 'crash_reporter-user-collection' |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 if output != 'core': | 49 if output != 'core': |
50 raise error.TestFail('core pattern should have been core, not %s' % | 50 raise error.TestFail('core pattern should have been core, not %s' % |
51 output) | 51 output) |
52 | 52 |
53 | 53 |
54 def _prepare_crasher(self): | 54 def _prepare_crasher(self): |
55 """Extract the crasher and set its permissions. | 55 """Extract the crasher and set its permissions. |
56 | 56 |
57 crasher is only gzipped to subvert Portage stripping. | 57 crasher is only gzipped to subvert Portage stripping. |
58 """ | 58 """ |
59 self.enable_crash_filtering('crasher_nobreakpad') | |
60 self._crasher_path = os.path.join(self.srcdir, 'crasher_nobreakpad') | 59 self._crasher_path = os.path.join(self.srcdir, 'crasher_nobreakpad') |
61 utils.system('cd %s; tar xzf crasher.tgz-unmasked' % | 60 utils.system('cd %s; tar xzf crasher.tgz-unmasked' % |
62 self.srcdir) | 61 self.srcdir) |
63 # Make sure all users (specifically chronos) have access to | 62 # Make sure all users (specifically chronos) have access to |
64 # this directory and its decendents in order to run crasher | 63 # this directory and its decendents in order to run crasher |
65 # executable as different users. | 64 # executable as different users. |
66 utils.system('chmod -R a+rx ' + self.bindir) | 65 utils.system('chmod -R a+rx ' + self.bindir) |
67 | 66 |
68 | 67 |
69 def _populate_symbols(self): | 68 def _populate_symbols(self): |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 if not self._is_frame_in_stack(15, basename, 'recbomb', | 157 if not self._is_frame_in_stack(15, basename, 'recbomb', |
159 'bomb.cc', 12, stack): | 158 'bomb.cc', 12, stack): |
160 raise error.TestFail('Did not show recursion line on stack') | 159 raise error.TestFail('Did not show recursion line on stack') |
161 | 160 |
162 # Should identify main line | 161 # Should identify main line |
163 if not self._is_frame_in_stack(16, basename, 'main', | 162 if not self._is_frame_in_stack(16, basename, 'main', |
164 'crasher.cc', 21, stack): | 163 'crasher.cc', 21, stack): |
165 raise error.TestFail('Did not show main on stack') | 164 raise error.TestFail('Did not show main on stack') |
166 | 165 |
167 | 166 |
168 def _run_crasher_process(self, username, cause_crash=True, consent=True): | 167 def _run_crasher_process(self, username, cause_crash=True, consent=True, |
| 168 crasher_path=None): |
169 """Runs the crasher process. | 169 """Runs the crasher process. |
170 | 170 |
171 Args: | 171 Args: |
172 username: runs as given user | 172 username: runs as given user |
173 extra_args: additional parameters to pass to crasher process | 173 extra_args: additional parameters to pass to crasher process |
174 | 174 |
175 Returns: | 175 Returns: |
176 A dictionary with keys: | 176 A dictionary with keys: |
177 returncode: return code of the crasher | 177 returncode: return code of the crasher |
178 crashed: did the crasher return segv error code | 178 crashed: did the crasher return segv error code |
179 crash_reporter_caught: did crash_reporter catch a segv | 179 crash_reporter_caught: did crash_reporter catch a segv |
180 output: stderr/stdout output of the crasher process | 180 output: stderr/stdout output of the crasher process |
181 """ | 181 """ |
182 self._prepare_crasher() | 182 if crasher_path is None: crasher_path=self._crasher_path |
183 self._populate_symbols() | 183 self.enable_crash_filtering(os.path.basename(crasher_path)) |
184 | 184 |
185 if username != 'root': | 185 if username != 'root': |
186 crasher_command = ['su', username, '-c'] | 186 crasher_command = ['su', username, '-c'] |
187 expected_result = 128 + SIGSEGV | 187 expected_result = 128 + SIGSEGV |
188 else: | 188 else: |
189 crasher_command = [] | 189 crasher_command = [] |
190 expected_result = -SIGSEGV | 190 expected_result = -SIGSEGV |
191 | 191 |
192 crasher_command.append(self._crasher_path) | 192 crasher_command.append(crasher_path) |
193 basename = os.path.basename(self._crasher_path) | 193 basename = os.path.basename(crasher_path) |
194 if not cause_crash: | 194 if not cause_crash: |
195 crasher_command.append('--nocrash') | 195 crasher_command.append('--nocrash') |
196 self._set_consent(consent) | 196 self._set_consent(consent) |
197 crasher = subprocess.Popen(crasher_command, | 197 crasher = subprocess.Popen(crasher_command, |
198 stdout=subprocess.PIPE, | 198 stdout=subprocess.PIPE, |
199 stderr=subprocess.PIPE) | 199 stderr=subprocess.PIPE) |
200 output = crasher.communicate()[1] | 200 output = crasher.communicate()[1] |
201 logging.debug('Output from %s: %s' % | 201 logging.debug('Output from %s: %s' % |
202 (crasher_command, output)) | 202 (crasher_command, output)) |
203 | 203 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 | 298 |
299 # Check version matches. | 299 # Check version matches. |
300 lsb_release = utils.read_file('/etc/lsb-release') | 300 lsb_release = utils.read_file('/etc/lsb-release') |
301 version_match = re.search(r'CHROMEOS_RELEASE_VERSION=(.*)', lsb_release) | 301 version_match = re.search(r'CHROMEOS_RELEASE_VERSION=(.*)', lsb_release) |
302 if not ('Version: %s' % version_match.group(1)) in result['output']: | 302 if not ('Version: %s' % version_match.group(1)) in result['output']: |
303 raise error.TestFail('Did not find version %s in log output' % | 303 raise error.TestFail('Did not find version %s in log output' % |
304 version_match.group(1)) | 304 version_match.group(1)) |
305 | 305 |
306 | 306 |
307 def _run_crasher_process_and_analyze(self, username, | 307 def _run_crasher_process_and_analyze(self, username, |
308 cause_crash=True, consent=True): | 308 cause_crash=True, consent=True, |
| 309 crasher_path=None): |
309 self._log_reader.set_start_by_current() | 310 self._log_reader.set_start_by_current() |
310 | 311 |
| 312 if crasher_path is None: crasher_path=self._crasher_path |
311 result = self._run_crasher_process(username, cause_crash=cause_crash, | 313 result = self._run_crasher_process(username, cause_crash=cause_crash, |
312 consent=consent) | 314 consent=consent, |
| 315 crasher_path=crasher_path) |
313 | 316 |
314 if not result['crashed'] or not result['crash_reporter_caught']: | 317 if not result['crashed'] or not result['crash_reporter_caught']: |
315 return result; | 318 return result; |
316 | 319 |
317 crash_dir = self._get_crash_dir(username) | 320 crash_dir = self._get_crash_dir(username) |
318 | 321 |
319 if not consent: | 322 if not consent: |
320 if os.path.exists(crash_dir): | 323 if os.path.exists(crash_dir): |
321 raise error.TestFail('Crash directory should not exist') | 324 raise error.TestFail('Crash directory should not exist') |
322 return result | 325 return result |
323 | 326 |
324 crash_contents = os.listdir(crash_dir) | 327 crash_contents = os.listdir(crash_dir) |
325 basename = os.path.basename(self._crasher_path) | 328 basename = os.path.basename(crasher_path) |
326 | 329 |
327 breakpad_minidump = None | 330 breakpad_minidump = None |
328 crash_reporter_minidump = None | 331 crash_reporter_minidump = None |
329 crash_reporter_meta = None | 332 crash_reporter_meta = None |
330 crash_reporter_log = None | 333 crash_reporter_log = None |
331 | 334 |
332 self._check_crash_directory_permissions(crash_dir) | 335 self._check_crash_directory_permissions(crash_dir) |
333 | 336 |
334 logging.debug('Contents in %s: %s' % (crash_dir, crash_contents)) | 337 logging.debug('Contents in %s: %s' % (crash_dir, crash_contents)) |
335 | 338 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 site_utils.poll_for_condition( | 456 site_utils.poll_for_condition( |
454 lambda: self._log_reader.can_find(to_find), | 457 lambda: self._log_reader.can_find(to_find), |
455 timeout=10, | 458 timeout=10, |
456 exception=error.TestError( | 459 exception=error.TestError( |
457 'Timeout waiting for: ' + to_find + ' in ' + | 460 'Timeout waiting for: ' + to_find + ' in ' + |
458 self._log_reader.get_logs())) | 461 self._log_reader.get_logs())) |
459 | 462 |
460 | 463 |
461 def _test_crash_filtering(self): | 464 def _test_crash_filtering(self): |
462 """Test that crash filtering (a feature needed for testing) works.""" | 465 """Test that crash filtering (a feature needed for testing) works.""" |
463 self._prepare_crasher() | |
464 crasher_basename = os.path.basename(self._crasher_path) | 466 crasher_basename = os.path.basename(self._crasher_path) |
465 self._log_reader.set_start_by_current() | 467 self._log_reader.set_start_by_current() |
466 | 468 |
467 self.enable_crash_filtering('none') | 469 self.enable_crash_filtering('none') |
468 self._check_filter_crasher(False) | 470 self._check_filter_crasher(False) |
469 | 471 |
470 self.enable_crash_filtering('sleep') | 472 self.enable_crash_filtering('sleep') |
471 self._check_filter_crasher(False) | 473 self._check_filter_crasher(False) |
472 | 474 |
473 self.disable_crash_filtering() | 475 self.disable_crash_filtering() |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 self._check_collection_failure('--core2md_failure_test', | 554 self._check_collection_failure('--core2md_failure_test', |
553 'Problem during %s [result=1]: Usage:' % | 555 'Problem during %s [result=1]: Usage:' % |
554 _CORE2MD_PATH) | 556 _CORE2MD_PATH) |
555 | 557 |
556 | 558 |
557 def _test_internal_directory_failure(self): | 559 def _test_internal_directory_failure(self): |
558 self._check_collection_failure('--directory_failure_test', | 560 self._check_collection_failure('--directory_failure_test', |
559 'Purposefully failing to create') | 561 'Purposefully failing to create') |
560 | 562 |
561 | 563 |
| 564 def _test_crash_logs_creation(self): |
| 565 logs_triggering_crasher = os.path.join(os.path.dirname(self.bindir), |
| 566 'crash_log_test') |
| 567 # Copy crasher_path to a test location with correct mode and a |
| 568 # special name to trigger crash log creation. |
| 569 utils.system('cp -a "%s" "%s"' % (self._crasher_path, |
| 570 logs_triggering_crasher)) |
| 571 result = self._run_crasher_process_and_analyze( |
| 572 'root', crasher_path=logs_triggering_crasher) |
| 573 self._check_crashed_and_caught(result) |
| 574 contents = utils.read_file(result['log']) |
| 575 if contents != 'hello world\n': |
| 576 raise error.TestFail('Crash log contents unexpected: %s' % contents) |
| 577 if not ('log=' + result['log']) in utils.read_file(result['meta']): |
| 578 raise error.TestFail('Meta file does not reference log') |
| 579 |
| 580 |
| 581 def _test_crash_log_infinite_recursion(self): |
| 582 recursion_triggering_crasher = os.path.join( |
| 583 os.path.dirname(self.bindir), 'crash_log_recursion_test') |
| 584 # The configuration file hardcodes this path, so make sure it's still |
| 585 # the same. |
| 586 if (recursion_triggering_crasher != |
| 587 '/home/autotest/tests/crash_log_recursion_test'): |
| 588 raise error.TestError('Path to recursion test changed') |
| 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 recursion_triggering_crasher)) |
| 593 # Simply completing this command means that we avoided |
| 594 # infinite recursion. |
| 595 result = self._run_crasher_process( |
| 596 'root', crasher_path=recursion_triggering_crasher) |
| 597 |
| 598 |
562 def _check_core_file_persisting(self, expect_persist): | 599 def _check_core_file_persisting(self, expect_persist): |
563 self._log_reader.set_start_by_current() | 600 self._log_reader.set_start_by_current() |
564 | 601 |
565 result = self._run_crasher_process('root') | 602 result = self._run_crasher_process('root') |
566 | 603 |
567 if not result['crashed']: | 604 if not result['crashed']: |
568 raise error.TestFail('crasher did not crash') | 605 raise error.TestFail('crasher did not crash') |
569 | 606 |
570 crash_contents = os.listdir(self._get_crash_dir('root')) | 607 crash_contents = os.listdir(self._get_crash_dir('root')) |
571 | 608 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 raise error.TestFail('.leave_core file did not disappear') | 653 raise error.TestFail('.leave_core file did not disappear') |
617 self._check_core_file_persisting(False) | 654 self._check_core_file_persisting(False) |
618 finally: | 655 finally: |
619 os.system('umount /root') | 656 os.system('umount /root') |
620 | 657 |
621 | 658 |
622 # TODO(kmixter): Test crashing a process as ntp or some other | 659 # TODO(kmixter): Test crashing a process as ntp or some other |
623 # non-root, non-chronos user. | 660 # non-root, non-chronos user. |
624 | 661 |
625 def run_once(self): | 662 def run_once(self): |
| 663 self._prepare_crasher() |
| 664 self._populate_symbols() |
626 self.run_crash_tests(['reporter_startup', | 665 self.run_crash_tests(['reporter_startup', |
627 'reporter_shutdown', | 666 'reporter_shutdown', |
628 'no_crash', | 667 'no_crash', |
629 'chronos_crasher', | 668 'chronos_crasher', |
630 'chronos_crasher_no_consent', | 669 'chronos_crasher_no_consent', |
631 'root_crasher', | 670 'root_crasher', |
632 'root_crasher_no_consent', | 671 'root_crasher_no_consent', |
633 'crash_filtering', | 672 'crash_filtering', |
634 'max_enqueued_crashes', | 673 'max_enqueued_crashes', |
635 'core2md_failure', | 674 'core2md_failure', |
636 'internal_directory_failure', | 675 'internal_directory_failure', |
| 676 'crash_logs_creation', |
| 677 'crash_log_infinite_recursion', |
637 'core_file_persists_in_debug', | 678 'core_file_persists_in_debug', |
638 'core_file_removed_in_production'], | 679 'core_file_removed_in_production'], |
639 initialize_crash_reporter = True) | 680 initialize_crash_reporter = True) |
OLD | NEW |