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