blob: 23ed62a8d803d5c00df0d6f7580f29a0834afb62 [file] [log] [blame]
barfab@chromium.orgb6d29932012-04-11 09:46:43 +02001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ken Mixter20d9e472010-08-12 10:58:46 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysinger0fa79ab2014-05-24 21:16:04 -04005import contextlib, fcntl, logging, os, re, shutil
barfab@chromium.orgb6d29932012-04-11 09:46:43 +02006
Hsinyu Chaoe0b08e62015-08-11 10:50:37 +00007import common, constants, cros_logging
Eric Lie7c4cab2011-01-05 14:39:19 -08008from 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):
Simon Glassa47f0d72011-03-15 11:45:32 -070013 """
14 This class deals with running crash tests, which are tests which crash a
15 user-space program (or the whole machine) and generate a core dump. We
16 want to check that the correct crash dump is available and can be
17 retrieved.
18
19 Chromium OS has a crash sender which checks for new crash data and sends
20 it to a server. This crash data is used to track software quality and find
21 bugs. The system crash sender normally is always running, but can be paused
22 by creating _PAUSE_FILE. When crash sender sees this, it pauses operation.
23
24 The pid of the system crash sender is stored in _CRASH_SENDER_RUN_PATH so
25 we can use this to kill the system crash sender for when we want to run
26 our own.
27
28 For testing purposes we sometimes want to run the crash sender manually.
29 In this case we can set 'OVERRIDE_PAUSE_SENDING=1' in the environment and
30 run the crash sender manually (as a child process).
31
32 Also for testing we sometimes want to mock out the crash sender, and just
33 have it pretend to succeed or fail. The _MOCK_CRASH_SENDING file is used
34 for this. If it doesn't exist, then the crash sender runs normally. If
35 it exists but is empty, the crash sender will succeed (but actually do
36 nothing). If the file contains something, then the crash sender will fail.
37
38 If the user consents to sending crash tests, then the _CONSENT_FILE will
39 exist in the home directory. This test needs to create this file for the
40 crash sending to work.
41
42 Crash reports are rate limited to a certain number of reports each 24
43 hours. If the maximum number has already been sent then reports are held
44 until later. This is administered by a directory _CRASH_SENDER_RATE_DIR
45 which contains one temporary file for each time a report is sent.
46
47 The class provides the ability to push a consent file. This disables
48 consent for this test but allows it to be popped back at later. This
49 makes nested tests easier. If _automatic_consent_saving is True (the
50 default) then consent will be pushed at the start and popped at the end.
51
52 Interesting variables:
53 _log_reader: the log reader used for reading log files
54 _leave_crash_sending: True to enable crash sending on exit from the
55 test, False to disable it. (Default True).
56 _automatic_consent_saving: True to push the consent at the start of
57 the test and pop it afterwards. (Default True).
58
59 Useful places to look for more information are:
60
61 chromeos/src/platform/crash-reporter/crash_sender
62 - sender script which crash crash reporter to create reports, then
63
64 chromeos/src/platform/crash-reporter/
65 - crash reporter program
66 """
67
Ken Mixter20d9e472010-08-12 10:58:46 -070068
69 _CONSENT_FILE = '/home/chronos/Consent To Send Stats'
Ken Mixterddcd92d2010-11-01 19:07:08 -070070 _CORE_PATTERN = '/proc/sys/kernel/core_pattern'
Ken Mixter20d9e472010-08-12 10:58:46 -070071 _CRASH_REPORTER_PATH = '/sbin/crash_reporter'
72 _CRASH_SENDER_PATH = '/sbin/crash_sender'
73 _CRASH_SENDER_RATE_DIR = '/var/lib/crash_sender'
74 _CRASH_SENDER_RUN_PATH = '/var/run/crash_sender.pid'
Mike Frysinger0fa79ab2014-05-24 21:16:04 -040075 _CRASH_SENDER_LOCK_PATH = '/var/lock/crash_sender'
Thieu Lec16253b2011-03-03 11:13:54 -080076 _CRASH_TEST_IN_PROGRESS = '/tmp/crash-test-in-progress'
Ken Mixter20d9e472010-08-12 10:58:46 -070077 _MOCK_CRASH_SENDING = '/tmp/mock-crash-sending'
Ken Mixter38dfe852010-08-18 15:24:00 -070078 _PAUSE_FILE = '/var/lib/crash_sender_paused'
Ken Mixter20d9e472010-08-12 10:58:46 -070079 _SYSTEM_CRASH_DIR = '/var/spool/crash'
Mike Frysingerded8de72013-05-29 20:45:48 -040080 _FALLBACK_USER_CRASH_DIR = '/home/chronos/crash'
81 _USER_CRASH_DIRS = '/home/chronos/u-*/crash'
Ken Mixter20d9e472010-08-12 10:58:46 -070082
Mike Frysingerbb54bc82014-05-14 14:04:56 -040083 # Use the same file format as crash does normally:
84 # <basename>.#.#.#.meta
85 _FAKE_TEST_BASENAME = 'fake.1.2.3'
86
Ken Mixter4f619652010-10-18 12:11:18 -070087 def _set_system_sending(self, is_enabled):
88 """Sets whether or not the system crash_sender is allowed to run.
89
Simon Glassa47f0d72011-03-15 11:45:32 -070090 This is done by creating or removing _PAUSE_FILE.
91
Ken Mixter4f619652010-10-18 12:11:18 -070092 crash_sender may still be allowed to run if _set_child_sending is
Simon Glassa47f0d72011-03-15 11:45:32 -070093 called with True and it is run as a child process.
94
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -070095 @param is_enabled: True to enable crash_sender, False to disable it.
Simon Glassa47f0d72011-03-15 11:45:32 -070096 """
Ken Mixter20d9e472010-08-12 10:58:46 -070097 if is_enabled:
98 if os.path.exists(self._PAUSE_FILE):
99 os.remove(self._PAUSE_FILE)
100 else:
101 utils.system('touch ' + self._PAUSE_FILE)
102
103
Ken Mixter4f619652010-10-18 12:11:18 -0700104 def _set_child_sending(self, is_enabled):
Simon Glassa47f0d72011-03-15 11:45:32 -0700105 """Overrides crash sending enabling for child processes.
106
107 When the system crash sender is disabled this test can manually run
108 the crash sender as a child process. Normally this would do nothing,
109 but this function sets up crash_sender to ignore its disabled status
110 and do its job.
111
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700112 @param is_enabled: True to enable crash sending for child processes.
Simon Glassa47f0d72011-03-15 11:45:32 -0700113 """
Ken Mixter4f619652010-10-18 12:11:18 -0700114 if is_enabled:
115 os.environ['OVERRIDE_PAUSE_SENDING'] = "1"
116 else:
117 del os.environ['OVERRIDE_PAUSE_SENDING']
118
119
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700120 def _set_force_official(self, is_enabled):
121 """Sets whether or not reports will upload for unofficial versions.
122
123 Normally, crash reports are only uploaded for official build
124 versions. If the override is set, however, they will also be
125 uploaded for unofficial versions.
126
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700127 @param is_enabled: True to enable uploading for unofficial versions.
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700128 """
129 if is_enabled:
130 os.environ['FORCE_OFFICIAL'] = "1"
131 elif os.environ.get('FORCE_OFFICIAL'):
132 del os.environ['FORCE_OFFICIAL']
133
134
Michael Krebsfb875d02012-09-13 16:49:50 -0700135 def _set_mock_developer_mode(self, is_enabled):
136 """Sets whether or not we should pretend we booted in developer mode.
137
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700138 @param is_enabled: True to pretend we are in developer mode.
Michael Krebsfb875d02012-09-13 16:49:50 -0700139 """
140 if is_enabled:
141 os.environ['MOCK_DEVELOPER_MODE'] = "1"
142 elif os.environ.get('MOCK_DEVELOPER_MODE'):
143 del os.environ['MOCK_DEVELOPER_MODE']
144
145
Ken Mixter20d9e472010-08-12 10:58:46 -0700146 def _reset_rate_limiting(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700147 """Reset the count of crash reports sent today.
148
149 This clears the contents of the rate limiting directory which has
150 the effect of reseting our count of crash reports sent.
151 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700152 utils.system('rm -rf ' + self._CRASH_SENDER_RATE_DIR)
153
154
155 def _clear_spooled_crashes(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700156 """Clears system and user crash directories.
157
158 This will remove all crash reports which are waiting to be sent.
159 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700160 utils.system('rm -rf ' + self._SYSTEM_CRASH_DIR)
Mike Frysingerded8de72013-05-29 20:45:48 -0400161 utils.system('rm -rf %s %s' % (self._USER_CRASH_DIRS,
162 self._FALLBACK_USER_CRASH_DIR))
Ken Mixter20d9e472010-08-12 10:58:46 -0700163
164
165 def _kill_running_sender(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700166 """Kill the the crash_sender process if running.
167
168 We use the PID file to find the process ID, then kill it with signal 9.
169 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700170 if not os.path.exists(self._CRASH_SENDER_RUN_PATH):
171 return
172 running_pid = int(utils.read_file(self._CRASH_SENDER_RUN_PATH))
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700173 logging.warning('Detected running crash sender (%d), killing',
Ken Mixter20d9e472010-08-12 10:58:46 -0700174 running_pid)
175 utils.system('kill -9 %d' % running_pid)
176 os.remove(self._CRASH_SENDER_RUN_PATH)
177
178
179 def _set_sending_mock(self, mock_enabled, send_success=True):
Simon Glassa47f0d72011-03-15 11:45:32 -0700180 """Enables / disables mocking of the sending process.
181
182 This uses the _MOCK_CRASH_SENDING file to achieve its aims. See notes
183 at the top.
184
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700185 @param mock_enabled: If True, mocking is enabled, else it is disabled.
186 @param send_success: If mock_enabled this is True for the mocking to
Simon Glassa47f0d72011-03-15 11:45:32 -0700187 indicate success, False to indicate failure.
188 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700189 if mock_enabled:
190 if send_success:
191 data = ''
192 else:
193 data = '1'
194 logging.info('Setting sending mock')
195 utils.open_write_close(self._MOCK_CRASH_SENDING, data)
196 else:
197 utils.system('rm -f ' + self._MOCK_CRASH_SENDING)
198
199
200 def _set_consent(self, has_consent):
Simon Glassa47f0d72011-03-15 11:45:32 -0700201 """Sets whether or not we have consent to send crash reports.
202
203 This creates or deletes the _CONSENT_FILE to control whether
204 crash_sender will consider that it has consent to send crash reports.
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200205 It also copies a policy blob with the proper policy setting.
Simon Glassa47f0d72011-03-15 11:45:32 -0700206
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700207 @param has_consent: True to indicate consent, False otherwise
Simon Glassa47f0d72011-03-15 11:45:32 -0700208 """
Simran Basi9d3bdf32014-08-20 17:11:26 -0700209 autotest_cros_dir = os.path.dirname(__file__)
Ken Mixter20d9e472010-08-12 10:58:46 -0700210 if has_consent:
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700211 if os.path.isdir(constants.WHITELIST_DIR):
212 # Create policy file that enables metrics/consent.
Simran Basi9d3bdf32014-08-20 17:11:26 -0700213 shutil.copy('%s/mock_metrics_on.policy' % autotest_cros_dir,
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700214 constants.SIGNED_POLICY_FILE)
Simran Basi9d3bdf32014-08-20 17:11:26 -0700215 shutil.copy('%s/mock_metrics_owner.key' % autotest_cros_dir,
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700216 constants.OWNER_KEY_FILE)
Michael Krebsb4b6f6b2011-08-03 13:52:19 -0700217 # Create deprecated consent file. This is created *after* the
218 # policy file in order to avoid a race condition where chrome
219 # might remove the consent file if the policy's not set yet.
Michael Krebse9028fc2011-08-19 15:00:00 -0700220 # We create it as a temp file first in order to make the creation
221 # of the consent file, owned by chronos, atomic.
Michael Krebsb4b6f6b2011-08-03 13:52:19 -0700222 # See crosbug.com/18413.
Michael Krebse9028fc2011-08-19 15:00:00 -0700223 temp_file = self._CONSENT_FILE + '.tmp';
224 utils.open_write_close(temp_file, 'test-consent')
225 utils.system('chown chronos:chronos "%s"' % (temp_file))
226 shutil.move(temp_file, self._CONSENT_FILE)
Ken Mixter20d9e472010-08-12 10:58:46 -0700227 logging.info('Created ' + self._CONSENT_FILE)
228 else:
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700229 if os.path.isdir(constants.WHITELIST_DIR):
230 # Create policy file that disables metrics/consent.
Simran Basi9d3bdf32014-08-20 17:11:26 -0700231 shutil.copy('%s/mock_metrics_off.policy' % autotest_cros_dir,
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700232 constants.SIGNED_POLICY_FILE)
Simran Basi9d3bdf32014-08-20 17:11:26 -0700233 shutil.copy('%s/mock_metrics_owner.key' % autotest_cros_dir,
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700234 constants.OWNER_KEY_FILE)
Michael Krebsb4b6f6b2011-08-03 13:52:19 -0700235 # Remove deprecated consent file.
236 utils.system('rm -f "%s"' % (self._CONSENT_FILE))
Ken Mixter20d9e472010-08-12 10:58:46 -0700237
238
Thieu Lec16253b2011-03-03 11:13:54 -0800239 def _set_crash_test_in_progress(self, in_progress):
240 if in_progress:
241 utils.open_write_close(self._CRASH_TEST_IN_PROGRESS, 'in-progress')
242 logging.info('Created ' + self._CRASH_TEST_IN_PROGRESS)
243 else:
244 utils.system('rm -f "%s"' % (self._CRASH_TEST_IN_PROGRESS))
245
246
Ken Mixter20d9e472010-08-12 10:58:46 -0700247 def _get_pushed_consent_file_path(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700248 """Returns filename of the pushed consent file."""
Ken Mixter20d9e472010-08-12 10:58:46 -0700249 return os.path.join(self.bindir, 'pushed_consent')
250
251
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200252 def _get_pushed_policy_file_path(self):
253 """Returns filename of the pushed policy file."""
254 return os.path.join(self.bindir, 'pushed_policy')
255
256
257 def _get_pushed_owner_key_file_path(self):
258 """Returns filename of the pushed owner.key file."""
259 return os.path.join(self.bindir, 'pushed_owner_key')
260
261
Ken Mixter20d9e472010-08-12 10:58:46 -0700262 def _push_consent(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700263 """Push the consent file, thus disabling consent.
264
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200265 The consent files can be created in the new test if required. Call
Simon Glassa47f0d72011-03-15 11:45:32 -0700266 _pop_consent() to restore the original state.
267 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700268 if os.path.exists(self._CONSENT_FILE):
Dale Curtis497c2cb2010-11-16 13:44:33 -0800269 shutil.move(self._CONSENT_FILE,
270 self._get_pushed_consent_file_path())
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700271 if os.path.exists(constants.SIGNED_POLICY_FILE):
272 shutil.move(constants.SIGNED_POLICY_FILE,
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200273 self._get_pushed_policy_file_path())
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700274 if os.path.exists(constants.OWNER_KEY_FILE):
275 shutil.move(constants.OWNER_KEY_FILE,
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200276 self._get_pushed_owner_key_file_path())
Ken Mixter20d9e472010-08-12 10:58:46 -0700277
278
279 def _pop_consent(self):
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200280 """Pop the consent files, enabling/disabling consent as it was before
Simon Glassa47f0d72011-03-15 11:45:32 -0700281 we pushed the consent."""
Ken Mixter20d9e472010-08-12 10:58:46 -0700282 if os.path.exists(self._get_pushed_consent_file_path()):
Dale Curtis497c2cb2010-11-16 13:44:33 -0800283 shutil.move(self._get_pushed_consent_file_path(),
284 self._CONSENT_FILE)
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200285 else:
286 utils.system('rm -f "%s"' % self._CONSENT_FILE)
287 if os.path.exists(self._get_pushed_policy_file_path()):
288 shutil.move(self._get_pushed_policy_file_path(),
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700289 constants.SIGNED_POLICY_FILE)
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200290 else:
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700291 utils.system('rm -f "%s"' % constants.SIGNED_POLICY_FILE)
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200292 if os.path.exists(self._get_pushed_owner_key_file_path()):
293 shutil.move(self._get_pushed_owner_key_file_path(),
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700294 constants.OWNER_KEY_FILE)
Julian Pastarmovd56badb2011-07-15 20:24:45 +0200295 else:
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700296 utils.system('rm -f "%s"' % constants.OWNER_KEY_FILE)
Ken Mixter20d9e472010-08-12 10:58:46 -0700297
298
299 def _get_crash_dir(self, username):
Simon Glassa47f0d72011-03-15 11:45:32 -0700300 """Returns full path to the crash directory for a given username
301
Mike Frysingerded8de72013-05-29 20:45:48 -0400302 This only really works (currently) when no one is logged in. That
303 is OK (currently) as the only test that uses this runs when no one
304 is actually logged in.
305
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700306 @param username: username to use:
Simon Glassa47f0d72011-03-15 11:45:32 -0700307 'chronos': Returns user crash directory.
308 'root': Returns system crash directory.
309 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700310 if username == 'chronos':
Mike Frysingerded8de72013-05-29 20:45:48 -0400311 return self._FALLBACK_USER_CRASH_DIR
Ken Mixter20d9e472010-08-12 10:58:46 -0700312 else:
313 return self._SYSTEM_CRASH_DIR
314
315
316 def _initialize_crash_reporter(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700317 """Start up the crash reporter."""
Julius Werner43d39972016-03-25 15:56:08 -0700318 utils.system('%s --init' % self._CRASH_REPORTER_PATH)
Ken Mixterddcd92d2010-11-01 19:07:08 -0700319 # Completely disable crash_reporter from generating crash dumps
320 # while any tests are running, otherwise a crashy system can make
321 # these tests flaky.
322 self.enable_crash_filtering('none')
Ken Mixter20d9e472010-08-12 10:58:46 -0700323
324
Mike Frysingerbb54bc82014-05-14 14:04:56 -0400325 def get_crash_dir_name(self, name):
326 """Return the full path for |name| inside the system crash directory."""
327 return os.path.join(self._SYSTEM_CRASH_DIR, name)
328
329
Ken Mixter67ff5622010-09-30 15:32:17 -0700330 def write_crash_dir_entry(self, name, contents):
Simon Glassa47f0d72011-03-15 11:45:32 -0700331 """Writes an empty file to the system crash directory.
332
333 This writes a file to _SYSTEM_CRASH_DIR with the given name. This is
334 used to insert new crash dump files for testing purposes.
335
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700336 @param name: Name of file to write.
337 @param contents: String to write to the file.
Simon Glassa47f0d72011-03-15 11:45:32 -0700338 """
Mike Frysingerbb54bc82014-05-14 14:04:56 -0400339 entry = self.get_crash_dir_name(name)
Ken Mixter20d9e472010-08-12 10:58:46 -0700340 if not os.path.exists(self._SYSTEM_CRASH_DIR):
341 os.makedirs(self._SYSTEM_CRASH_DIR)
Ken Mixter67ff5622010-09-30 15:32:17 -0700342 utils.open_write_close(entry, contents)
Ken Mixter20d9e472010-08-12 10:58:46 -0700343 return entry
344
345
Ken Mixterdee4e292010-12-14 17:45:21 -0800346 def write_fake_meta(self, name, exec_name, payload, log=None,
347 complete=True):
Simon Glassa47f0d72011-03-15 11:45:32 -0700348 """Writes a fake meta entry to the system crash directory.
349
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700350 @param name: Name of file to write.
351 @param exec_name: Value for exec_name item.
352 @param payload: Value for payload item.
353 @param log: Value for log item.
354 @param complete: True to close off the record, otherwise leave it
Simon Glassa47f0d72011-03-15 11:45:32 -0700355 incomplete.
356 """
Ken Mixter1a894e02010-10-28 15:42:52 -0700357 last_line = ''
358 if complete:
359 last_line = 'done=1\n'
Ken Mixterdee4e292010-12-14 17:45:21 -0800360 contents = ('exec_name=%s\n'
361 'ver=my_ver\n'
362 'payload=%s\n'
363 '%s' % (exec_name, payload,
364 last_line))
365 if log:
366 contents = ('log=%s\n' % log) + contents
367 return self.write_crash_dir_entry(name, contents)
Ken Mixter67ff5622010-09-30 15:32:17 -0700368
369
Ken Mixter20d9e472010-08-12 10:58:46 -0700370 def _prepare_sender_one_crash(self,
371 send_success,
372 reports_enabled,
Ken Mixter38dfe852010-08-18 15:24:00 -0700373 report):
Simon Glassa47f0d72011-03-15 11:45:32 -0700374 """Create metadata for a fake crash report.
375
376 This enabled mocking of the crash sender, then creates a fake
377 crash report for testing purposes.
378
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700379 @param send_success: True to make the crash_sender success, False to
380 make it fail.
381 @param reports_enabled: True to enable consent to that reports will be
Simon Glassa47f0d72011-03-15 11:45:32 -0700382 sent.
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700383 @param report: Report to use for crash, if None we create one.
Simon Glassa47f0d72011-03-15 11:45:32 -0700384 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700385 self._set_sending_mock(mock_enabled=True, send_success=send_success)
386 self._set_consent(reports_enabled)
Ken Mixter38dfe852010-08-18 15:24:00 -0700387 if report is None:
Mike Frysingerbb54bc82014-05-14 14:04:56 -0400388 # Use the same file format as crash does normally:
389 # <basename>.#.#.#.meta
390 payload = self.write_crash_dir_entry(
391 '%s.dmp' % self._FAKE_TEST_BASENAME, '')
392 report = self.write_fake_meta(
393 '%s.meta' % self._FAKE_TEST_BASENAME, 'fake', payload)
Ken Mixter38dfe852010-08-18 15:24:00 -0700394 return report
Ken Mixter20d9e472010-08-12 10:58:46 -0700395
396
397 def _parse_sender_output(self, output):
398 """Parse the log output from the crash_sender script.
399
400 This script can run on the logs from either a mocked or true
401 crash send.
402
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700403 @param output: output from the script
Ken Mixter20d9e472010-08-12 10:58:46 -0700404
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700405 @returns A dictionary with these values:
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700406 error_type: an error type, if given
Ken Mixter38dfe852010-08-18 15:24:00 -0700407 exec_name: name of executable which crashed
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700408 image_type: type of image ("dev","force-official",...), if given
Michael Krebsfb875d02012-09-13 16:49:50 -0700409 boot_mode: current boot mode ("dev",...), if given
Ken Mixter67ff5622010-09-30 15:32:17 -0700410 meta_path: path to the report metadata file
411 output: the output from the script, copied
Ken Mixter38dfe852010-08-18 15:24:00 -0700412 report_kind: kind of report sent (minidump vs kernel)
Ken Mixter20d9e472010-08-12 10:58:46 -0700413 send_attempt: did the script attempt to send a crash.
414 send_success: if it attempted, was the crash send successful.
Ken Mixterd79140e2010-10-26 14:45:30 -0700415 sig: signature of the report, if given.
Ken Mixter20d9e472010-08-12 10:58:46 -0700416 sleep_time: if it attempted, how long did it sleep before
417 sending (if mocked, how long would it have slept)
Ken Mixter20d9e472010-08-12 10:58:46 -0700418 """
419 sleep_match = re.search('Scheduled to send in (\d+)s', output)
420 send_attempt = sleep_match is not None
421 if send_attempt:
422 sleep_time = int(sleep_match.group(1))
423 else:
424 sleep_time = None
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700425
Ken Mixter67ff5622010-09-30 15:32:17 -0700426 meta_match = re.search('Metadata: (\S+) \((\S+)\)', output)
427 if meta_match:
428 meta_path = meta_match.group(1)
429 report_kind = meta_match.group(2)
Ken Mixter38dfe852010-08-18 15:24:00 -0700430 else:
Ken Mixter67ff5622010-09-30 15:32:17 -0700431 meta_path = None
Ken Mixter38dfe852010-08-18 15:24:00 -0700432 report_kind = None
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700433
Ken Mixter67ff5622010-09-30 15:32:17 -0700434 payload_match = re.search('Payload: (\S+)', output)
435 if payload_match:
436 report_payload = payload_match.group(1)
437 else:
438 report_payload = None
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700439
Ken Mixter38dfe852010-08-18 15:24:00 -0700440 exec_name_match = re.search('Exec name: (\S+)', output)
441 if exec_name_match:
442 exec_name = exec_name_match.group(1)
443 else:
444 exec_name = None
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700445
Ken Mixter10c48672010-11-01 13:37:08 -0700446 sig_match = re.search('sig: (\S+)', output)
Ken Mixterd79140e2010-10-26 14:45:30 -0700447 if sig_match:
448 sig = sig_match.group(1)
449 else:
450 sig = None
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700451
452 error_type_match = re.search('Error type: (\S+)', output)
453 if error_type_match:
454 error_type = error_type_match.group(1)
455 else:
456 error_type = None
457
458 image_type_match = re.search('Image type: (\S+)', output)
459 if image_type_match:
460 image_type = image_type_match.group(1)
461 else:
462 image_type = None
463
Michael Krebsfb875d02012-09-13 16:49:50 -0700464 boot_mode_match = re.search('Boot mode: (\S+)', output)
465 if boot_mode_match:
466 boot_mode = boot_mode_match.group(1)
467 else:
468 boot_mode = None
469
Ken Mixter20d9e472010-08-12 10:58:46 -0700470 send_success = 'Mocking successful send' in output
Ken Mixter38dfe852010-08-18 15:24:00 -0700471 return {'exec_name': exec_name,
472 'report_kind': report_kind,
Ken Mixter67ff5622010-09-30 15:32:17 -0700473 'meta_path': meta_path,
474 'report_payload': report_payload,
Ken Mixter38dfe852010-08-18 15:24:00 -0700475 'send_attempt': send_attempt,
Ken Mixter20d9e472010-08-12 10:58:46 -0700476 'send_success': send_success,
Ken Mixterd79140e2010-10-26 14:45:30 -0700477 'sig': sig,
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700478 'error_type': error_type,
479 'image_type': image_type,
Michael Krebsfb875d02012-09-13 16:49:50 -0700480 'boot_mode': boot_mode,
Ken Mixter20d9e472010-08-12 10:58:46 -0700481 'sleep_time': sleep_time,
482 'output': output}
483
484
Ken Mixter654f32e2010-10-20 11:47:31 -0700485 def wait_for_sender_completion(self):
486 """Wait for crash_sender to complete.
487
488 Wait for no crash_sender's last message to be placed in the
489 system log before continuing and for the process to finish.
490 Otherwise we might get only part of the output."""
Eric Lie7c4cab2011-01-05 14:39:19 -0800491 utils.poll_for_condition(
Ken Mixter654f32e2010-10-20 11:47:31 -0700492 lambda: self._log_reader.can_find('crash_sender done.'),
493 timeout=60,
494 exception=error.TestError(
495 'Timeout waiting for crash_sender to emit done: ' +
496 self._log_reader.get_logs()))
Eric Lie7c4cab2011-01-05 14:39:19 -0800497 utils.poll_for_condition(
Ken Mixter654f32e2010-10-20 11:47:31 -0700498 lambda: utils.system('pgrep crash_sender',
499 ignore_status=True) != 0,
500 timeout=60,
501 exception=error.TestError(
502 'Timeout waiting for crash_sender to finish: ' +
503 self._log_reader.get_logs()))
504
505
Ken Mixter20d9e472010-08-12 10:58:46 -0700506 def _call_sender_one_crash(self,
507 send_success=True,
508 reports_enabled=True,
509 username='root',
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700510 report=None,
511 should_fail=False):
Ken Mixter20d9e472010-08-12 10:58:46 -0700512 """Call the crash sender script to mock upload one crash.
513
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700514 @param send_success: Mock a successful send if true
515 @param reports_enabled: Has the user consented to sending crash reports.
516 @param username: user to emulate a crash from
517 @param report: report to use for crash, if None we create one.
Ken Mixter20d9e472010-08-12 10:58:46 -0700518
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700519 @returns a dictionary describing the result with the keys
Ken Mixter20d9e472010-08-12 10:58:46 -0700520 from _parse_sender_output, as well as:
Ken Mixter38dfe852010-08-18 15:24:00 -0700521 report_exists: does the minidump still exist after calling
Ken Mixter20d9e472010-08-12 10:58:46 -0700522 send script
523 rate_count: how many crashes have been uploaded in the past
524 24 hours.
525 """
Ken Mixter38dfe852010-08-18 15:24:00 -0700526 report = self._prepare_sender_one_crash(send_success,
527 reports_enabled,
Ken Mixter38dfe852010-08-18 15:24:00 -0700528 report)
Ken Mixter20d9e472010-08-12 10:58:46 -0700529 self._log_reader.set_start_by_current()
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700530 script_output = ""
531 try:
532 script_output = utils.system_output(
533 '/bin/sh -c "%s" 2>&1' % self._CRASH_SENDER_PATH,
534 ignore_status=should_fail)
535 except error.CmdError as err:
536 raise error.TestFail('"%s" returned an unexpected non-zero '
537 'value (%s).'
538 % (err.command, err.result_obj.exit_status))
539
Ken Mixter654f32e2010-10-20 11:47:31 -0700540 self.wait_for_sender_completion()
Ken Mixter20d9e472010-08-12 10:58:46 -0700541 output = self._log_reader.get_logs()
542 logging.debug('Crash sender message output:\n' + output)
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700543
Ken Mixter20d9e472010-08-12 10:58:46 -0700544 if script_output != '':
Bertrand SIMONNET9347d362014-06-30 11:17:59 -0700545 logging.debug('crash_sender stdout/stderr: ' + script_output)
Ken Mixter20d9e472010-08-12 10:58:46 -0700546
Ken Mixter38dfe852010-08-18 15:24:00 -0700547 if os.path.exists(report):
548 report_exists = True
549 os.remove(report)
Ken Mixter20d9e472010-08-12 10:58:46 -0700550 else:
Ken Mixter38dfe852010-08-18 15:24:00 -0700551 report_exists = False
Ken Mixter20d9e472010-08-12 10:58:46 -0700552 if os.path.exists(self._CRASH_SENDER_RATE_DIR):
553 rate_count = len(os.listdir(self._CRASH_SENDER_RATE_DIR))
554 else:
555 rate_count = 0
556
557 result = self._parse_sender_output(output)
Ken Mixter38dfe852010-08-18 15:24:00 -0700558 result['report_exists'] = report_exists
Ken Mixter20d9e472010-08-12 10:58:46 -0700559 result['rate_count'] = rate_count
560
561 # Show the result for debugging but remove 'output' key
562 # since it's large and earlier in debug output.
563 debug_result = dict(result)
564 del debug_result['output']
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700565 logging.debug('Result of send (besides output): %s', debug_result)
Ken Mixter20d9e472010-08-12 10:58:46 -0700566
567 return result
568
569
Ken Mixterddcd92d2010-11-01 19:07:08 -0700570 def _replace_crash_reporter_filter_in(self, new_parameter):
Simon Glassa47f0d72011-03-15 11:45:32 -0700571 """Replaces the --filter_in= parameter of the crash reporter.
572
573 The kernel is set up to call the crash reporter with the core dump
574 as stdin when a process dies. This function adds a filter to the
575 command line used to call the crash reporter. This is used to ignore
576 crashes in which we have no interest.
577
578 This removes any --filter_in= parameter and optionally replaces it
579 with a new one.
580
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700581 @param new_parameter: This is parameter to add to the command line
Simon Glassa47f0d72011-03-15 11:45:32 -0700582 instead of the --filter_in=... that was there.
583 """
Ken Mixterddcd92d2010-11-01 19:07:08 -0700584 core_pattern = utils.read_file(self._CORE_PATTERN)[:-1]
585 core_pattern = re.sub('--filter_in=\S*\s*', '',
586 core_pattern).rstrip()
587 if new_parameter:
588 core_pattern += ' ' + new_parameter
589 utils.system('echo "%s" > %s' % (core_pattern, self._CORE_PATTERN))
590
591
592 def enable_crash_filtering(self, name):
Simon Glassa47f0d72011-03-15 11:45:32 -0700593 """Add a --filter_in argument to the kernel core dump cmdline.
594
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700595 @param name: Filter text to use. This is passed as a --filter_in
Simon Glassa47f0d72011-03-15 11:45:32 -0700596 argument to the crash reporter.
597 """
Ken Mixterddcd92d2010-11-01 19:07:08 -0700598 self._replace_crash_reporter_filter_in('--filter_in=' + name)
599
600
601 def disable_crash_filtering(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700602 """Remove the --filter_in argument from the kernel core dump cmdline.
603
604 Next time the crash reporter is invoked (due to a crash) it will not
605 receive a --filter_in paramter."""
Ken Mixterddcd92d2010-11-01 19:07:08 -0700606 self._replace_crash_reporter_filter_in('')
607
608
Mike Frysinger0fa79ab2014-05-24 21:16:04 -0400609 @contextlib.contextmanager
610 def hold_crash_lock(self):
611 """A context manager to hold the crash sender lock."""
612 with open(self._CRASH_SENDER_LOCK_PATH, 'w+') as f:
613 fcntl.flock(f.fileno(), fcntl.LOCK_EX)
614 try:
615 yield
616 finally:
617 fcntl.flock(f.fileno(), fcntl.LOCK_UN)
618
619
Ken Mixter20d9e472010-08-12 10:58:46 -0700620 def initialize(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700621 """Initalize the test."""
Ken Mixter20d9e472010-08-12 10:58:46 -0700622 test.test.initialize(self)
Andrey Ulanovca62e7d2015-10-14 15:48:23 -0700623 self._log_reader = cros_logging.make_system_log_reader()
Ken Mixter38dfe852010-08-18 15:24:00 -0700624 self._leave_crash_sending = True
Ken Mixter67ff5622010-09-30 15:32:17 -0700625 self._automatic_consent_saving = True
Ken Mixterddcd92d2010-11-01 19:07:08 -0700626 self.enable_crash_filtering('none')
Thieu Lec16253b2011-03-03 11:13:54 -0800627 self._set_crash_test_in_progress(True)
Ken Mixter20d9e472010-08-12 10:58:46 -0700628
629
630 def cleanup(self):
Simon Glassa47f0d72011-03-15 11:45:32 -0700631 """Cleanup after the test.
632
633 We reset things back to the way we think they should be. This is
634 intended to allow the system to continue normal operation.
635
636 Some variables silently change the behavior:
637 _automatic_consent_saving: if True, we pop the consent file.
638 _leave_crash_sending: True to enable crash sending, False to
639 disable it
640 """
Ken Mixter20d9e472010-08-12 10:58:46 -0700641 self._reset_rate_limiting()
642 self._clear_spooled_crashes()
Ken Mixter4f619652010-10-18 12:11:18 -0700643 self._set_system_sending(self._leave_crash_sending)
Ken Mixter20d9e472010-08-12 10:58:46 -0700644 self._set_sending_mock(mock_enabled=False)
Ken Mixter67ff5622010-09-30 15:32:17 -0700645 if self._automatic_consent_saving:
646 self._pop_consent()
Ken Mixterddcd92d2010-11-01 19:07:08 -0700647 self.disable_crash_filtering()
Thieu Lec16253b2011-03-03 11:13:54 -0800648 self._set_crash_test_in_progress(False)
Ken Mixter20d9e472010-08-12 10:58:46 -0700649 test.test.cleanup(self)
650
651
Ken Mixter38dfe852010-08-18 15:24:00 -0700652 def run_crash_tests(self,
653 test_names,
654 initialize_crash_reporter=False,
655 clear_spool_first=True,
656 must_run_all=True):
657 """Run crash tests defined in this class.
658
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700659 @param test_names: Array of test names.
660 @param initialize_crash_reporter: Should set up crash reporter for every
Simon Glassa47f0d72011-03-15 11:45:32 -0700661 run.
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700662 @param clear_spool_first: Clear all spooled user/system crashes before
Simon Glassa47f0d72011-03-15 11:45:32 -0700663 starting the test.
Bertrand SIMONNET72691dd2014-07-07 14:49:45 -0700664 @param must_run_all: Should make sure every test in this class is
Simon Glassa47f0d72011-03-15 11:45:32 -0700665 mentioned in test_names.
Ken Mixter38dfe852010-08-18 15:24:00 -0700666 """
Ken Mixter67ff5622010-09-30 15:32:17 -0700667 if self._automatic_consent_saving:
668 self._push_consent()
Ken Mixter20d9e472010-08-12 10:58:46 -0700669
Ken Mixter38dfe852010-08-18 15:24:00 -0700670 if must_run_all:
671 # Sanity check test_names is complete
672 for attr in dir(self):
673 if attr.find('_test_') == 0:
674 test_name = attr[6:]
675 if not test_name in test_names:
676 raise error.TestError('Test %s is missing' % test_name)
Ken Mixter20d9e472010-08-12 10:58:46 -0700677
678 for test_name in test_names:
679 logging.info(('=' * 20) + ('Running %s' % test_name) + ('=' * 20))
Ken Mixter38dfe852010-08-18 15:24:00 -0700680 if initialize_crash_reporter:
681 self._initialize_crash_reporter()
Ken Mixter4f619652010-10-18 12:11:18 -0700682 # Disable crash_sender from running, kill off any running ones, but
683 # set environment so crash_sender may run as a child process.
684 self._set_system_sending(False)
685 self._set_child_sending(True)
Ken Mixter20d9e472010-08-12 10:58:46 -0700686 self._kill_running_sender()
687 self._reset_rate_limiting()
Michael Krebs6cffa3d2012-09-06 20:09:11 -0700688 # Default to not overriding for unofficial versions.
689 self._set_force_official(False)
Michael Krebsfb875d02012-09-13 16:49:50 -0700690 # Default to not pretending we're in developer mode.
691 self._set_mock_developer_mode(False)
Ken Mixter38dfe852010-08-18 15:24:00 -0700692 if clear_spool_first:
693 self._clear_spooled_crashes()
Simon Glassa47f0d72011-03-15 11:45:32 -0700694
695 # Call the test function
Ken Mixter20d9e472010-08-12 10:58:46 -0700696 getattr(self, '_test_' + test_name)()