1*6777b538SAndroid Build Coastguard Worker# Copyright 2015 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker"""Utility script to run tests on the Chromoting bot.""" 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Workerfrom __future__ import print_function 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard Workerimport hashlib 10*6777b538SAndroid Build Coastguard Workerimport os 11*6777b538SAndroid Build Coastguard Workerfrom os.path import expanduser 12*6777b538SAndroid Build Coastguard Workerimport re 13*6777b538SAndroid Build Coastguard Workerimport shutil 14*6777b538SAndroid Build Coastguard Workerimport socket 15*6777b538SAndroid Build Coastguard Workerimport subprocess 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Workerimport psutil 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard WorkerPROD_DIR_ID = '#PROD_DIR#' 20*6777b538SAndroid Build Coastguard WorkerCRD_ID = 'chrome-remote-desktop' # Used in a few file/folder names 21*6777b538SAndroid Build Coastguard WorkerHOST_READY_INDICATOR = 'Host ready to receive connections.' 22*6777b538SAndroid Build Coastguard WorkerBROWSER_TEST_ID = 'browser_tests' 23*6777b538SAndroid Build Coastguard WorkerHOST_HASH_VALUE = hashlib.md5(socket.gethostname()).hexdigest() 24*6777b538SAndroid Build Coastguard WorkerNATIVE_MESSAGING_DIR = 'NativeMessagingHosts' 25*6777b538SAndroid Build Coastguard Worker# On a Swarming bot where these tests are executed, a temp folder is created 26*6777b538SAndroid Build Coastguard Worker# under which the files specified in an .isolate are copied. This temp folder 27*6777b538SAndroid Build Coastguard Worker# has a random name, which we'll store here for use later. 28*6777b538SAndroid Build Coastguard Worker# Note that the test-execution always starts from the testing/chromoting folder 29*6777b538SAndroid Build Coastguard Worker# under the temp folder. 30*6777b538SAndroid Build Coastguard WorkerISOLATE_CHROMOTING_HOST_PATH = 'remoting/host/linux/linux_me2me_host.py' 31*6777b538SAndroid Build Coastguard WorkerISOLATE_TEMP_FOLDER = os.path.abspath(os.path.join(os.getcwd(), '../..')) 32*6777b538SAndroid Build Coastguard WorkerCHROMOTING_HOST_PATH = os.path.join(ISOLATE_TEMP_FOLDER, 33*6777b538SAndroid Build Coastguard Worker ISOLATE_CHROMOTING_HOST_PATH) 34*6777b538SAndroid Build Coastguard WorkerMAX_RETRIES = 1 35*6777b538SAndroid Build Coastguard Worker 36*6777b538SAndroid Build Coastguard Worker 37*6777b538SAndroid Build Coastguard Workerclass HostOperationFailedException(Exception): 38*6777b538SAndroid Build Coastguard Worker pass 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Workerdef RunCommandInSubProcess(command): 42*6777b538SAndroid Build Coastguard Worker """Creates a subprocess with command-line that is passed in. 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker Args: 45*6777b538SAndroid Build Coastguard Worker command: The text of command to be executed. 46*6777b538SAndroid Build Coastguard Worker Returns: 47*6777b538SAndroid Build Coastguard Worker results: stdout contents of executing the command. 48*6777b538SAndroid Build Coastguard Worker """ 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard Worker cmd_line = [command] 51*6777b538SAndroid Build Coastguard Worker try: 52*6777b538SAndroid Build Coastguard Worker print('Going to run:\n%s' % command) 53*6777b538SAndroid Build Coastguard Worker results = subprocess.check_output(cmd_line, stderr=subprocess.STDOUT, 54*6777b538SAndroid Build Coastguard Worker shell=True) 55*6777b538SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 56*6777b538SAndroid Build Coastguard Worker results = e.output 57*6777b538SAndroid Build Coastguard Worker finally: 58*6777b538SAndroid Build Coastguard Worker print(results) 59*6777b538SAndroid Build Coastguard Worker return results 60*6777b538SAndroid Build Coastguard Worker 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Workerdef TestMachineCleanup(user_profile_dir, host_logs=None): 63*6777b538SAndroid Build Coastguard Worker """Cleans up test machine so as not to impact other tests. 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker Args: 66*6777b538SAndroid Build Coastguard Worker user_profile_dir: the user-profile folder used by Chromoting tests. 67*6777b538SAndroid Build Coastguard Worker host_logs: List of me2me host logs; these will be deleted. 68*6777b538SAndroid Build Coastguard Worker """ 69*6777b538SAndroid Build Coastguard Worker 70*6777b538SAndroid Build Coastguard Worker # Stop the host service. 71*6777b538SAndroid Build Coastguard Worker RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --stop') 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Worker # Cleanup any host logs. 74*6777b538SAndroid Build Coastguard Worker if host_logs: 75*6777b538SAndroid Build Coastguard Worker for host_log in host_logs: 76*6777b538SAndroid Build Coastguard Worker RunCommandInSubProcess('rm %s' % host_log) 77*6777b538SAndroid Build Coastguard Worker 78*6777b538SAndroid Build Coastguard Worker # Remove the user-profile dir 79*6777b538SAndroid Build Coastguard Worker if os.path.exists(user_profile_dir): 80*6777b538SAndroid Build Coastguard Worker shutil.rmtree(user_profile_dir) 81*6777b538SAndroid Build Coastguard Worker 82*6777b538SAndroid Build Coastguard Worker 83*6777b538SAndroid Build Coastguard Workerdef InitialiseTestMachineForLinux(cfg_file): 84*6777b538SAndroid Build Coastguard Worker """Sets up a Linux machine for connect-to-host chromoting tests. 85*6777b538SAndroid Build Coastguard Worker 86*6777b538SAndroid Build Coastguard Worker Copy over me2me host-config to expected locations. 87*6777b538SAndroid Build Coastguard Worker By default, the Linux me2me host expects the host-config file to be under 88*6777b538SAndroid Build Coastguard Worker $HOME/.config/chrome-remote-desktop 89*6777b538SAndroid Build Coastguard Worker Its name is expected to have a hash that is specific to a machine. 90*6777b538SAndroid Build Coastguard Worker 91*6777b538SAndroid Build Coastguard Worker Args: 92*6777b538SAndroid Build Coastguard Worker cfg_file: location of test account's host-config file. 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker Raises: 95*6777b538SAndroid Build Coastguard Worker Exception: if host did not start properly. 96*6777b538SAndroid Build Coastguard Worker """ 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker # First get home directory on current machine. 99*6777b538SAndroid Build Coastguard Worker home_dir = expanduser('~') 100*6777b538SAndroid Build Coastguard Worker default_config_file_location = os.path.join(home_dir, '.config', CRD_ID) 101*6777b538SAndroid Build Coastguard Worker if os.path.exists(default_config_file_location): 102*6777b538SAndroid Build Coastguard Worker shutil.rmtree(default_config_file_location) 103*6777b538SAndroid Build Coastguard Worker os.makedirs(default_config_file_location) 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker # Copy over test host-config to expected location, with expected file-name. 106*6777b538SAndroid Build Coastguard Worker # The file-name should contain a hash-value that is machine-specific. 107*6777b538SAndroid Build Coastguard Worker default_config_file_name = 'host#%s.json' % HOST_HASH_VALUE 108*6777b538SAndroid Build Coastguard Worker config_file_src = os.path.join(os.getcwd(), cfg_file) 109*6777b538SAndroid Build Coastguard Worker shutil.copyfile( 110*6777b538SAndroid Build Coastguard Worker config_file_src, 111*6777b538SAndroid Build Coastguard Worker os.path.join(default_config_file_location, default_config_file_name)) 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker # Make sure chromoting host is running. 114*6777b538SAndroid Build Coastguard Worker RestartMe2MeHost() 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker 117*6777b538SAndroid Build Coastguard Workerdef RestartMe2MeHost(): 118*6777b538SAndroid Build Coastguard Worker """Stops and starts the Me2Me host on the test machine. 119*6777b538SAndroid Build Coastguard Worker 120*6777b538SAndroid Build Coastguard Worker Launches the me2me start-host command, and parses the stdout of the execution 121*6777b538SAndroid Build Coastguard Worker to obtain the host log-file name. 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Worker Returns: 124*6777b538SAndroid Build Coastguard Worker log_file: Host log file. 125*6777b538SAndroid Build Coastguard Worker 126*6777b538SAndroid Build Coastguard Worker Raises: 127*6777b538SAndroid Build Coastguard Worker Exception: If host-log does not contain string indicating host is ready. 128*6777b538SAndroid Build Coastguard Worker """ 129*6777b538SAndroid Build Coastguard Worker 130*6777b538SAndroid Build Coastguard Worker # To start the host, we want to be in the temp-folder for this test execution. 131*6777b538SAndroid Build Coastguard Worker # Store the current folder to return back to it later. 132*6777b538SAndroid Build Coastguard Worker previous_directory = os.getcwd() 133*6777b538SAndroid Build Coastguard Worker os.chdir(ISOLATE_TEMP_FOLDER) 134*6777b538SAndroid Build Coastguard Worker 135*6777b538SAndroid Build Coastguard Worker # Stop chromoting host. 136*6777b538SAndroid Build Coastguard Worker RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --stop') 137*6777b538SAndroid Build Coastguard Worker # Start chromoting host. 138*6777b538SAndroid Build Coastguard Worker print('Starting chromoting host from %s' % CHROMOTING_HOST_PATH) 139*6777b538SAndroid Build Coastguard Worker results = RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --start') 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker os.chdir(previous_directory) 142*6777b538SAndroid Build Coastguard Worker 143*6777b538SAndroid Build Coastguard Worker # Get log file from results of above command printed to stdout. Example: 144*6777b538SAndroid Build Coastguard Worker # Log file: /tmp/tmp0c3EcP/chrome_remote_desktop_20150929_101525_B0o89t 145*6777b538SAndroid Build Coastguard Worker start_of_host_log = results.index('Log file: ') + len('Log file: ') 146*6777b538SAndroid Build Coastguard Worker log_file = results[start_of_host_log:].rstrip() 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker # Confirm that the start process completed, and we got: 149*6777b538SAndroid Build Coastguard Worker # "Host ready to receive connections." in the log. 150*6777b538SAndroid Build Coastguard Worker if HOST_READY_INDICATOR not in results: 151*6777b538SAndroid Build Coastguard Worker # Host start failed. Print out host-log. Don't run any tests. 152*6777b538SAndroid Build Coastguard Worker with open(log_file, 'r') as f: 153*6777b538SAndroid Build Coastguard Worker print(f.read()) 154*6777b538SAndroid Build Coastguard Worker raise HostOperationFailedException('Host restart failed.') 155*6777b538SAndroid Build Coastguard Worker 156*6777b538SAndroid Build Coastguard Worker return log_file 157*6777b538SAndroid Build Coastguard Worker 158*6777b538SAndroid Build Coastguard Worker 159*6777b538SAndroid Build Coastguard Workerdef CleanupUserProfileDir(args): 160*6777b538SAndroid Build Coastguard Worker SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file, 161*6777b538SAndroid Build Coastguard Worker args.user_profile_dir) 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker 164*6777b538SAndroid Build Coastguard Workerdef SetupUserProfileDir(me2me_manifest_file, it2me_manifest_file, 165*6777b538SAndroid Build Coastguard Worker user_profile_dir): 166*6777b538SAndroid Build Coastguard Worker """Sets up the Google Chrome user profile directory. 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Worker Delete the previous user profile directory if exists and create a new one. 169*6777b538SAndroid Build Coastguard Worker This invalidates any state changes by the previous test so each test can start 170*6777b538SAndroid Build Coastguard Worker with the same environment. 171*6777b538SAndroid Build Coastguard Worker 172*6777b538SAndroid Build Coastguard Worker When a user launches the remoting web-app, the native messaging host process 173*6777b538SAndroid Build Coastguard Worker is started. For this to work, this function places the me2me and it2me native 174*6777b538SAndroid Build Coastguard Worker messaging host manifest files in a specific folder under the user-profile dir. 175*6777b538SAndroid Build Coastguard Worker 176*6777b538SAndroid Build Coastguard Worker Args: 177*6777b538SAndroid Build Coastguard Worker me2me_manifest_file: location of me2me native messaging host manifest file. 178*6777b538SAndroid Build Coastguard Worker it2me_manifest_file: location of it2me native messaging host manifest file. 179*6777b538SAndroid Build Coastguard Worker user_profile_dir: Chrome user-profile-directory. 180*6777b538SAndroid Build Coastguard Worker """ 181*6777b538SAndroid Build Coastguard Worker native_messaging_folder = os.path.join(user_profile_dir, NATIVE_MESSAGING_DIR) 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker if os.path.exists(user_profile_dir): 184*6777b538SAndroid Build Coastguard Worker shutil.rmtree(user_profile_dir) 185*6777b538SAndroid Build Coastguard Worker os.makedirs(native_messaging_folder) 186*6777b538SAndroid Build Coastguard Worker 187*6777b538SAndroid Build Coastguard Worker manifest_files = [me2me_manifest_file, it2me_manifest_file] 188*6777b538SAndroid Build Coastguard Worker for manifest_file in manifest_files: 189*6777b538SAndroid Build Coastguard Worker manifest_file_src = os.path.join(os.getcwd(), manifest_file) 190*6777b538SAndroid Build Coastguard Worker manifest_file_dest = ( 191*6777b538SAndroid Build Coastguard Worker os.path.join(native_messaging_folder, os.path.basename(manifest_file))) 192*6777b538SAndroid Build Coastguard Worker shutil.copyfile(manifest_file_src, manifest_file_dest) 193*6777b538SAndroid Build Coastguard Worker 194*6777b538SAndroid Build Coastguard Worker 195*6777b538SAndroid Build Coastguard Workerdef PrintRunningProcesses(): 196*6777b538SAndroid Build Coastguard Worker processes = psutil.get_process_list() 197*6777b538SAndroid Build Coastguard Worker processes = sorted(processes, key=lambda process: process.name) 198*6777b538SAndroid Build Coastguard Worker 199*6777b538SAndroid Build Coastguard Worker print('List of running processes:\n') 200*6777b538SAndroid Build Coastguard Worker for process in processes: 201*6777b538SAndroid Build Coastguard Worker print(process.name) 202*6777b538SAndroid Build Coastguard Worker 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Workerdef PrintHostLogContents(host_log_files=None): 205*6777b538SAndroid Build Coastguard Worker if host_log_files: 206*6777b538SAndroid Build Coastguard Worker host_log_contents = '' 207*6777b538SAndroid Build Coastguard Worker for log_file in sorted(host_log_files): 208*6777b538SAndroid Build Coastguard Worker with open(log_file, 'r') as log: 209*6777b538SAndroid Build Coastguard Worker host_log_contents += '\nHOST LOG %s\n CONTENTS:\n%s' % ( 210*6777b538SAndroid Build Coastguard Worker log_file, log.read()) 211*6777b538SAndroid Build Coastguard Worker print(host_log_contents) 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Worker 214*6777b538SAndroid Build Coastguard Workerdef TestCaseSetup(args): 215*6777b538SAndroid Build Coastguard Worker # Reset the user profile directory to start each test with a clean slate. 216*6777b538SAndroid Build Coastguard Worker CleanupUserProfileDir(args) 217*6777b538SAndroid Build Coastguard Worker # Stop+start me2me host process. 218*6777b538SAndroid Build Coastguard Worker return RestartMe2MeHost() 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker 221*6777b538SAndroid Build Coastguard Workerdef GetJidListFromTestResults(results): 222*6777b538SAndroid Build Coastguard Worker """Parse the output of a test execution to obtain the JID used by the test. 223*6777b538SAndroid Build Coastguard Worker 224*6777b538SAndroid Build Coastguard Worker Args: 225*6777b538SAndroid Build Coastguard Worker results: stdio contents of test execution. 226*6777b538SAndroid Build Coastguard Worker 227*6777b538SAndroid Build Coastguard Worker Returns: 228*6777b538SAndroid Build Coastguard Worker jids_used: List of JIDs used by test; empty list if not found. 229*6777b538SAndroid Build Coastguard Worker """ 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard Worker # Reg-ex defining the JID information in the string being parsed. 232*6777b538SAndroid Build Coastguard Worker jid_re = '(Connecting to )(.*.gserviceaccount.com/chromoting.*)(. Local.*)' 233*6777b538SAndroid Build Coastguard Worker jids_used = [] 234*6777b538SAndroid Build Coastguard Worker for line in results.split('\n'): 235*6777b538SAndroid Build Coastguard Worker match = re.search(jid_re, line) 236*6777b538SAndroid Build Coastguard Worker if match: 237*6777b538SAndroid Build Coastguard Worker jid_used = match.group(2) 238*6777b538SAndroid Build Coastguard Worker if jid_used not in jids_used: 239*6777b538SAndroid Build Coastguard Worker jids_used.append(jid_used) 240*6777b538SAndroid Build Coastguard Worker 241*6777b538SAndroid Build Coastguard Worker return jids_used 242*6777b538SAndroid Build Coastguard Worker 243*6777b538SAndroid Build Coastguard Worker 244*6777b538SAndroid Build Coastguard Workerdef GetJidFromHostLog(host_log_file): 245*6777b538SAndroid Build Coastguard Worker """Parse the me2me host log to obtain the JID that the host registered. 246*6777b538SAndroid Build Coastguard Worker 247*6777b538SAndroid Build Coastguard Worker Args: 248*6777b538SAndroid Build Coastguard Worker host_log_file: path to host-log file that should be parsed for a JID. 249*6777b538SAndroid Build Coastguard Worker 250*6777b538SAndroid Build Coastguard Worker Returns: 251*6777b538SAndroid Build Coastguard Worker host_jid: host-JID if found in host-log, else None 252*6777b538SAndroid Build Coastguard Worker """ 253*6777b538SAndroid Build Coastguard Worker host_jid = None 254*6777b538SAndroid Build Coastguard Worker with open(host_log_file, 'r') as log_file: 255*6777b538SAndroid Build Coastguard Worker for line in log_file: 256*6777b538SAndroid Build Coastguard Worker # The host JID will be recorded in a line saying 'Signaling 257*6777b538SAndroid Build Coastguard Worker # connected'. 258*6777b538SAndroid Build Coastguard Worker if 'Signaling connected. ' in line: 259*6777b538SAndroid Build Coastguard Worker components = line.split(':') 260*6777b538SAndroid Build Coastguard Worker host_jid = components[-1].lstrip() 261*6777b538SAndroid Build Coastguard Worker break 262*6777b538SAndroid Build Coastguard Worker 263*6777b538SAndroid Build Coastguard Worker return host_jid 264