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

Side by Side Diff: client/site_tests/logging_UserCrash/logging_UserCrash.py

Issue 5763003: autotest: Test that logs can be sent when processes crash (Closed) Base URL: http://git.chromium.org/git/autotest.git@master
Patch Set: Created 10 years 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 | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698