
Enables the import-error pylint check on //testing. Most errors are fixed by updating the PYTHONPATH used by pylint to include the necessary directories, although some import errors are simply suppressed (most commonly for vpython-provided modules). Also takes this opportunity to add comments about where each block of non-standard imports comes from. This was already present in a number of places, but not everywhere. Bug: 353942917 Change-Id: I506d35e5a6ae56471618e6b4af57dd2ecb64dd7b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6092016 Commit-Queue: Brian Sheedy <bsheedy@chromium.org> Reviewed-by: Ben Pastene <bpastene@chromium.org> Reviewed-by: Paul Semel <paulsemel@chromium.org> Cr-Commit-Position: refs/heads/main@{#1396194}
265 lines
8.6 KiB
Python
265 lines
8.6 KiB
Python
# Copyright 2015 The Chromium Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
"""Utility script to run tests on the Chromoting bot."""
|
|
|
|
from __future__ import print_function
|
|
|
|
import hashlib
|
|
import os
|
|
from os.path import expanduser
|
|
import re
|
|
import shutil
|
|
import socket
|
|
import subprocess
|
|
|
|
# vpython-provided modules.
|
|
import psutil # pylint: disable=import-error
|
|
|
|
PROD_DIR_ID = '#PROD_DIR#'
|
|
CRD_ID = 'chrome-remote-desktop' # Used in a few file/folder names
|
|
HOST_READY_INDICATOR = 'Host ready to receive connections.'
|
|
BROWSER_TEST_ID = 'browser_tests'
|
|
HOST_HASH_VALUE = hashlib.md5(socket.gethostname()).hexdigest()
|
|
NATIVE_MESSAGING_DIR = 'NativeMessagingHosts'
|
|
# On a Swarming bot where these tests are executed, a temp folder is created
|
|
# under which the files specified in an .isolate are copied. This temp folder
|
|
# has a random name, which we'll store here for use later.
|
|
# Note that the test-execution always starts from the testing/chromoting folder
|
|
# under the temp folder.
|
|
ISOLATE_CHROMOTING_HOST_PATH = 'remoting/host/linux/linux_me2me_host.py'
|
|
ISOLATE_TEMP_FOLDER = os.path.abspath(os.path.join(os.getcwd(), '../..'))
|
|
CHROMOTING_HOST_PATH = os.path.join(ISOLATE_TEMP_FOLDER,
|
|
ISOLATE_CHROMOTING_HOST_PATH)
|
|
MAX_RETRIES = 1
|
|
|
|
|
|
class HostOperationFailedException(Exception):
|
|
pass
|
|
|
|
|
|
def RunCommandInSubProcess(command):
|
|
"""Creates a subprocess with command-line that is passed in.
|
|
|
|
Args:
|
|
command: The text of command to be executed.
|
|
Returns:
|
|
results: stdout contents of executing the command.
|
|
"""
|
|
|
|
cmd_line = [command]
|
|
try:
|
|
print('Going to run:\n%s' % command)
|
|
results = subprocess.check_output(cmd_line,
|
|
stderr=subprocess.STDOUT,
|
|
shell=True)
|
|
except subprocess.CalledProcessError as e:
|
|
results = e.output
|
|
finally:
|
|
print(results)
|
|
return results
|
|
|
|
|
|
def TestMachineCleanup(user_profile_dir, host_logs=None):
|
|
"""Cleans up test machine so as not to impact other tests.
|
|
|
|
Args:
|
|
user_profile_dir: the user-profile folder used by Chromoting tests.
|
|
host_logs: List of me2me host logs; these will be deleted.
|
|
"""
|
|
|
|
# Stop the host service.
|
|
RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --stop')
|
|
|
|
# Cleanup any host logs.
|
|
if host_logs:
|
|
for host_log in host_logs:
|
|
RunCommandInSubProcess('rm %s' % host_log)
|
|
|
|
# Remove the user-profile dir
|
|
if os.path.exists(user_profile_dir):
|
|
shutil.rmtree(user_profile_dir)
|
|
|
|
|
|
def InitialiseTestMachineForLinux(cfg_file):
|
|
"""Sets up a Linux machine for connect-to-host chromoting tests.
|
|
|
|
Copy over me2me host-config to expected locations.
|
|
By default, the Linux me2me host expects the host-config file to be under
|
|
$HOME/.config/chrome-remote-desktop
|
|
Its name is expected to have a hash that is specific to a machine.
|
|
|
|
Args:
|
|
cfg_file: location of test account's host-config file.
|
|
|
|
Raises:
|
|
Exception: if host did not start properly.
|
|
"""
|
|
|
|
# First get home directory on current machine.
|
|
home_dir = expanduser('~')
|
|
default_config_file_location = os.path.join(home_dir, '.config', CRD_ID)
|
|
if os.path.exists(default_config_file_location):
|
|
shutil.rmtree(default_config_file_location)
|
|
os.makedirs(default_config_file_location)
|
|
|
|
# Copy over test host-config to expected location, with expected file-name.
|
|
# The file-name should contain a hash-value that is machine-specific.
|
|
default_config_file_name = 'host#%s.json' % HOST_HASH_VALUE
|
|
config_file_src = os.path.join(os.getcwd(), cfg_file)
|
|
shutil.copyfile(
|
|
config_file_src,
|
|
os.path.join(default_config_file_location, default_config_file_name))
|
|
|
|
# Make sure chromoting host is running.
|
|
RestartMe2MeHost()
|
|
|
|
|
|
def RestartMe2MeHost():
|
|
"""Stops and starts the Me2Me host on the test machine.
|
|
|
|
Launches the me2me start-host command, and parses the stdout of the execution
|
|
to obtain the host log-file name.
|
|
|
|
Returns:
|
|
log_file: Host log file.
|
|
|
|
Raises:
|
|
Exception: If host-log does not contain string indicating host is ready.
|
|
"""
|
|
|
|
# To start the host, we want to be in the temp-folder for this test execution.
|
|
# Store the current folder to return back to it later.
|
|
previous_directory = os.getcwd()
|
|
os.chdir(ISOLATE_TEMP_FOLDER)
|
|
|
|
# Stop chromoting host.
|
|
RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --stop')
|
|
# Start chromoting host.
|
|
print('Starting chromoting host from %s' % CHROMOTING_HOST_PATH)
|
|
results = RunCommandInSubProcess(CHROMOTING_HOST_PATH + ' --start')
|
|
|
|
os.chdir(previous_directory)
|
|
|
|
# Get log file from results of above command printed to stdout. Example:
|
|
# Log file: /tmp/tmp0c3EcP/chrome_remote_desktop_20150929_101525_B0o89t
|
|
start_of_host_log = results.index('Log file: ') + len('Log file: ')
|
|
log_file = results[start_of_host_log:].rstrip()
|
|
|
|
# Confirm that the start process completed, and we got:
|
|
# "Host ready to receive connections." in the log.
|
|
if HOST_READY_INDICATOR not in results:
|
|
# Host start failed. Print out host-log. Don't run any tests.
|
|
with open(log_file, 'r') as f:
|
|
print(f.read())
|
|
raise HostOperationFailedException('Host restart failed.')
|
|
|
|
return log_file
|
|
|
|
|
|
def CleanupUserProfileDir(args):
|
|
SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file,
|
|
args.user_profile_dir)
|
|
|
|
|
|
def SetupUserProfileDir(me2me_manifest_file, it2me_manifest_file,
|
|
user_profile_dir):
|
|
"""Sets up the Google Chrome user profile directory.
|
|
|
|
Delete the previous user profile directory if exists and create a new one.
|
|
This invalidates any state changes by the previous test so each test can start
|
|
with the same environment.
|
|
|
|
When a user launches the remoting web-app, the native messaging host process
|
|
is started. For this to work, this function places the me2me and it2me native
|
|
messaging host manifest files in a specific folder under the user-profile dir.
|
|
|
|
Args:
|
|
me2me_manifest_file: location of me2me native messaging host manifest file.
|
|
it2me_manifest_file: location of it2me native messaging host manifest file.
|
|
user_profile_dir: Chrome user-profile-directory.
|
|
"""
|
|
native_messaging_folder = os.path.join(user_profile_dir, NATIVE_MESSAGING_DIR)
|
|
|
|
if os.path.exists(user_profile_dir):
|
|
shutil.rmtree(user_profile_dir)
|
|
os.makedirs(native_messaging_folder)
|
|
|
|
manifest_files = [me2me_manifest_file, it2me_manifest_file]
|
|
for manifest_file in manifest_files:
|
|
manifest_file_src = os.path.join(os.getcwd(), manifest_file)
|
|
manifest_file_dest = (os.path.join(native_messaging_folder,
|
|
os.path.basename(manifest_file)))
|
|
shutil.copyfile(manifest_file_src, manifest_file_dest)
|
|
|
|
|
|
def PrintRunningProcesses():
|
|
processes = psutil.get_process_list()
|
|
processes = sorted(processes, key=lambda process: process.name)
|
|
|
|
print('List of running processes:\n')
|
|
for process in processes:
|
|
print(process.name)
|
|
|
|
|
|
def PrintHostLogContents(host_log_files=None):
|
|
if host_log_files:
|
|
host_log_contents = ''
|
|
for log_file in sorted(host_log_files):
|
|
with open(log_file, 'r') as log:
|
|
host_log_contents += '\nHOST LOG %s\n CONTENTS:\n%s' % (log_file,
|
|
log.read())
|
|
print(host_log_contents)
|
|
|
|
|
|
def TestCaseSetup(args):
|
|
# Reset the user profile directory to start each test with a clean slate.
|
|
CleanupUserProfileDir(args)
|
|
# Stop+start me2me host process.
|
|
return RestartMe2MeHost()
|
|
|
|
|
|
def GetJidListFromTestResults(results):
|
|
"""Parse the output of a test execution to obtain the JID used by the test.
|
|
|
|
Args:
|
|
results: stdio contents of test execution.
|
|
|
|
Returns:
|
|
jids_used: List of JIDs used by test; empty list if not found.
|
|
"""
|
|
|
|
# Reg-ex defining the JID information in the string being parsed.
|
|
jid_re = '(Connecting to )(.*.gserviceaccount.com/chromoting.*)(. Local.*)'
|
|
jids_used = []
|
|
for line in results.split('\n'):
|
|
match = re.search(jid_re, line)
|
|
if match:
|
|
jid_used = match.group(2)
|
|
if jid_used not in jids_used:
|
|
jids_used.append(jid_used)
|
|
|
|
return jids_used
|
|
|
|
|
|
def GetJidFromHostLog(host_log_file):
|
|
"""Parse the me2me host log to obtain the JID that the host registered.
|
|
|
|
Args:
|
|
host_log_file: path to host-log file that should be parsed for a JID.
|
|
|
|
Returns:
|
|
host_jid: host-JID if found in host-log, else None
|
|
"""
|
|
host_jid = None
|
|
with open(host_log_file, 'r') as log_file:
|
|
for line in log_file:
|
|
# The host JID will be recorded in a line saying 'Signaling
|
|
# connected'.
|
|
if 'Signaling connected. ' in line:
|
|
components = line.split(':')
|
|
host_jid = components[-1].lstrip()
|
|
break
|
|
|
|
return host_jid
|