1b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa# Use of this source code is governed by a BSD-style license that can be
3b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa# found in the LICENSE file.
4b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
5b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosaimport logging
6b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosaimport time
7b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
8b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosafrom autotest_lib.client.common_lib import error
9b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosafrom autotest_lib.server import autotest, test
10c193217c55a11367708be5c25bd1c8e1857ab6ffChris Sosafrom autotest_lib.server.cros import autoupdate_utils
11b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
12b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
13b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosaclass platform_RebootAfterUpdate(test.test):
14b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    """Test that updates the machine, reboots, and logs in / logs out.
15b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
16b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    This test keeps a reboot timeout in order to keep the system boot times
17b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    regressing in performance. For example, if Chrome takes a long time to
18b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    shutdown / hangs, other tests have much longer timeouts (to prevent them
19b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    from being flaky) while this test targets these hangs. Note, this test only
20b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    has smaller timeouts for boot, not for login/logout. Also, these timeouts
21b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    are still fairly conservative and are only meant to catch large regressions
22b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    or hangs, not small regressions.
23b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
24b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    """
25b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    version = 1
26b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
27b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    _REBOOT_ERROR_MESSAGE = (
28b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            'System failed to restart within the timeout after '
29b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            '%(reason)s. This failure indicates that the system after '
30b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            'receiving a reboot request and restarting did not '
31b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            'reconnect via ssh within the timeout. Actual time %(actual)d '
32b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            'seconds vs expected time: %(expected)d seconds')
33b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
34b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    # Timeouts specific to this test. These should be as low as possible.
35b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
36b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    # Total amount of time to wait for a reboot to return.
375fb06ab458fcab3abee1b1dadb1b490b74cd6754Chris Sosa    _REBOOT_TIMEOUT = 120
38b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
39b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
40b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    @classmethod
41b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    def reboot_with_timeout(cls, host, reason):
42b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        """Reboots the device and checks to see if it completed within desired.
43b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
44b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        @param host: Autotest host object to reboot.
45b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        @param reason: string representing why we are rebooting e.g. autoupdate.
46b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
47b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        Raises:
48b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            error.TestFail: If it takes too long to reboot.
49b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        """
50b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        start_time = time.time()
51b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        host.reboot()
52b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        reboot_duration = time.time() - start_time
53b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        if reboot_duration > cls._REBOOT_TIMEOUT:
54b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            raise error.TestFail(
55b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa                cls._REBOOT_ERROR_MESSAGE % dict(
56b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa                        reason=reason, actual=reboot_duration,
57b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa                        expected=cls._REBOOT_TIMEOUT))
58b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
59b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
60b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa    def run_once(self, host, job_repo_url=None):
61b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        """Runs the test.
62b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
63b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        @param host: a host object representing the DUT
64b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        @param job_repo_url: URL to get the image.
65b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
66b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        @raise error.TestError if anything went wrong with setting up the test;
67b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa               error.TestFail if any part of the test has failed.
68b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
69b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        """
70c193217c55a11367708be5c25bd1c8e1857ab6ffChris Sosa        updater = autoupdate_utils.get_updater_from_repo_url(host, job_repo_url)
71b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        updater.update_stateful(clobber=True)
72b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
73b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        logging.info('Rebooting after performing update.')
74b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        self.reboot_with_timeout(host, 'update')
75b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
76b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # TODO(sosa): Ideally we would be able to just use
77b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # autotest.run_static_method to login/logout, however, this
78b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # functionality is currently nested deep into the test logic. Once
79b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # telemetry has replaced pyauto login and has been librarized, we
80b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # should switch to using that code and not have to rely on running a
81b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        # client test to do what we want.
82b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        logging.info('Running sanity desktop login to see that we can '
83b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa                     'login and logout after performing an update.')
84b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        client_at = autotest.Autotest(host)
85b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        self.job.set_state('client_success', False)
86a7dbfbc4cf0ab55cd217de345a98ccd605062a7dChris Masone        client_at.run_test('login_LoginSuccess')
87b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        if not self.job.get_state('client_success'):
88b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa            raise error.TestFail(
89b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa                    'Failed to login successfully after an update.')
90b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa
91b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        logging.info('Rebooting the DUT after first login/logout.')
92b76e0ee685a5808687d4ce657b39fb4c08647deaChris Sosa        self.reboot_with_timeout(host, 'first login')
93