1# Copyright (c) 2011 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
5# This test isn't really HW specific. It's testing /dev/watchdog API
6# to make sure it works as expected. The most robust implementations is
7# based on real HW but it doesn't have to be.
8
9import logging, re
10
11# http://docs.python.org/2/library/errno.html
12import errno
13
14from autotest_lib.client.common_lib import error
15from autotest_lib.server import test
16
17
18class platform_HWwatchdog(test.test):
19    """Test to make sure that /dev/watchdog will reboot the system."""
20
21    version = 1
22
23    def _stop_watchdog(self, wd_dev):
24        # HW watchdog is open and closed "properly".
25        try:
26            self.client.run('echo "V" > %s' % wd_dev);
27        except error.AutoservRunError, e:
28            raise error.TestError('write to %s failed (%s)' %
29                                  (wd_dev, errno.errorcode[e.errno]))
30
31    def _trig_watchdog(self, wd_dev):
32        # Test the machine will reboot if HW watchdog is open but NOT pet.
33        try:
34            self.client.run('echo "z" > %s' % wd_dev);
35        except error.AutoservRunError, e:
36            raise error.TestError('write to %s failed (%s)' %
37                                  (wd_dev, errno.errorcode[e.errno]))
38
39        logging.info("KernelHWpath: tickled watchdog on %s (%ds to reboot)",
40                     self.client.hostname, self._hw_interval)
41
42        # machine should became unpingable after lockup
43        # ...give 5 seconds slack...
44        wait_down = self._hw_interval + 5
45        if not self.client.wait_down(timeout=wait_down):
46            raise error.TestError('machine should be unpingable '
47                                  'within %d seconds' % wait_down)
48
49        # make sure the machine comes back,
50        # DHCP can take up to 45 seconds in odd cases.
51        if not self.client.wait_up(timeout=60):
52            raise error.TestError('machine did not reboot/ping within '
53                                  '60 seconds of HW reset')
54
55    def _exists_on_client(self, wd_dev):
56        return self.client.run('test -c "%s"' % wd_dev,
57                               ignore_status=True).exit_status == 0
58
59    # If daisydog is running, stop it so we can use /dev/watchdog
60    def _stop_daemon(self):
61        """If running, stop daisydog so we can use /dev/watchdog."""
62        self.client.run('stop daisydog', ignore_status=True)
63
64    def _start_daemon(self):
65        self.client.run('start daisydog', ignore_status=True)
66
67    def _query_hw_interval(self):
68        """Check how long the hardware interval is."""
69        output = self.client.run('daisydog -c').stdout
70        secs = re.findall(r'HW watchdog interval is (\d*) seconds', output)[0]
71        return int(secs)
72
73    def run_once(self, host=None):
74        self.client = host
75        wd_dev = '/dev/watchdog'
76
77        # If watchdog not present, just skip this test
78        if not self._exists_on_client(wd_dev):
79            logging.info("INFO: %s not present. Skipping test.", wd_dev)
80            return
81
82        self._stop_daemon()
83        self._hw_interval = self._query_hw_interval()
84        self._stop_watchdog(wd_dev)
85        self._trig_watchdog(wd_dev)
86        self._start_daemon()
87