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 logging, os, re, shutil | 5 import logging, os |
6 from autotest_lib.server import test, autotest | 6 |
7 from autotest_lib.client.common_lib import error | 7 from autotest_lib.client.common_lib import error |
| 8 from autotest_lib.client.cros.crash_test import CrashTest as CrashTestDefs |
| 9 from autotest_lib.server import test |
8 | 10 |
9 class platform_KernelErrorPaths(test.test): | 11 class platform_KernelErrorPaths(test.test): |
10 version = 1 | 12 version = 1 |
11 | 13 |
12 def breakme(self, command): | 14 def breakme(self, text): |
13 logging.info('KernelErrorPaths: causing %s on host %s' % | 15 command = "echo %s > /proc/breakme" % text |
| 16 logging.info("KernelErrorPaths: executing '%s' on %s" % |
14 (command, self.client.hostname)) | 17 (command, self.client.hostname)) |
15 try: | 18 try: |
16 self.client.run("echo %s > /proc/breakme" % command) | 19 # Simple sending text into /proc/breakme resets the target |
| 20 # immediately, leaving files unsaved to disk and the master ssh |
| 21 # connection wedged for a long time. The sequence below borrowed |
| 22 # from logging_KernelCrashServer.py makes sure that the test |
| 23 # proceeds smoothly. |
| 24 self.client.run( |
| 25 'sh -c "sync; sleep 1; %s" >/dev/null 2>&1 &' % command) |
17 except error.AutoservRunError, e: | 26 except error.AutoservRunError, e: |
18 # it is expected that this will cause a non-zero exit status | 27 # It is expected that this will cause a non-zero exit status. |
19 pass | 28 pass |
20 | 29 |
| 30 def configure_crash_reporting(self): |
| 31 self._preserved_files = [] |
| 32 for f in (CrashTestDefs._PAUSE_FILE, CrashTestDefs._CONSENT_FILE): |
| 33 result = self.client.run('ls -1 "%s"' % os.path.dirname(f)) |
| 34 if os.path.basename(f) in result.stdout.splitlines(): |
| 35 result = self.client.run('cat "%s"' % f) |
| 36 self._preserved_files.append((f, result.stdout)) |
| 37 else: |
| 38 self._preserved_files.append((f, None)) |
21 | 39 |
22 def test_bug(self): | 40 self.client.run('touch "%s"' % CrashTestDefs._PAUSE_FILE) |
23 """ | 41 self.client.run( |
24 Cause the target to log a kernel bug, and then check in the | 42 'echo test-consent > "%s"' % CrashTestDefs._CONSENT_FILE) |
25 messages to make sure it did. | |
26 """ | |
27 # Clear the messages so we can compare. | |
28 self.client.run('dmesg -c') | |
29 # Cause the client to report a kernel BUG. | |
30 self.breakme('bug') | |
31 # Now get messages and check to make sure it's in there. | |
32 result = self.client.run('dmesg') | |
33 marker = "Kernel BUG at" | |
34 found = False | |
35 for line in result.stdout.split('\n'): | |
36 if line.find(marker) != -1: | |
37 found = True | |
38 break | |
39 if not found: | |
40 raise error.TestFail("Kernel BUG reporting not working.") | |
41 | 43 |
42 | 44 def cleanup(self): |
43 def test_deadlock(self): | 45 for f, text in self._preserved_files: |
44 # Cause the target to go into a deadlock (have to run it twice). | 46 if text is None: |
45 self.breakme('deadlock') | 47 self.client.run('rm -f "%s"' % f) |
46 self.breakme('deadlock') | 48 continue |
47 | 49 self.client.run('cat <<EOF >"%s"\n%s\nEOF\n' % (f, text)) |
48 | 50 test.test.cleanup(self) |
49 def test_soft_lockup(self): | |
50 # Cause the target to go into an infinite loop. | |
51 self.breakme('softlockup') | |
52 | |
53 | |
54 def test_irq_lockup(self): | |
55 # Cause the target to go into a lockup with interrupts enabled. | |
56 self.breakme('irqlockup') | |
57 | |
58 | |
59 def test_no_irq_lockup(self): | |
60 # Cause the target to go into a lockup with interrupts disabled. | |
61 self.breakme('nmiwatchdog') | |
62 | |
63 | |
64 def test_null_dereference(self): | |
65 # Clear the messages so we can compare. | |
66 self.client.run('dmesg -c') | |
67 # Cause the target to dereference a null pointer. | |
68 self.breakme('nullptr') | |
69 # Now get messages and check to make sure it was noticed. | |
70 result = self.client.run('dmesg') | |
71 found = False | |
72 marker = "BUG: unable to handle kernel NULL pointer dereference" | |
73 for line in result.stdout.split('\n'): | |
74 if line.find(marker) != -1: | |
75 found = True | |
76 break | |
77 if not found: | |
78 raise error.TestFail("Kernel NULL pointer dereference detection " | |
79 "not working.") | |
80 | |
81 | |
82 def test_panic(self): | |
83 # Cause the target to panic. | |
84 self.breakme('panic') | |
85 if not self.client.wait_down(timeout=30): | |
86 raise error.TestFail("Kernel panic went unnoticed.") | |
87 if not self.client.wait_up(timeout=40): | |
88 raise error.TestFail("Kernel panic didn't cause successful reboot.") | |
89 | |
90 | 51 |
91 def run_once(self, host=None): | 52 def run_once(self, host=None): |
92 self.client = host | 53 self.client = host |
| 54 self.configure_crash_reporting() |
93 | 55 |
94 self.test_bug() | 56 crash_log_dir = CrashTestDefs._SYSTEM_CRASH_DIR |
95 # TODO: Fill in the tests for these. | 57 |
96 # self.test_deadlock() | 58 # Each tuple consists of two strings: the 'breakme' string to send |
97 # self.test_soft_lockup() | 59 # into /proc/breakme on the target, and the crash report string to |
98 # self.test_irq_lockup() | 60 # look for in the crash dump after target restarts. |
99 # self.test_no_irq_lockup() | 61 # TODO(vbendeb): add the following breakme strings after fixing kernel |
100 self.test_null_dereference() | 62 # bugs: |
101 # TODO(mbligh): crosbug.com/2269 - panic currently halts the | 63 # 'deadlock' (has to be sent twice), 'softlockup', 'irqlockup' |
102 # DUT instead of rebooting it. Commenting out until | 64 test_tuples = ( |
103 # fixed. | 65 ('bug', 'kernel BUG at'), |
104 #self.test_panic() | 66 ('nmiwatchdog', 'BUG: NMI Watchdog detected LOCKUP'), |
| 67 ('nullptr', |
| 68 'BUG: unable to handle kernel NULL pointer dereference at'), |
| 69 ('panic', 'Kernel panic - not syncing:'), |
| 70 ) |
| 71 |
| 72 for action, text in test_tuples: |
| 73 # Delete crash results, if any |
| 74 self.client.run('rm -f %s/*' % crash_log_dir) |
| 75 boot_id = self.client.get_boot_id() |
| 76 self.breakme(action) # This should cause target reset. |
| 77 self.client.wait_for_restart(timeout=25, old_boot_id=boot_id) |
| 78 result = self.client.run('cat %s/kernel.*.kcrash' % crash_log_dir) |
| 79 if text not in result.stdout: |
| 80 raise error.TestFail( |
| 81 "No '%s' in the log after sending '%s'" % (text, action)) |
OLD | NEW |