• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 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 json
6import logging
7import time
8
9from autotest_lib.client.bin import test
10from autotest_lib.client.bin import utils
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.common_lib.cros import chrome
13from autotest_lib.client.cros import cryptohome
14from autotest_lib.client.cros.input_playback import input_playback
15
16
17class desktopui_CheckRlzPingSent(test.test):
18    """Tests creating a new user, doing a google search, checking RLZ Data."""
19    version = 1
20
21    _RLZ_DATA_FILE = "/home/chronos/user/RLZ Data"
22
23    def _verify_rlz_data(self, expect_caf_ping=True, guest=False):
24        """
25        Checks the RLZ data file for CAI and CAF ping events.
26
27        @param expect_caf_ping: True if expecting the CAF event to be in the
28                                RLZ data file, False if not expecting it.
29        @param guest: True if checking in guest mode. The guest mode user
30                      mount may not be in the root mount namespace, so the RLZ
31                      data file path must be adjusted accordingly.
32
33        """
34        rlz_data_cmd = []
35        if guest:
36            mounter_pid = utils.run(
37                ['pgrep', '-f', '/usr/sbin/cryptohome-namespace-mount']).stdout
38            if mounter_pid is not None:
39                ns_path = '/proc/%s/ns/mnt' % mounter_pid.rstrip()
40                rlz_data_cmd.extend(['nsenter', '--mount=%s' % ns_path])
41
42        rlz_data_cmd.extend(['cat', self._RLZ_DATA_FILE])
43
44        def rlz_data_exists():
45            """Check rlz data exists."""
46            rlz_data = json.loads(utils.run(rlz_data_cmd).stdout)
47            logging.debug('rlz data: %s', rlz_data)
48            if 'stateful_events' in rlz_data:
49                cai_present = 'CAI' in rlz_data['stateful_events']['C']['_']
50                caf_present = 'CAF' in rlz_data['stateful_events']['C']['_']
51                return cai_present and (caf_present == expect_caf_ping)
52            return False
53
54        utils.poll_for_condition(rlz_data_exists, timeout=120)
55
56
57    def _check_url_for_rlz(self, cr):
58        """
59        Does a Google search and ensures there is an rlz parameter.
60
61        @param cr: Chrome instance.
62
63        """
64        timeout_minutes = 2
65        timeout = time.time() + 60 * timeout_minutes
66
67        # Setup a keyboard emulator to open new tabs and type a search.
68        with input_playback.InputPlayback() as player:
69            player.emulate(input_type='keyboard')
70            player.find_connected_inputs()
71
72            while True:
73                # Open a new tab, search in the omnibox.
74                player.blocking_playback_of_default_file(
75                    input_type='keyboard', filename='keyboard_ctrl+t')
76                player.blocking_playback_of_default_file(
77                    input_type='keyboard', filename='keyboard_b+a+d+enter')
78                logging.info(cr.browser.tabs[-1].url)
79                if 'rlz=' in cr.browser.tabs[-1].url:
80                    break
81                else:
82                    if time.time() > timeout:
83                        raise error.TestFail('RLZ ping did not send in %d '
84                                             'minutes.' % timeout_minutes)
85                    time.sleep(10)
86
87
88    def _wait_for_rlz_lock(self):
89        """Waits for the DUT to get into locked state after login."""
90        def get_install_lockbox_finalized_status():
91            status = cryptohome.get_install_attribute_status()
92            return status == 'VALID'
93
94        try:
95            utils.poll_for_condition(
96                lambda: get_install_lockbox_finalized_status(),
97                exception=utils.TimeoutError(),
98                timeout=120)
99        except utils.TimeoutError:
100            raise error.TestFail('Timed out trying to lock the device')
101
102
103    def run_once(self, ping_timeout=30, expect_caf_ping=True, username=None,
104                 pre_login=None, pre_login_username=None):
105        """
106        Tests whether or not the RLZ install event (CAI) and first-use event
107        (CAF) pings are sent. After the first user login, the CAI ping will
108        be sent after a certain delay. This delay is 24 hours by default, but
109        can be overridden by specifying the rlz-ping-delay flag in
110        /etc/chrome_dev.conf, or by using the --rlz-ping-delay argument to
111        Chrome. Then, if two RW_VPD settings have the correct values
112        (should_send_rlz_ping == 1, rlz_embargo_end_date has passed OR not
113        specified), the CAF ping will be sent as well. Ping status is checked
114        in the /home/chronos/user/'RLZ Data' file, which will contain entries
115        for CAI and CAF pings in the 'stateful_events' section.
116
117        @param ping_timeout: Delay time (seconds) before any RLZ pings are
118                             sent.
119        @param expect_caf_ping: True if expecting the first-use event (CAF)
120                                ping to be sent, False if not expecting it.
121                                The ping would not be expected if the relevant
122                                RW_VPD settings do not have the right
123                                combination of values.
124        @param username: Username to log in with during the main RLZ check.
125                         None to sign in with the default test user account.
126                         Specifying a username will log in with a profile
127                         distinct from the test user.
128        @param pre_login: Whether or not to login before the main RLZ ping
129                          test, and for how long. Should be one of
130                          ['lock', 'no_lock', None]. 'lock' is meant for guest
131                          mode testing, where a non-guest user must login to
132                          'lock' the device for RLZ before the ping can be
133                          sent in guest mode. 'no_lock' is to log and log out
134                          immediately to ensure no ping is sent. Used to
135                          verify that the ping can be sent from subsequent
136                          user logins if it has not already been sent.
137        @param pre_login_username: The username to sign in with for the
138                                   pre-login step. None to use the default
139                                   test user account.
140
141        """
142        # Browser arg to make DUT send rlz ping after a short delay.
143        browser_args = ['--rlz-ping-delay=%d' % ping_timeout]
144
145        # TODO(crbug/1103298): keyboard input doesn't work in guest mode
146        # without disabling this flag. Remove when bug is fixed.
147        if pre_login == 'lock':
148            browser_args.append('--disable-features=ImeInputLogicFst')
149
150        # If we are testing the ping is sent in guest mode (pre_login='lock'),
151        # we need to first do a real login and wait for the DUT to become
152        # 'locked' for rlz. Then logout and enter guest mode.
153        # If we are testing the ping can be sent by the second user to use the
154        # device, we will login and immediately logout (pre_login='no_lock').
155        if pre_login is not None:
156            logging.debug("Logging in before main RLZ test with username "
157                          "flag: %s", pre_login_username)
158            with chrome.Chrome(logged_in=True, username=pre_login_username,
159                               extra_browser_args=browser_args):
160                if pre_login is 'lock':
161                    logging.debug("Waiting for device to be 'locked' for RLZ")
162                    self._wait_for_rlz_lock()
163
164        logging.debug("Starting RLZ check with username flag: %s", username)
165        # Pass clear_enterprise_policy=False in guest mode to avoid deleting
166        # /home/chronos/'Local State' between logins. Deleting it will cause
167        # the guest mode test to fail on boards that do not have rlz_brand_code
168        # in the VPD (mainly unibuild models). This file is normally not
169        # deleted between logins anyways.
170        with chrome.Chrome(
171                logged_in=pre_login is not 'lock',
172                clear_enterprise_policy=pre_login is not 'lock',
173                extra_browser_args=browser_args,
174                username=username,
175                dont_override_profile=True) as cr:
176            self._check_url_for_rlz(cr)
177            self._verify_rlz_data(expect_caf_ping=expect_caf_ping,
178                                  guest=pre_login is 'lock')
179