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