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

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

Issue 4113004: autotest: Test new crash_reporter error diagnostics (Closed) Base URL: http://git.chromium.org/git/autotest.git
Patch Set: Add signature for error logs Created 10 years, 1 month 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
« no previous file with comments | « client/site_tests/logging_KernelCrash/logging_KernelCrash.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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'
11 _CORE2MD_PATH = '/usr/bin/core2md'
10 _CORE_PATTERN = '/proc/sys/kernel/core_pattern' 12 _CORE_PATTERN = '/proc/sys/kernel/core_pattern'
11 _LEAVE_CORE_PATH = '/root/.leave_core' 13 _LEAVE_CORE_PATH = '/root/.leave_core'
12 _MAX_CRASH_DIRECTORY_SIZE = 32 14 _MAX_CRASH_DIRECTORY_SIZE = 32
13 15
14 16
15 class logging_UserCrash(site_crash_test.CrashTest): 17 class logging_UserCrash(site_crash_test.CrashTest):
16 version = 1 18 version = 1
17 19
18 20
19 def setup(self): 21 def setup(self):
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 crasher_command.append(self._crasher_path) 150 crasher_command.append(self._crasher_path)
149 basename = os.path.basename(self._crasher_path) 151 basename = os.path.basename(self._crasher_path)
150 if not cause_crash: 152 if not cause_crash:
151 crasher_command.append('--nocrash') 153 crasher_command.append('--nocrash')
152 self._set_consent(consent) 154 self._set_consent(consent)
153 crasher = subprocess.Popen(crasher_command, 155 crasher = subprocess.Popen(crasher_command,
154 stdout=subprocess.PIPE, 156 stdout=subprocess.PIPE,
155 stderr=subprocess.PIPE) 157 stderr=subprocess.PIPE)
156 output = crasher.communicate()[1] 158 output = crasher.communicate()[1]
157 logging.debug('Output from %s: %s' % 159 logging.debug('Output from %s: %s' %
158 (self._crasher_path, output)) 160 (crasher_command, output))
159 161
160 # Grab the pid from the process output. We can't just use 162 # Grab the pid from the process output. We can't just use
161 # crasher.pid unfortunately because that may be the PID of su. 163 # crasher.pid unfortunately because that may be the PID of su.
162 match = re.search(r'pid=(\d+)', output) 164 match = re.search(r'pid=(\d+)', output)
163 if not match: 165 if not match:
164 raise error.TestFail('Could not find pid output from crasher: %s' % 166 raise error.TestFail('Could not find pid output from crasher: %s' %
165 output) 167 output)
166 pid = int(match.group(1)) 168 pid = int(match.group(1))
167 169
168 if consent: 170 if consent:
169 handled_string = 'handling' 171 handled_string = 'handling'
170 else: 172 else:
171 handled_string = 'ignoring' 173 handled_string = 'ignoring - no consent'
172 expected_message = ( 174 expected_message = (
173 'Received crash notification for %s[%d] sig 11 (%s)' % 175 'Received crash notification for %s[%d] sig 11 (%s)' %
174 (basename, pid, handled_string)) 176 (basename, pid, handled_string))
175 177
176 # Wait until no crash_reporter is running. 178 # Wait until no crash_reporter is running.
177 site_utils.poll_for_condition( 179 site_utils.poll_for_condition(
178 lambda: utils.system('pgrep crash_reporter', 180 lambda: utils.system('pgrep crash_reporter',
179 ignore_status=True) != 0, 181 ignore_status=True) != 0,
180 timeout=10, 182 timeout=10,
181 exception=error.TestError( 183 exception=error.TestError(
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 221
220 222
221 def _check_minidump_stackwalk(self, minidump_path, basename, 223 def _check_minidump_stackwalk(self, minidump_path, basename,
222 from_crash_reporter): 224 from_crash_reporter):
223 # Now stackwalk the minidump 225 # Now stackwalk the minidump
224 stack = utils.system_output('/usr/bin/minidump_stackwalk %s %s' % 226 stack = utils.system_output('/usr/bin/minidump_stackwalk %s %s' %
225 (minidump_path, self._symbol_dir)) 227 (minidump_path, self._symbol_dir))
226 self._verify_stack(stack, basename, from_crash_reporter) 228 self._verify_stack(stack, basename, from_crash_reporter)
227 229
228 230
229 def _check_generated_minidump_sending(self, meta_path, minidump_path, 231 def _check_generated_report_sending(self, meta_path, payload_path,
230 username, crasher_basename, 232 username, exec_name, report_kind,
231 will_syslog_give_name): 233 expected_sig=None):
232 # Now check that the sending works 234 # Now check that the sending works
233 result = self._call_sender_one_crash( 235 result = self._call_sender_one_crash(
234 username=username, 236 username=username,
235 report=os.path.basename(minidump_path)) 237 report=os.path.basename(payload_path))
236 if (not result['send_attempt'] or not result['send_success'] or 238 if (not result['send_attempt'] or not result['send_success'] or
237 result['report_exists']): 239 result['report_exists']):
238 raise error.TestFail('Minidump not sent properly') 240 raise error.TestFail('Report not sent properly')
239 if will_syslog_give_name: 241 if result['exec_name'] != exec_name:
240 if result['exec_name'] != crasher_basename: 242 raise error.TestFail('Executable name incorrect')
241 raise error.TestFail('Executable name incorrect') 243 if result['report_kind'] != report_kind:
242 if result['report_kind'] != 'minidump':
243 raise error.TestFail('Expected a minidump report') 244 raise error.TestFail('Expected a minidump report')
244 if result['report_payload'] != minidump_path: 245 if result['report_payload'] != payload_path:
245 raise error.TestFail('Sent the wrong minidump payload') 246 raise error.TestFail('Sent the wrong minidump payload')
246 if result['meta_path'] != meta_path: 247 if result['meta_path'] != meta_path:
247 raise error.TestFail('Used the wrong meta file') 248 raise error.TestFail('Used the wrong meta file')
248 if result['sig'] is not None: 249 if expected_sig is None:
249 raise error.TestFail('User crash should not have signature') 250 if result['sig'] is not None:
251 raise error.TestFail('Report should not have signature')
252 else:
253 if not 'sig' in result or result['sig'] != expected_sig:
254 raise error.TestFail('Report signature mismatch: %s vs %s' %
255 (result['sig'], expected_sig))
250 256
251 # Check version matches. 257 # Check version matches.
252 lsb_release = utils.read_file('/etc/lsb-release') 258 lsb_release = utils.read_file('/etc/lsb-release')
253 version_match = re.search(r'CHROMEOS_RELEASE_VERSION=(.*)', lsb_release) 259 version_match = re.search(r'CHROMEOS_RELEASE_VERSION=(.*)', lsb_release)
254 if not ('Version: %s' % version_match.group(1)) in result['output']: 260 if not ('Version: %s' % version_match.group(1)) in result['output']:
255 raise error.TestFail('Did not find version %s in log output' % 261 raise error.TestFail('Did not find version %s in log output' %
256 version_match.group(1)) 262 version_match.group(1))
257 263
258 264
259 def _check_crashing_process(self, username, consent=True): 265 def _run_crasher_process_and_analyze(self, username,
266 cause_crash=True, consent=True):
260 self._log_reader.set_start_by_current() 267 self._log_reader.set_start_by_current()
261 268
262 result = self._run_crasher_process(username, consent=consent) 269 result = self._run_crasher_process(username, cause_crash=cause_crash,
270 consent=consent)
263 271
264 if not result['crashed']: 272 if not result['crashed'] or not result['crash_reporter_caught']:
265 raise error.TestFail('crasher did not do its job of crashing: %d' % 273 return result;
266 result['returncode'])
267
268 if not result['crash_reporter_caught']:
269 logging.debug('Messages that should have included segv: %s' %
270 self._log_reader.get_logs())
271 raise error.TestFail('Did not find segv message')
272 274
273 crash_dir = self._get_crash_dir(username) 275 crash_dir = self._get_crash_dir(username)
274 276
275 if not consent: 277 if not consent:
276 if os.path.exists(crash_dir): 278 if os.path.exists(crash_dir):
277 raise error.TestFail('Crash directory should not exist') 279 raise error.TestFail('Crash directory should not exist')
278 return 280 return result
279 281
280 crash_contents = os.listdir(crash_dir) 282 crash_contents = os.listdir(crash_dir)
281 basename = os.path.basename(self._crasher_path) 283 basename = os.path.basename(self._crasher_path)
282 284
283 breakpad_minidump = None 285 breakpad_minidump = None
284 crash_reporter_minidump = None 286 crash_reporter_minidump = None
285 crash_reporter_meta = None 287 crash_reporter_meta = None
288 crash_reporter_log = None
286 289
287 self._check_crash_directory_permissions(crash_dir) 290 self._check_crash_directory_permissions(crash_dir)
288 291
289 logging.debug('Contents in %s: %s' % (crash_dir, crash_contents)) 292 logging.debug('Contents in %s: %s' % (crash_dir, crash_contents))
290 293
291 for filename in crash_contents: 294 for filename in crash_contents:
292 if filename.endswith('.core'): 295 if filename.endswith('.core'):
293 # Ignore core files. We'll test them later. 296 # Ignore core files. We'll test them later.
294 pass 297 pass
295 elif (filename.startswith(basename) and 298 elif (filename.startswith(basename) and
296 filename.endswith('.dmp')): 299 filename.endswith('.dmp')):
297 # This appears to be a minidump created by the crash reporter. 300 # This appears to be a minidump created by the crash reporter.
298 if not crash_reporter_minidump is None: 301 if not crash_reporter_minidump is None:
299 raise error.TestFail('Crash reporter wrote multiple ' 302 raise error.TestFail('Crash reporter wrote multiple '
300 'minidumps') 303 'minidumps')
301 crash_reporter_minidump = os.path.join(crash_dir, filename) 304 crash_reporter_minidump = os.path.join(crash_dir, filename)
302 elif (filename.startswith(basename) and 305 elif (filename.startswith(basename) and
303 filename.endswith('.meta')): 306 filename.endswith('.meta')):
304 if not crash_reporter_meta is None: 307 if not crash_reporter_meta is None:
305 raise error.TestFail('Crash reported wrote multiple ' 308 raise error.TestFail('Crash reporter wrote multiple '
306 'meta files') 309 'meta files')
307 crash_reporter_meta = os.path.join(crash_dir, filename) 310 crash_reporter_meta = os.path.join(crash_dir, filename)
311 elif (filename.startswith(basename) and
312 filename.endswith('.log')):
313 if not crash_reporter_log is None:
314 raise error.TestFail('Crash reporter wrote multiple '
315 'log files')
316 crash_reporter_log = os.path.join(crash_dir, filename)
308 else: 317 else:
309 # This appears to be a breakpad created minidump. 318 # This appears to be a breakpad created minidump.
310 if not breakpad_minidump is None: 319 if not breakpad_minidump is None:
311 raise error.TestFail('Breakpad wrote multimpe minidumps') 320 raise error.TestFail('Breakpad wrote multimpe minidumps')
312 breakpad_minidump = os.path.join(crash_dir, filename) 321 breakpad_minidump = os.path.join(crash_dir, filename)
313 322
314 if breakpad_minidump: 323 if breakpad_minidump:
315 raise error.TestFail('%s did generate breakpad minidump' % basename) 324 raise error.TestFail('%s did generate breakpad minidump' % basename)
316 325
317 if not crash_reporter_minidump:
318 raise error.TestFail('crash reporter did not generate minidump')
319
320 if not crash_reporter_meta: 326 if not crash_reporter_meta:
321 raise error.TestFail('crash reporter did not generate meta') 327 raise error.TestFail('crash reporter did not generate meta')
322 328
329 result['minidump'] = crash_reporter_minidump
330 result['basename'] = basename
331 result['meta'] = crash_reporter_meta
332 result['log'] = crash_reporter_log
333 return result
334
335
336 def _check_crashed_and_caught(self, result):
337 if not result['crashed']:
338 raise error.TestFail('crasher did not do its job of crashing: %d' %
339 result['returncode'])
340
341 if not result['crash_reporter_caught']:
342 logging.debug('Messages that should have included segv: %s' %
343 self._log_reader.get_logs())
344 raise error.TestFail('Did not find segv message')
345
346
347 def _check_crashing_process(self, username, consent=True):
348 result = self._run_crasher_process_and_analyze(username,
349 consent=consent)
350
351 self._check_crashed_and_caught(result)
352
353 if not consent:
354 return
355
356 if not result['minidump']:
357 raise error.TestFail('crash reporter did not generate minidump')
358
323 if not self._log_reader.can_find('Stored minidump to ' + 359 if not self._log_reader.can_find('Stored minidump to ' +
324 crash_reporter_minidump): 360 result['minidump']):
325 raise error.TestFail('crash reporter did not announce minidump') 361 raise error.TestFail('crash reporter did not announce minidump')
326 362
327 if crash_reporter_minidump: 363 self._check_minidump_stackwalk(result['minidump'],
328 self._check_minidump_stackwalk(crash_reporter_minidump, 364 result['basename'],
329 basename, 365 from_crash_reporter=True)
330 from_crash_reporter=True) 366 self._check_generated_report_sending(result['meta'],
331 will_syslog_give_name = True 367 result['minidump'],
332 368 username,
333 self._check_generated_minidump_sending(crash_reporter_meta, 369 result['basename'],
334 crash_reporter_minidump, 370 'minidump')
335 username,
336 basename,
337 will_syslog_give_name)
338 371
339 def _test_no_crash(self): 372 def _test_no_crash(self):
340 """Test a program linked against libcrash_dumper can exit normally.""" 373 """Test a program linked against libcrash_dumper can exit normally."""
341 self._log_reader.set_start_by_current() 374 self._log_reader.set_start_by_current()
342 result = self._run_crasher_process(username='root', 375 result = self._run_crasher_process_and_analyze(username='root',
343 cause_crash=False) 376 cause_crash=False)
344 if (result['crashed'] or 377 if (result['crashed'] or
345 result['crash_reporter_caught'] or 378 result['crash_reporter_caught'] or
346 result['returncode'] != 0): 379 result['returncode'] != 0):
347 raise error.TestFail('Normal exit of program with dumper failed') 380 raise error.TestFail('Normal exit of program with dumper failed')
348 381
349 382
350 def _test_chronos_crasher(self): 383 def _test_chronos_crasher(self):
351 """Test a user space crash when running as chronos is handled.""" 384 """Test a user space crash when running as chronos is handled."""
352 self._check_crashing_process('chronos') 385 self._check_crashing_process('chronos')
353 386
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 if not self._log_reader.can_find(full_message): 435 if not self._log_reader.can_find(full_message):
403 raise error.TestFail('expected full message: ' + full_message) 436 raise error.TestFail('expected full message: ' + full_message)
404 437
405 if crash_dir_size != len(os.listdir(crash_dir)): 438 if crash_dir_size != len(os.listdir(crash_dir)):
406 utils.system('ls -l %s' % crash_dir) 439 utils.system('ls -l %s' % crash_dir)
407 raise error.TestFail('expected no new files (now %d were %d)', 440 raise error.TestFail('expected no new files (now %d were %d)',
408 len(os.listdir(crash_dir)), 441 len(os.listdir(crash_dir)),
409 crash_dir_size) 442 crash_dir_size)
410 443
411 444
445 def _check_collection_failure(self, test_option, failure_string):
446 # Add parameter to core_pattern.
447 old_core_pattern = utils.read_file(_CORE_PATTERN)[:-1]
448 try:
449 utils.system('echo "%s %s" > %s' % (old_core_pattern, test_option,
petkov 2010/10/28 22:30:50 You could use utils.write_one_line here and below.
450 _CORE_PATTERN))
451 result = self._run_crasher_process_and_analyze('root',
452 consent=True)
453 self._check_crashed_and_caught(result)
454 if not self._log_reader.can_find(failure_string):
455 raise error.TestFail('Did not find fail string in log %s' %
456 failure_string)
457 if result['minidump']:
458 raise error.TestFail('failed collection resulted in minidump')
459 if not result['log']:
460 raise error.TestFail('failed collection had no log')
461 log_contents = utils.read_file(result['log'])
462 if not log_contents.startswith(failure_string):
463 raise error.TestFail('Expected logged error '
464 '\"%s\" was \"%s\"' %
465 (failure_string, log_contents))
466 self._check_generated_report_sending(result['meta'],
467 result['log'],
468 'root',
469 result['basename'],
470 'log',
471 _COLLECTION_ERROR_SIGNATURE)
472 finally:
473 utils.system('echo "%s" > %s' % (old_core_pattern, _CORE_PATTERN))
474
475
476 def _test_core2md_failure(self):
477 self._check_collection_failure('--core2md_failure_test',
478 'Problem during %s [result=1]: Usage:' %
479 _CORE2MD_PATH)
480
481
482 def _test_internal_directory_failure(self):
483 self._check_collection_failure('--directory_failure_test',
484 'Purposefully failing to create')
485
486
412 def _check_core_file_persisting(self, expect_persist): 487 def _check_core_file_persisting(self, expect_persist):
413 self._log_reader.set_start_by_current() 488 self._log_reader.set_start_by_current()
414 489
415 result = self._run_crasher_process('root') 490 result = self._run_crasher_process('root')
416 491
417 if not result['crashed']: 492 if not result['crashed']:
418 raise error.TestFail('crasher did not crash') 493 raise error.TestFail('crasher did not crash')
419 494
420 crash_contents = os.listdir(self._get_crash_dir('root')) 495 crash_contents = os.listdir(self._get_crash_dir('root'))
421 496
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 549
475 def run_once(self): 550 def run_once(self):
476 self.run_crash_tests(['reporter_startup', 551 self.run_crash_tests(['reporter_startup',
477 'reporter_shutdown', 552 'reporter_shutdown',
478 'no_crash', 553 'no_crash',
479 'chronos_crasher', 554 'chronos_crasher',
480 'chronos_crasher_no_consent', 555 'chronos_crasher_no_consent',
481 'root_crasher', 556 'root_crasher',
482 'root_crasher_no_consent', 557 'root_crasher_no_consent',
483 'max_enqueued_crashes', 558 'max_enqueued_crashes',
559 'core2md_failure',
560 'internal_directory_failure',
484 'core_file_persists_in_debug', 561 'core_file_persists_in_debug',
485 'core_file_removed_in_production'], 562 'core_file_removed_in_production'],
486 initialize_crash_reporter = True) 563 initialize_crash_reporter = True)
OLDNEW
« no previous file with comments | « client/site_tests/logging_KernelCrash/logging_KernelCrash.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698