1# Copyright (c) 2013 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
5import gzip, logging, os, utils
6from autotest_lib.client.bin import utils
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.cros import crash_test
9
10
11class logging_UdevCrash(crash_test.CrashTest):
12    """Verify udev triggered crash works as expected."""
13    version = 1
14
15
16    def CheckAtmelCrashes(self):
17        """Check proper Atmel trackpad crash reports are created."""
18        if not os.path.exists(self._SYSTEM_CRASH_DIR):
19              return False
20
21        for filename in os.listdir(self._SYSTEM_CRASH_DIR):
22            if not filename.startswith('change__i2c_atmel_mxt_ts'):
23                raise error.TestFail('Crash report %s has wrong name' %
24                                     filename)
25            if filename.endswith('meta'):
26                continue
27
28            filepath = os.path.join(self._SYSTEM_CRASH_DIR, filename)
29            if filename.endswith('.log.gz'):
30                f = gzip.open(filepath, 'r')
31            elif filename.endswith('.log'):
32                f = open(filepath)
33            else:
34                raise error.TestFail('Crash report %s has wrong extension' %
35                                     filename)
36
37            data = f.read()
38            # Check that we have seen the end of the file. Otherwise we could
39            # end up racing bwtween writing to the log file and reading/checking
40            # the log file.
41            if 'END-OF-LOG' not in data:
42                continue
43
44            lines = data.splitlines()
45            bad_lines = [x for x in lines if 'atmel_mxt_ts' not in x
46                                             and 'END-OF-LOG' not in x]
47            if bad_lines:
48                raise error.TestFail('Crash report contains invalid '
49                                     'content %s' % bad_lines)
50            return True
51
52        return False
53
54    def _test_udev_report_atmel(self):
55        """Test that atmel trackpad failure can trigger udev crash report."""
56        DRIVER_DIR = '/sys/bus/i2c/drivers/atmel_mxt_ts'
57        has_atmel_device = False
58        if os.path.exists(DRIVER_DIR):
59            for filename in os.listdir(DRIVER_DIR):
60                if os.path.isdir(os.path.join(DRIVER_DIR, filename)):
61                    has_atmel_device = True
62
63        if not has_atmel_device:
64            logging.info('No atmel device, skip the test')
65            return None
66
67        self._set_consent(True)
68
69        # Use udevadm to trigger a fake udev event representing atmel driver
70        # failure. The uevent match rule in 99-crash-reporter.rules is
71        # ACTION=="change", SUBSYSTEM=="i2c", DRIVER=="atmel_mxt_ts",
72        # ENV{ERROR}=="1" RUN+="/sbin/crash_reporter
73        # --udev=SUBSYSTEM=i2c-atmel_mxt_ts:ACTION=change"
74        utils.system('udevadm control --property=ERROR=1',
75                     ignore_status=True)
76        utils.system('udevadm trigger '
77                     '--action=change '
78                     '--subsystem-match=i2c '
79                     '--attr-match=driver=atmel_mxt_ts',
80                     ignore_status=True)
81        utils.system('udevadm control --property=ERROR=0',
82                     ignore_status=True)
83
84        utils.poll_for_condition(
85            self.CheckAtmelCrashes,
86            timeout=60,
87            exception=error.TestFail('No valid Atmel crash reports'))
88
89    def run_once(self):
90        self._automatic_consent_saving = True
91        self.run_crash_tests(['udev_report_atmel'], True)
92