120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat# Copyright 2016 The Chromium OS Authors. All rights reserved.
220257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat# Use of this source code is governed by a BSD-style license that can be
320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat# found in the LICENSE file.
420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat#
520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat# arc_util.py is supposed to be called from chrome.py for ARC specific logic.
620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat# It should not import arc.py since it will create a import loop.
720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatimport logging
9b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavezimport os
10b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavezimport select
1120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatimport tempfile
12b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavezimport time
1320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
1420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatfrom autotest_lib.client.common_lib import error
1520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatfrom autotest_lib.client.common_lib import file_utils
1620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatfrom autotest_lib.client.common_lib.cros import arc_common
1720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatfrom telemetry.internal.browser import extension_page
1820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
1920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat_ARC_SUPPORT_HOST_URL = 'chrome-extension://cnbgggchhmkkdmeppjobngjoejnihlei/'
20ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld_ARC_SUPPORT_HOST_PAGENAME = '_generated_background_page.html'
21b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez_DUMPSTATE_DEFAULT_TIMEOUT = 20
22b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez_DUMPSTATE_PATH = '/var/log/arc-dumpstate.log'
23b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez_DUMPSTATE_PIPE_PATH = '/var/run/arc/bugreport/pipe'
2490ba12ece4886e6deeed8849dd6c24b83f03e3e4Derek Basehore_USERNAME = 'arcplusplustest@gmail.com'
2590ba12ece4886e6deeed8849dd6c24b83f03e3e4Derek Basehore_USERNAME_DISPLAY = 'arcplusplustest@gmail.com'
2690ba12ece4886e6deeed8849dd6c24b83f03e3e4Derek Basehore_ARCP_URL = 'https://sites.google.com/a/chromium.org/dev/chromium-os' \
2790ba12ece4886e6deeed8849dd6c24b83f03e3e4Derek Basehore                '/testing/arcplusplus-testing/arcp'
28d33c21d5d384efdb53643bf1168b17628905ac68Ben Cheng_OPT_IN_BEGIN = 'Initializing ARC opt-in flow.'
29d33c21d5d384efdb53643bf1168b17628905ac68Ben Cheng_OPT_IN_FINISH = 'ARC opt-in flow complete.'
3020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
3120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatdef should_start_arc(arc_mode):
32c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
33c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    Determines whether ARC should be started.
34c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
35c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    @param arc_mode: mode as defined in arc_common.
36c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
37c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    @returns: True or False.
38c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
39c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
4020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    logging.debug('ARC is enabled in mode ' + str(arc_mode))
4120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    assert arc_mode is None or arc_mode in arc_common.ARC_MODES
4220257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    return arc_mode in [arc_common.ARC_MODE_ENABLED,
4320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat                        arc_common.ARC_MODE_ENABLED_ASYNC]
4420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
4520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
4620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatdef get_extra_chrome_flags():
4720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    """Returns extra Chrome flags for ARC tests to run"""
4820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    return ['--disable-arc-opt-in-verification']
4920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
5020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
5120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatdef post_processing_after_browser(chrome):
52c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
53c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    Called when a new browser instance has been initialized.
5420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
5520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    Note that this hook function is called regardless of arc_mode.
5620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
5720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    @param chrome: Chrome object.
58c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
5920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    """
60b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    # Remove any stale dumpstate files.
61b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    if os.path.isfile(_DUMPSTATE_PATH):
62b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez        os.unlink(_DUMPSTATE_PATH)
6320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
6431a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    # Wait for Android container ready if ARC is enabled.
6531a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    if chrome.arc_mode == arc_common.ARC_MODE_ENABLED:
6631a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        try:
6731a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            arc_common.wait_for_android_boot()
6831a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        except Exception:
6931a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # Save dumpstate so that we can figure out why boot does not
7031a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # complete.
7131a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            _save_android_dumpstate()
7231a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            raise
7331a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono
7420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
7520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatdef pre_processing_before_close(chrome):
76c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
77c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    Called when the browser instance is being closed.
7820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
7920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    Note that this hook function is called regardless of arc_mode.
8020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
8120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    @param chrome: Chrome object.
82c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
8320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    """
8420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    if not should_start_arc(chrome.arc_mode):
8520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        return
861565be1acdf46506acf71b67395f4296d94b0a13Junichi Uekawa    # TODO(b/29341443): Implement stopping of adb logcat when we start adb
871565be1acdf46506acf71b67395f4296d94b0a13Junichi Uekawa    # logcat for all tests
8820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
89b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    # Save dumpstate just before logout.
9031a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    _save_android_dumpstate()
91b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez
92b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez
93b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavezdef _save_android_dumpstate(timeout=_DUMPSTATE_DEFAULT_TIMEOUT):
94b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    """
95b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    Triggers a dumpstate and saves its contents to to /var/log/arc-dumpstate.log
9631a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    with logging.
9731a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono
9831a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    Exception thrown while doing dumpstate will be ignored.
99b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez
100b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    @param timeout: The timeout in seconds.
101b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez    """
102b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez
10331a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    try:
10431a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        logging.info('Saving Android dumpstate.')
10531a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        with open(_DUMPSTATE_PATH, 'w') as out:
10631a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # _DUMPSTATE_PIPE_PATH is a named pipe, so it permanently blocks if
10731a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # opened normally if the other end has not been opened. In order to
10831a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # avoid that, open the file with O_NONBLOCK and use a select loop to
10931a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            # read from the file with a timeout.
11031a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            fd = os.open(_DUMPSTATE_PIPE_PATH, os.O_RDONLY | os.O_NONBLOCK)
11131a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono            with os.fdopen(fd, 'r') as pipe:
11231a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                end_time = time.time() + timeout
11331a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                while True:
11431a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    remaining_time = end_time - time.time()
11531a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    if remaining_time <= 0:
11631a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                        break
11731a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    rlist, _, _ = select.select([pipe], [], [], remaining_time)
11831a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    if pipe not in rlist:
11931a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                        break
12031a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    buf = os.read(pipe.fileno(), 1024)
12131a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    if len(buf) == 0:
12231a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                        break
12331a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono                    out.write(buf)
12431a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        logging.info('Android dumpstate successfully saved.')
12531a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono    except Exception:
12631a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        # Dumpstate is nice-to-have stuff. Do not make it as a fatal error.
12731a79e07cd33d9469c8bdc669c365df00da3b091Daichi Hirono        logging.exception('Failed to save Android dumpstate.')
128b6168e5d23e8916922564de8823f0cd915260c53Luis Hector Chavez
12920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
13020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichatdef set_browser_options_for_opt_in(b_options):
131c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
132c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    Setup Chrome for gaia login and opt_in.
133c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
134c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    @param b_options: browser options object used by chrome.Chrome.
135c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
136c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
13720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    b_options.username = _USERNAME
13820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    with tempfile.NamedTemporaryFile() as pltp:
13990ba12ece4886e6deeed8849dd6c24b83f03e3e4Derek Basehore        file_utils.download_file(_ARCP_URL, pltp.name)
14020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        b_options.password = pltp.read().rstrip()
14120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    b_options.disable_default_apps = False
14220257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    b_options.disable_component_extensions_with_background_pages = False
14320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    b_options.gaia_login = True
14420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
14520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
146ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkelddef enable_arc_setting(browser):
147c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
148ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    Enable ARC++ via the settings page checkbox.
149ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
150ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    Do nothing if the account is managed.
151c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
152c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    @param browser: chrome.Chrome broswer object.
153c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
154ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @returns: True if the opt-in should continue; else False.
155c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld
156c64d6f280cf6c327f88532e61317eb241840e494Katherine Threlkeld    """
157be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat    settings_tab = browser.tabs.New()
15820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
15920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    try:
160ef2eaccbed2a30105e3b6efdeb0640923c5390f1khmel        settings_tab.Navigate('chrome://settings-frame')
161be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        settings_tab.WaitForDocumentReadyStateToBeComplete()
162be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat
163be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        try:
164be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            settings_tab.ExecuteJavaScript(
165be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                    'assert(document.getElementById("android-apps-enabled"))')
166be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        except Exception, e:
167be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            raise error.TestFail('Could not locate section in chrome://settings'
168be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                                 ' to enable arc. Make sure ARC is available.')
169be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat
170be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        # Skip enabling for managed users, since value is policy enforced.
171be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        # Return early if a managed user has ArcEnabled set to false.
172be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        is_managed = settings_tab.EvaluateJavaScript(
173be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                'document.getElementById("android-apps-enabled").disabled')
174be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        if is_managed:
175be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            logging.info('Determined that ARC is managed by user policy.')
176be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            policy_value = settings_tab.EvaluateJavaScript(
177be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                    'document.getElementById("android-apps-enabled").checked')
178be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            if not policy_value:
179be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                logging.info(
180be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                        'Returning early since ARC is policy-enforced off.')
181be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                return False
182be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        else:
183be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat            settings_tab.ExecuteJavaScript(
184be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat                    'Preferences.setBooleanPref("arc.enabled", true, true)')
185be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat    finally:
186be39cd54afe24d6cc346689ab81c03147e7290efDaniel Erat        settings_tab.Close()
18720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
188ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    return True
189ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
190ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
191ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkelddef find_opt_in_extension_page(browser):
192ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
193ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    Find and verify the opt-in extension extension page.
194ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
195ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @param browser: chrome.Chrome broswer object.
196ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
197ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @returns: the extension page.
198ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
199ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @raises: error.TestFail if extension is not found or is mal-formed.
200ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
201ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
202ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    opt_in_extension_id = extension_page.UrlToExtensionId(_ARC_SUPPORT_HOST_URL)
203ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    try:
204ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld        extension_pages = browser.extensions.GetByExtensionId(
205ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld            opt_in_extension_id)
206ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    except Exception, e:
2070c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld        raise error.TestFail('Could not locate extension for arc opt-in. '
2080c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld                             'Make sure disable_default_apps is False. '
2090c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld                             '"%s".' % e)
210ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
211ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    extension_main_page = None
212ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    for page in extension_pages:
213ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld        url = page.EvaluateJavaScript('location.href;')
214ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld        if url.endswith(_ARC_SUPPORT_HOST_PAGENAME):
215ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld            extension_main_page = page
216ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld            break
217ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    if not extension_main_page:
218ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld        raise error.TestError('Found opt-in extension but not correct page!')
219ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    extension_main_page.WaitForDocumentReadyStateToBeComplete()
220ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
221dd18afb9a111c8f33e3821af5413cf9ad0497757Chung-yih Wang    js_code_did_start_conditions = ['termsPage != null',
222952a041496fbdae50a01268edd01d1635d657f02Chung-yih Wang            '(termsPage.isManaged_ || termsPage.state_ == LoadState.LOADED)']
2230c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld    try:
2240c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld        for condition in js_code_did_start_conditions:
2250309dc99e4f2ffae6211c80e4e46a62579807486Achuith Bhandarkar            extension_main_page.WaitForJavaScriptCondition(condition,
2260309dc99e4f2ffae6211c80e4e46a62579807486Achuith Bhandarkar                                                           timeout=60)
2270c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld    except Exception, e:
2280c9b8816e646213e740ede2775bf20bfe8a00efeKatherine Threlkeld        raise error.TestError('Error waiting for "%s": "%s".' % (condition, e))
22920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
230ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    return extension_main_page
231ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
232ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
233867874a283bc8ae42b70c2df1c344d8b6ab9161eVictor Hsiehdef opt_in_and_wait_for_completion(extension_main_page):
234ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
235867874a283bc8ae42b70c2df1c344d8b6ab9161eVictor Hsieh    Step through the user input of the opt-in extension and wait for completion.
236ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
237ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @param extension_main_page: opt-in extension object.
238ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
239867874a283bc8ae42b70c2df1c344d8b6ab9161eVictor Hsieh    @raises error.TestFail if opt-in doesn't complete after timeout.
240ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
241ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
24220257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    js_code_click_agree = """
24320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        doc = appWindow.contentWindow.document;
24420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        agree_button_element = doc.getElementById('button-agree');
24520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        agree_button_element.click();
24620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    """
24720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    extension_main_page.ExecuteJavaScript(js_code_click_agree)
24820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
24920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    SIGN_IN_TIMEOUT = 120
25020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    try:
2510309dc99e4f2ffae6211c80e4e46a62579807486Achuith Bhandarkar        extension_main_page.WaitForJavaScriptCondition('!appWindow',
2520309dc99e4f2ffae6211c80e4e46a62579807486Achuith Bhandarkar                                                       timeout=SIGN_IN_TIMEOUT)
25320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat    except Exception, e:
25420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        js_read_error_message = """
25520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat            err = appWindow.contentWindow.document.getElementById(
25620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat                    "error-message");
25720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat            if (err) {
25820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat                err.innerText;
25920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat            }
26020257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        """
26120257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        err_msg = extension_main_page.EvaluateJavaScript(js_read_error_message)
26220257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        err_msg = err_msg.strip()
26320257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        logging.error('Error: %s', err_msg.strip())
26420257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        if err_msg:
26520257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat            raise error.TestFail('Opt-in app error: %s' % err_msg)
26620257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat        else:
26720257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat            raise error.TestFail('Opt-in app did not finish running after %s '
26820257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat                                 'seconds!' % SIGN_IN_TIMEOUT)
26920257f0b6214b283f4821cde39425dfffba8b3b6Nicolas Boichat
270ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
271ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkelddef opt_in(browser):
272ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
273ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    Step through opt in and wait for it to complete.
274ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
275ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    Return early if the arc_setting cannot be set True.
276ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
277ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @param browser: chrome.Chrome broswer object.
278ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
279ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    @raises: error.TestFail if opt in fails.
280ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld
281ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    """
282ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    logging.info(_OPT_IN_BEGIN)
283ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    if not enable_arc_setting(browser):
284ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld        return
285ba12a34aa06205a215e7908a9a1c1e3a332177e0Katherine Threlkeld    extension_main_page = find_opt_in_extension_page(browser)
286867874a283bc8ae42b70c2df1c344d8b6ab9161eVictor Hsieh    opt_in_and_wait_for_completion(extension_main_page)
287d33c21d5d384efdb53643bf1168b17628905ac68Ben Cheng    logging.info(_OPT_IN_FINISH)
288