1# Copyright (c) 2012 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 logging
6import os
7
8from autotest_lib.client.common_lib.cros import kernel_utils
9from autotest_lib.client.cros import constants
10from autotest_lib.server import afe_utils
11from autotest_lib.server.cros import provisioner
12from autotest_lib.server.cros.update_engine import update_engine_test
13
14
15class autoupdate_EndToEndTest(update_engine_test.UpdateEngineTest):
16    """Complete update test between two Chrome OS releases.
17
18    Performs an end-to-end test of updating a ChromeOS device from one version
19    to another. The test performs the following steps:
20
21      - Stages the source (full) and target update payloads on a devserver.
22      - Installs source image on the DUT (if provided) and reboots to it.
23      - Verifies that sign in works correctly on the source image.
24      - Installs target image on the DUT and reboots.
25      - Does a final update check.
26      - Verifies that sign in works correctly on the target image.
27      - Returns the hostlogs collected during each update check for
28        verification against expected update events.
29
30    This class interacts with several others:
31    UpdateEngineTest: base class for comparing expected update events against
32                      the events listed in the hostlog.
33    UpdateEngineEvent: class representing a single expected update engine event.
34
35    """
36    version = 1
37
38    _LOGIN_TEST = 'login_LoginSuccess'
39
40
41    def cleanup(self):
42        """Save the logs from stateful_partition's preserved/log dir."""
43        stateful_preserved_logs = os.path.join(self.resultsdir,
44                                               '~stateful_preserved_logs')
45        os.makedirs(stateful_preserved_logs)
46        self._host.get_file(constants.AUTOUPDATE_PRESERVE_LOG,
47                            stateful_preserved_logs, safe_symlinks=True,
48                            preserve_perm=False)
49        super(autoupdate_EndToEndTest, self).cleanup()
50
51
52    def _print_rerun_command(self, test_conf):
53        """Prints the command to rerun a test run from the lab at your desk."""
54        logging.debug('Rerun this test run at your desk using this command:')
55        rerun_cmd = ('test_that <DUT NAME>.cros autoupdate_EndToEndTest '
56                     '--args="update_type=%s source_release=%s '
57                     'source_payload_uri=%s target_release=%s '
58                     'target_payload_uri=%s"')
59        rerun_cmd = rerun_cmd % (
60                test_conf['update_type'], test_conf['source_release'],
61                test_conf['source_payload_uri'], test_conf['target_release'],
62                test_conf['target_payload_uri'])
63        logging.debug(rerun_cmd)
64
65    def run_update_test(self, test_conf):
66        """Runs the update test and checks it succeeded.
67
68        @param test_conf: A dictionary containing test configuration values.
69
70        """
71        # Record the active root partition.
72        active, inactive = kernel_utils.get_kernel_state(self._host)
73        logging.info('Source active slot: %s', active)
74
75        source_release = test_conf['source_release']
76        target_release = test_conf['target_release']
77
78        self.update_device(test_conf['target_payload_uri'], tag='target')
79
80        # Compare hostlog events from the update to the expected ones.
81        rootfs, reboot = self._create_hostlog_files()
82        self.verify_update_events(source_release, rootfs)
83        self.verify_update_events(source_release, reboot, target_release)
84        kernel_utils.verify_boot_expectations(inactive, host=self._host)
85        logging.info('Update successful, test completed')
86
87
88    def run_once(self, test_conf):
89        """Performs a complete auto update test.
90
91        @param test_conf: a dictionary containing test configuration values.
92
93        """
94        logging.debug('The test configuration supplied: %s', test_conf)
95        self._print_rerun_command(test_conf)
96        self._autotest_devserver = self._get_devserver_for_test(test_conf)
97
98        afe_utils.clean_provision_labels(self._host)
99
100        # Install source image with quick-provision.
101        source_payload_uri = test_conf['source_payload_uri']
102        if source_payload_uri:
103            build_name, _ = self._get_update_parameters_from_uri(
104                source_payload_uri)
105            update_url = self._autotest_devserver.get_update_url(
106                build_name)
107            logging.info('Installing source image with update url: %s',
108                         update_url)
109
110            provisioner.ChromiumOSProvisioner(
111                    update_url, host=self._host,
112                    is_release_bucket=True).run_provision()
113
114            self._run_client_test_and_check_result(self._LOGIN_TEST,
115                                                   tag='source')
116        # Start the update to the target image.
117        self._stage_payloads(test_conf['target_payload_uri'],
118                             test_conf['target_archive_uri'])
119        self.run_update_test(test_conf)
120
121        # Check we can login after the update.
122        self._run_client_test_and_check_result(self._LOGIN_TEST, tag='target')
123