xref: /aosp_15_r20/external/cronet/testing/chromoting/chromoting_test_utilities.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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