blob: 069fdde62a3ecdf20026480a38291ba9b3816b46 [file] [log] [blame]
Ken Mixter20d9e472010-08-12 10:58:46 -07001# 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
Dale Curtis497c2cb2010-11-16 13:44:33 -08005import logging, os, re, shutil
Eric Lie7c4cab2011-01-05 14:39:19 -08006import common
7import cros_logging
8from autotest_lib.client.bin import test, utils
9from autotest_lib.client.common_lib import error
Ken Mixter20d9e472010-08-12 10:58:46 -070010
11
12class CrashTest(test.test):
13
14 _CONSENT_FILE = '/home/chronos/Consent To Send Stats'
Ken Mixterddcd92d2010-11-01 19:07:08 -070015 _CORE_PATTERN = '/proc/sys/kernel/core_pattern'
Ken Mixter20d9e472010-08-12 10:58:46 -070016 _CRASH_REPORTER_PATH = '/sbin/crash_reporter'
17 _CRASH_SENDER_PATH = '/sbin/crash_sender'
18 _CRASH_SENDER_RATE_DIR = '/var/lib/crash_sender'
19 _CRASH_SENDER_RUN_PATH = '/var/run/crash_sender.pid'
Thieu Lec16253b2011-03-03 11:13:54 -080020 _CRASH_TEST_IN_PROGRESS = '/tmp/crash-test-in-progress'
Ken Mixter20d9e472010-08-12 10:58:46 -070021 _MOCK_CRASH_SENDING = '/tmp/mock-crash-sending'
Ken Mixter38dfe852010-08-18 15:24:00 -070022 _PAUSE_FILE = '/var/lib/crash_sender_paused'
Ken Mixter20d9e472010-08-12 10:58:46 -070023 _SYSTEM_CRASH_DIR = '/var/spool/crash'
24 _USER_CRASH_DIR = '/home/chronos/user/crash'
25
Ken Mixter4f619652010-10-18 12:11:18 -070026 def _set_system_sending(self, is_enabled):
27 """Sets whether or not the system crash_sender is allowed to run.
28
29 crash_sender may still be allowed to run if _set_child_sending is
30 called with true and it is run as a child process."""
Ken Mixter20d9e472010-08-12 10:58:46 -070031 if is_enabled:
32 if os.path.exists(self._PAUSE_FILE):
33 os.remove(self._PAUSE_FILE)
34 else:
35 utils.system('touch ' + self._PAUSE_FILE)
36
37
Ken Mixter4f619652010-10-18 12:11:18 -070038 def _set_child_sending(self, is_enabled):
39 """Overrides crash sending enabling for child processes."""
40 if is_enabled:
41 os.environ['OVERRIDE_PAUSE_SENDING'] = "1"
42 else:
43 del os.environ['OVERRIDE_PAUSE_SENDING']
44
45
Ken Mixter20d9e472010-08-12 10:58:46 -070046 def _reset_rate_limiting(self):
47 utils.system('rm -rf ' + self._CRASH_SENDER_RATE_DIR)
48
49
50 def _clear_spooled_crashes(self):
51 utils.system('rm -rf ' + self._SYSTEM_CRASH_DIR)
52 utils.system('rm -rf ' + self._USER_CRASH_DIR)
53
54
55 def _kill_running_sender(self):
56 if not os.path.exists(self._CRASH_SENDER_RUN_PATH):
57 return
58 running_pid = int(utils.read_file(self._CRASH_SENDER_RUN_PATH))
59 logging.warning('Detected running crash sender (%d), killing' %
60 running_pid)
61 utils.system('kill -9 %d' % running_pid)
62 os.remove(self._CRASH_SENDER_RUN_PATH)
63
64
65 def _set_sending_mock(self, mock_enabled, send_success=True):
66 if mock_enabled:
67 if send_success:
68 data = ''
69 else:
70 data = '1'
71 logging.info('Setting sending mock')
72 utils.open_write_close(self._MOCK_CRASH_SENDING, data)
73 else:
74 utils.system('rm -f ' + self._MOCK_CRASH_SENDING)
75
76
77 def _set_consent(self, has_consent):
78 if has_consent:
79 utils.open_write_close(self._CONSENT_FILE, 'test-consent')
80 logging.info('Created ' + self._CONSENT_FILE)
81 else:
82 utils.system('rm -f "%s"' % (self._CONSENT_FILE))
83
84
Thieu Lec16253b2011-03-03 11:13:54 -080085 def _set_crash_test_in_progress(self, in_progress):
86 if in_progress:
87 utils.open_write_close(self._CRASH_TEST_IN_PROGRESS, 'in-progress')
88 logging.info('Created ' + self._CRASH_TEST_IN_PROGRESS)
89 else:
90 utils.system('rm -f "%s"' % (self._CRASH_TEST_IN_PROGRESS))
91
92
Ken Mixter20d9e472010-08-12 10:58:46 -070093 def _get_pushed_consent_file_path(self):
94 return os.path.join(self.bindir, 'pushed_consent')
95
96
97 def _push_consent(self):
98 if os.path.exists(self._CONSENT_FILE):
Dale Curtis497c2cb2010-11-16 13:44:33 -080099 shutil.move(self._CONSENT_FILE,
100 self._get_pushed_consent_file_path())
Ken Mixter20d9e472010-08-12 10:58:46 -0700101
102
103 def _pop_consent(self):
104 self._set_consent(False)
105 if os.path.exists(self._get_pushed_consent_file_path()):
Dale Curtis497c2cb2010-11-16 13:44:33 -0800106 shutil.move(self._get_pushed_consent_file_path(),
107 self._CONSENT_FILE)
Ken Mixter20d9e472010-08-12 10:58:46 -0700108
109
110 def _get_crash_dir(self, username):
111 if username == 'chronos':
112 return self._USER_CRASH_DIR
113 else:
114 return self._SYSTEM_CRASH_DIR
115
116
117 def _initialize_crash_reporter(self):
118 utils.system('%s --init --nounclean_check' % self._CRASH_REPORTER_PATH)
Ken Mixterddcd92d2010-11-01 19:07:08 -0700119 # Completely disable crash_reporter from generating crash dumps
120 # while any tests are running, otherwise a crashy system can make
121 # these tests flaky.
122 self.enable_crash_filtering('none')
Ken Mixter20d9e472010-08-12 10:58:46 -0700123
124
Ken Mixter67ff5622010-09-30 15:32:17 -0700125 def write_crash_dir_entry(self, name, contents):
Ken Mixter20d9e472010-08-12 10:58:46 -0700126 entry = os.path.join(self._SYSTEM_CRASH_DIR, name)
127 if not os.path.exists(self._SYSTEM_CRASH_DIR):
128 os.makedirs(self._SYSTEM_CRASH_DIR)
Ken Mixter67ff5622010-09-30 15:32:17 -0700129 utils.open_write_close(entry, contents)
Ken Mixter20d9e472010-08-12 10:58:46 -0700130 return entry
131
132
Ken Mixterdee4e292010-12-14 17:45:21 -0800133 def write_fake_meta(self, name, exec_name, payload, log=None,
134 complete=True):
Ken Mixter1a894e02010-10-28 15:42:52 -0700135 last_line = ''
136 if complete:
137 last_line = 'done=1\n'
Ken Mixterdee4e292010-12-14 17:45:21 -0800138 contents = ('exec_name=%s\n'
139 'ver=my_ver\n'
140 'payload=%s\n'
141 '%s' % (exec_name, payload,
142 last_line))
143 if log:
144 contents = ('log=%s\n' % log) + contents
145 return self.write_crash_dir_entry(name, contents)
Ken Mixter67ff5622010-09-30 15:32:17 -0700146
147
Ken Mixter20d9e472010-08-12 10:58:46 -0700148 def _prepare_sender_one_crash(self,
149 send_success,
150 reports_enabled,
151 username,
Ken Mixter38dfe852010-08-18 15:24:00 -0700152 report):
Ken Mixter20d9e472010-08-12 10:58:46 -0700153 self._set_sending_mock(mock_enabled=True, send_success=send_success)
154 self._set_consent(reports_enabled)
Ken Mixter38dfe852010-08-18 15:24:00 -0700155 if report is None:
Ken Mixter1a894e02010-10-28 15:42:52 -0700156 payload = self.write_crash_dir_entry('fake.dmp', '')
157 report = self.write_fake_meta('fake.meta', 'fake', payload)
Ken Mixter38dfe852010-08-18 15:24:00 -0700158 return report
Ken Mixter20d9e472010-08-12 10:58:46 -0700159
160
161 def _parse_sender_output(self, output):
162 """Parse the log output from the crash_sender script.
163
164 This script can run on the logs from either a mocked or true
165 crash send.
166
167 Args:
168 output: output from the script
169
170 Returns:
171 A dictionary with these values:
Ken Mixter38dfe852010-08-18 15:24:00 -0700172 exec_name: name of executable which crashed
Ken Mixter67ff5622010-09-30 15:32:17 -0700173 meta_path: path to the report metadata file
174 output: the output from the script, copied
Ken Mixter38dfe852010-08-18 15:24:00 -0700175 report_kind: kind of report sent (minidump vs kernel)
Ken Mixter20d9e472010-08-12 10:58:46 -0700176 send_attempt: did the script attempt to send a crash.
177 send_success: if it attempted, was the crash send successful.
Ken Mixterd79140e2010-10-26 14:45:30 -0700178 sig: signature of the report, if given.
Ken Mixter20d9e472010-08-12 10:58:46 -0700179 sleep_time: if it attempted, how long did it sleep before
180 sending (if mocked, how long would it have slept)
Ken Mixter20d9e472010-08-12 10:58:46 -0700181 """
182 sleep_match = re.search('Scheduled to send in (\d+)s', output)
183 send_attempt = sleep_match is not None
184 if send_attempt:
185 sleep_time = int(sleep_match.group(1))
186 else:
187 sleep_time = None
Ken Mixter67ff5622010-09-30 15:32:17 -0700188 meta_match = re.search('Metadata: (\S+) \((\S+)\)', output)
189 if meta_match:
190 meta_path = meta_match.group(1)
191 report_kind = meta_match.group(2)
Ken Mixter38dfe852010-08-18 15:24:00 -0700192 else:
Ken Mixter67ff5622010-09-30 15:32:17 -0700193 meta_path = None
Ken Mixter38dfe852010-08-18 15:24:00 -0700194 report_kind = None
Ken Mixter67ff5622010-09-30 15:32:17 -0700195 payload_match = re.search('Payload: (\S+)', output)
196 if payload_match:
197 report_payload = payload_match.group(1)
198 else:
199 report_payload = None
Ken Mixter38dfe852010-08-18 15:24:00 -0700200 exec_name_match = re.search('Exec name: (\S+)', output)
201 if exec_name_match:
202 exec_name = exec_name_match.group(1)
203 else:
204 exec_name = None
Ken Mixter10c48672010-11-01 13:37:08 -0700205 sig_match = re.search('sig: (\S+)', output)
Ken Mixterd79140e2010-10-26 14:45:30 -0700206 if sig_match:
207 sig = sig_match.group(1)
208 else:
209 sig = None
Ken Mixter20d9e472010-08-12 10:58:46 -0700210 send_success = 'Mocking successful send' in output
Ken Mixter38dfe852010-08-18 15:24:00 -0700211 return {'exec_name': exec_name,
212 'report_kind': report_kind,
Ken Mixter67ff5622010-09-30 15:32:17 -0700213 'meta_path': meta_path,
214 'report_payload': report_payload,
Ken Mixter38dfe852010-08-18 15:24:00 -0700215 'send_attempt': send_attempt,
Ken Mixter20d9e472010-08-12 10:58:46 -0700216 'send_success': send_success,
Ken Mixterd79140e2010-10-26 14:45:30 -0700217 'sig': sig,
Ken Mixter20d9e472010-08-12 10:58:46 -0700218 'sleep_time': sleep_time,
219 'output': output}
220
221
Ken Mixter654f32e2010-10-20 11:47:31 -0700222 def wait_for_sender_completion(self):
223 """Wait for crash_sender to complete.
224
225 Wait for no crash_sender's last message to be placed in the
226 system log before continuing and for the process to finish.
227 Otherwise we might get only part of the output."""
Eric Lie7c4cab2011-01-05 14:39:19 -0800228 utils.poll_for_condition(
Ken Mixter654f32e2010-10-20 11:47:31 -0700229 lambda: self._log_reader.can_find('crash_sender done.'),
230 timeout=60,
231 exception=error.TestError(
232 'Timeout waiting for crash_sender to emit done: ' +
233 self._log_reader.get_logs()))
Eric Lie7c4cab2011-01-05 14:39:19 -0800234 utils.poll_for_condition(
Ken Mixter654f32e2010-10-20 11:47:31 -0700235 lambda: utils.system('pgrep crash_sender',
236 ignore_status=True) != 0,
237 timeout=60,
238 exception=error.TestError(
239 'Timeout waiting for crash_sender to finish: ' +
240 self._log_reader.get_logs()))
241
242
Ken Mixter20d9e472010-08-12 10:58:46 -0700243 def _call_sender_one_crash(self,
244 send_success=True,
245 reports_enabled=True,
246 username='root',
Ken Mixter38dfe852010-08-18 15:24:00 -0700247 report=None):
Ken Mixter20d9e472010-08-12 10:58:46 -0700248 """Call the crash sender script to mock upload one crash.
249
250 Args:
251 send_success: Mock a successful send if true
252 reports_enabled: Has the user consented to sending crash reports.
253 username: user to emulate a crash from
Ken Mixter38dfe852010-08-18 15:24:00 -0700254 report: report to use for crash, if None we create one.
Ken Mixter20d9e472010-08-12 10:58:46 -0700255
256 Returns:
257 Returns a dictionary describing the result with the keys
258 from _parse_sender_output, as well as:
Ken Mixter38dfe852010-08-18 15:24:00 -0700259 report_exists: does the minidump still exist after calling
Ken Mixter20d9e472010-08-12 10:58:46 -0700260 send script
261 rate_count: how many crashes have been uploaded in the past
262 24 hours.
263 """
Ken Mixter38dfe852010-08-18 15:24:00 -0700264 report = self._prepare_sender_one_crash(send_success,
265 reports_enabled,
266 username,
267 report)
Ken Mixter20d9e472010-08-12 10:58:46 -0700268 self._log_reader.set_start_by_current()
269 script_output = utils.system_output(
270 '/bin/sh -c "%s" 2>&1' % self._CRASH_SENDER_PATH,
271 ignore_status=True)
Ken Mixter654f32e2010-10-20 11:47:31 -0700272 self.wait_for_sender_completion()
Ken Mixter20d9e472010-08-12 10:58:46 -0700273 output = self._log_reader.get_logs()
274 logging.debug('Crash sender message output:\n' + output)
275 if script_output != '':
276 raise error.TestFail(
277 'Unexpected crash_sender stdout/stderr: ' + script_output)
278
Ken Mixter38dfe852010-08-18 15:24:00 -0700279 if os.path.exists(report):
280 report_exists = True
281 os.remove(report)
Ken Mixter20d9e472010-08-12 10:58:46 -0700282 else:
Ken Mixter38dfe852010-08-18 15:24:00 -0700283 report_exists = False
Ken Mixter20d9e472010-08-12 10:58:46 -0700284 if os.path.exists(self._CRASH_SENDER_RATE_DIR):
285 rate_count = len(os.listdir(self._CRASH_SENDER_RATE_DIR))
286 else:
287 rate_count = 0
288
289 result = self._parse_sender_output(output)
Ken Mixter38dfe852010-08-18 15:24:00 -0700290 result['report_exists'] = report_exists
Ken Mixter20d9e472010-08-12 10:58:46 -0700291 result['rate_count'] = rate_count
292
293 # Show the result for debugging but remove 'output' key
294 # since it's large and earlier in debug output.
295 debug_result = dict(result)
296 del debug_result['output']
297 logging.debug('Result of send (besides output): %s' % debug_result)
298
299 return result
300
301
Ken Mixterddcd92d2010-11-01 19:07:08 -0700302 def _replace_crash_reporter_filter_in(self, new_parameter):
303 core_pattern = utils.read_file(self._CORE_PATTERN)[:-1]
304 core_pattern = re.sub('--filter_in=\S*\s*', '',
305 core_pattern).rstrip()
306 if new_parameter:
307 core_pattern += ' ' + new_parameter
308 utils.system('echo "%s" > %s' % (core_pattern, self._CORE_PATTERN))
309
310
311 def enable_crash_filtering(self, name):
312 self._replace_crash_reporter_filter_in('--filter_in=' + name)
313
314
315 def disable_crash_filtering(self):
316 self._replace_crash_reporter_filter_in('')
317
318
Ken Mixter20d9e472010-08-12 10:58:46 -0700319 def initialize(self):
320 test.test.initialize(self)
Eric Lie7c4cab2011-01-05 14:39:19 -0800321 self._log_reader = cros_logging.LogReader()
Ken Mixter38dfe852010-08-18 15:24:00 -0700322 self._leave_crash_sending = True
Ken Mixter67ff5622010-09-30 15:32:17 -0700323 self._automatic_consent_saving = True
Ken Mixterddcd92d2010-11-01 19:07:08 -0700324 self.enable_crash_filtering('none')
Thieu Lec16253b2011-03-03 11:13:54 -0800325 self._set_crash_test_in_progress(True)
Ken Mixter20d9e472010-08-12 10:58:46 -0700326
327
328 def cleanup(self):
329 self._reset_rate_limiting()
330 self._clear_spooled_crashes()
Ken Mixter4f619652010-10-18 12:11:18 -0700331 self._set_system_sending(self._leave_crash_sending)
Ken Mixter20d9e472010-08-12 10:58:46 -0700332 self._set_sending_mock(mock_enabled=False)
Ken Mixter67ff5622010-09-30 15:32:17 -0700333 if self._automatic_consent_saving:
334 self._pop_consent()
Ken Mixterddcd92d2010-11-01 19:07:08 -0700335 self.disable_crash_filtering()
Thieu Lec16253b2011-03-03 11:13:54 -0800336 self._set_crash_test_in_progress(False)
Ken Mixter20d9e472010-08-12 10:58:46 -0700337 test.test.cleanup(self)
338
339
Ken Mixter38dfe852010-08-18 15:24:00 -0700340 def run_crash_tests(self,
341 test_names,
342 initialize_crash_reporter=False,
343 clear_spool_first=True,
344 must_run_all=True):
345 """Run crash tests defined in this class.
346
347 Args:
348 test_names: array of test names
349 initialize_crash_reporter: should set up crash reporter for every run
350 must_run_all: should make sure every test in this class is mentioned
351 in test_names
352 """
Ken Mixter67ff5622010-09-30 15:32:17 -0700353 if self._automatic_consent_saving:
354 self._push_consent()
Ken Mixter20d9e472010-08-12 10:58:46 -0700355
Ken Mixter38dfe852010-08-18 15:24:00 -0700356 if must_run_all:
357 # Sanity check test_names is complete
358 for attr in dir(self):
359 if attr.find('_test_') == 0:
360 test_name = attr[6:]
361 if not test_name in test_names:
362 raise error.TestError('Test %s is missing' % test_name)
Ken Mixter20d9e472010-08-12 10:58:46 -0700363
364 for test_name in test_names:
365 logging.info(('=' * 20) + ('Running %s' % test_name) + ('=' * 20))
Ken Mixter38dfe852010-08-18 15:24:00 -0700366 if initialize_crash_reporter:
367 self._initialize_crash_reporter()
Ken Mixter4f619652010-10-18 12:11:18 -0700368 # Disable crash_sender from running, kill off any running ones, but
369 # set environment so crash_sender may run as a child process.
370 self._set_system_sending(False)
371 self._set_child_sending(True)
Ken Mixter20d9e472010-08-12 10:58:46 -0700372 self._kill_running_sender()
373 self._reset_rate_limiting()
Ken Mixter38dfe852010-08-18 15:24:00 -0700374 if clear_spool_first:
375 self._clear_spooled_crashes()
Ken Mixter20d9e472010-08-12 10:58:46 -0700376 getattr(self, '_test_' + test_name)()