1# Lint as: python2, python3
2# Copyright 2017 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.common_lib import lsbrelease_utils
11from autotest_lib.client.common_lib.cros import chrome
12from autotest_lib.client.cros.cellular import test_environment
13from autotest_lib.client.cros.update_engine import nebraska_wrapper
14from autotest_lib.client.cros.update_engine import update_engine_test
15
16class autoupdate_StartOOBEUpdate(update_engine_test.UpdateEngineTest):
17    """Starts a forced update at OOBE.
18
19    ChromeOS will restart when the update is complete so this test will just
20    start the update. The rest of the processing will be done in a server
21    side test.
22    """
23    version = 1
24
25
26    def initialize(self):
27        """Test setup."""
28        super(autoupdate_StartOOBEUpdate, self).initialize()
29        self._clear_custom_lsb_release()
30
31
32    def _navigate_to_oobe_update_screen(self):
33        """Navigates to the OOBE update check screen."""
34        timeout = 30
35        self._oobe.WaitForJavaScriptCondition(
36                "typeof Oobe == 'function' && typeof OobeAPI == 'object' && "
37                "Oobe.readyForTesting",
38                timeout=timeout)
39        self._oobe.WaitForJavaScriptCondition(
40                "OobeAPI.screens.WelcomeScreen.isVisible()", timeout=timeout)
41        self._oobe.ExecuteJavaScript(
42                "OobeAPI.screens.WelcomeScreen.clickNext()")
43
44        if not self._oobe.EvaluateJavaScript(
45                "OobeAPI.screens.NetworkScreen.shouldSkip()"):
46            self._oobe.WaitForJavaScriptCondition(
47                    "OobeAPI.screens.NetworkScreen.isVisible()",
48                    timeout=timeout)
49            self._oobe.ExecuteJavaScript(
50                    "OobeAPI.screens.NetworkScreen.clickNext()")
51
52        if not self._oobe.EvaluateJavaScript(
53                "OobeAPI.screens.EulaScreen.shouldSkip()"):
54            self._oobe.WaitForJavaScriptCondition(
55                    "OobeAPI.screens.EulaScreen.isVisible()", timeout=timeout)
56            self._oobe.WaitForJavaScriptCondition(
57                    "OobeAPI.screens.EulaScreen.nextButton.isEnabled()",
58                    timeout=timeout)
59            self._oobe.ExecuteJavaScript(
60                    "OobeAPI.screens.EulaScreen.clickNext()")
61
62        # TODO(yunkez): remove this check after M92 is in stable
63        if self._oobe.EvaluateJavaScript(
64                "typeof OobeAPI.screens.UpdateScreen == 'object'"):
65            self._oobe.WaitForJavaScriptCondition(
66                    "OobeAPI.screens.UpdateScreen.isVisible()",
67                    timeout=timeout)
68        else:
69            self._oobe.WaitForJavaScriptCondition("!$('oobe-update').hidden",
70                                                  timeout=timeout)
71
72    def _start_oobe_update(self, update_url, critical_update):
73        """
74        Jump to the update check screen at OOBE and wait for update to start.
75
76        @param update_url: The omaha update URL we expect to call.
77        @param critical_update: True if the update is critical.
78
79        """
80        self._create_custom_lsb_release(update_url)
81        # Start chrome instance to interact with OOBE.
82        extra_browser_args = []
83        if lsbrelease_utils.get_device_type() != 'CHROMEBOOK':
84            extra_browser_args.append('--disable-hid-detection-on-oobe')
85        self._chrome = chrome.Chrome(auto_login=False,
86                                     extra_browser_args=extra_browser_args)
87        self._oobe = self._chrome.browser.oobe
88        self._navigate_to_oobe_update_screen()
89
90        timeout = 180
91        err_str = 'Update did not start within %d seconds.' % timeout
92        try:
93            utils.poll_for_condition(self._is_update_started,
94                                     error.TestFail(err_str),
95                                     timeout=timeout)
96        except error.TestFail as e:
97            if critical_update:
98                if not self._get_update_requests():
99                    raise error.TestFail('%s There were no update requests in'
100                                         ' update_engine.log. OOBE update'
101                                         ' screen was missed.' % err_str)
102                err_code = self._get_last_error_string()
103                if err_code is not None:
104                    raise error.TestFail('%s %s' % (err_str, err_code))
105                else:
106                    raise e
107
108
109    def run_once(self,
110                 payload_url=None,
111                 cellular=False,
112                 critical_update=True,
113                 full_payload=None,
114                 interrupt_network=False,
115                 interrupt_progress=0.0):
116        """
117        Test that will start a forced update at OOBE.
118
119        @param payload_url: Payload url to pass to Nebraska.
120        @param cellular: True if we should run this test using a sim card.
121        @param critical_update: True if we should have deadline:now in omaha
122                                response.
123        @param full_payload: Whether the payload is full or delta. None if we
124                             don't have to care about it.
125        @param interrupt_network: True to cause a network interruption after
126                                  starting the update. Should only be used
127                                  during a critical update.
128        @param interrupt_progress: If interrupt_network is True, we will wait
129                                   for the update progress to reach this
130                                   value before interrupting. Should be
131                                   expressed as a number between 0 and 1.
132
133        """
134
135        with nebraska_wrapper.NebraskaWrapper(
136                log_dir=self.resultsdir,
137                payload_url=payload_url,
138                persist_metadata=True) as nebraska:
139
140            config = {
141                    'critical_update': critical_update,
142                    'full_payload': full_payload
143            }
144            nebraska.update_config(**config)
145            update_url = nebraska.get_update_url()
146            # Create a nebraska config, which causes nebraska to start up before update_engine.
147            # This will allow nebraska to be up right after system startup so it can be used in interruption tests.
148            nebraska.create_startup_config(**config)
149
150            if not cellular:
151                self._start_oobe_update(update_url, critical_update)
152                if interrupt_network:
153                    self._wait_for_progress(interrupt_progress)
154                    self._take_screenshot(self._BEFORE_INTERRUPT_FILENAME)
155                    completed = self._get_update_progress()
156                    self._disconnect_reconnect_network_test()
157                    self._take_screenshot(self._AFTER_INTERRUPT_FILENAME)
158
159                    if self._is_update_engine_idle():
160                        raise error.TestFail(
161                                'The update was IDLE after interrupt.')
162                    if not self._update_continued_where_it_left_off(completed):
163                        raise error.TestFail(
164                                'The update did not continue where '
165                                'it left off after interruption.')
166
167                    # Remove screenshots since the interrupt test succeeded.
168                    self._remove_screenshots()
169                return
170
171            try:
172                with test_environment.CellularOTATestEnvironment() as test_env:
173                    service = test_env.shill.wait_for_cellular_service_object()
174                    if not service:
175                        raise error.TestError('No cellular service found.')
176                    connect_timeout = 120
177                    test_env.shill.connect_service_synchronous(service,
178                                                               connect_timeout)
179
180                    self._start_oobe_update(update_url, critical_update)
181
182                    # Set the nebraska startup config's no_update=True for the
183                    # post-reboot update check, just in case we don't have time
184                    # to server-side.
185                    config['no_update'] = True
186                    nebraska.create_startup_config(**config)
187                    self._clear_custom_lsb_release()
188
189                    # Need to return from this client test before OOBE reboots
190                    # or the server test will hang. Cannot return immediately
191                    # when the OOBE update starts because all code for cellular
192                    # connections is client side and the test will switch to
193                    # ethernet. So wait for FINALIZING so payload is downloaded
194                    # via cellular and won't ping omaha again. After reboot,
195                    # there is a final ping to omaha and login screen is shown.
196                    self._wait_for_update_status(
197                        self._UPDATE_STATUS_FINALIZING)
198            except error.TestError as e:
199                logging.error('Failure setting up sim card.')
200                raise error.TestFail(e)
201