cros ca: Enable Google Meet for CrOS
- Modified the autologin script to allow more options to be passed
to CrOS Chrome during auto login.
- Scripts are borrowed from autotest autologin.py.
- Add related Chrome options in Google Meet test.
- This is to bypass the camera/microphone permission granting for
Google Meet.
- Support --verbose logging level config
- Default logging level is "INFO", with verbose mode, the logging
level is "DEBUG"
BUG=b:336637815
TEST=python bin/test_cros_remote.py --var=duration=3 --var=typing_delay=0.01 --var=meet_ttl=5 <DUT> cuj.GoogleMeet
Change-Id: Idc8b6b1319ad1384af0226ea88781e7875ca05e0
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/5482558
Reviewed-by: Willis Kung <williskung@google.com>
Tested-by: Xibin Liu <xliu@cienet.com>
Commit-Queue: Xibin Liu <xliu@cienet.com>
diff --git a/contrib/cros_ca_linux/bin/test_cros_local.py b/contrib/cros_ca_linux/bin/test_cros_local.py
index ad68ded..e535db9 100644
--- a/contrib/cros_ca_linux/bin/test_cros_local.py
+++ b/contrib/cros_ca_linux/bin/test_cros_local.py
@@ -26,6 +26,7 @@
sys.path.insert(0, venv_package)
from bin import utils
+import lib.config as cf
from lib.host import cros_local_host
from lib.runner import local_runner
import lib.utils.logging as lg
@@ -34,6 +35,9 @@
# pylint: enable=wrong-import-position
logger = lg.logger
+# Remove the standard output from the local runner to avoid the logs
+# flushing into SSH pipe. Logs will be written to files.
+logger.removeHandler(lg.stream_handler)
def parse_arguments(argv):
@@ -50,6 +54,7 @@
are not present.
"""
parser = argparse.ArgumentParser(description="Run tests on CrOS locally.")
+ utils.add_config(parser)
utils.add_vars(parser)
utils.add_tests(parser)
utils.add_run_id(parser)
@@ -65,6 +70,7 @@
"""
arguments = parse_arguments(argv)
variables = utils.parse_vars(arguments.variables)
+ cf.args_to_config(arguments)
start_file = f"{df.PROJECT_ROOT_DIR}/{df.TEST_START_FILE}"
end_file = f"{df.PROJECT_ROOT_DIR}/{df.TEST_END_FILE}"
diff --git a/contrib/cros_ca_linux/bin/test_cros_remote.py b/contrib/cros_ca_linux/bin/test_cros_remote.py
index 824f16f..cdd77f8 100644
--- a/contrib/cros_ca_linux/bin/test_cros_remote.py
+++ b/contrib/cros_ca_linux/bin/test_cros_remote.py
@@ -17,6 +17,7 @@
from bin import utils
from lib import definition as df
+import lib.config as cf
from lib.host import cros_paramiko_host
from lib.host import cros_ssh_host
from lib.runner import remote_runner_direct
@@ -44,6 +45,7 @@
parser = argparse.ArgumentParser(description="Run tests on CrOS.")
utils.add_vars(parser)
utils.add_target(parser)
+ utils.add_config(parser)
utils.add_transport(parser)
utils.add_tests(parser)
# With the above config, the program accept these optional arguments:
@@ -73,6 +75,7 @@
port = ssh_specs["port"]
username = ssh_specs["user"]
variables = utils.parse_vars(arguments.variables)
+ cf.args_to_config(arguments)
if arguments.transport == "ssh":
# When --transport=ssh argument is given.
diff --git a/contrib/cros_ca_linux/bin/test_win_local.py b/contrib/cros_ca_linux/bin/test_win_local.py
index 22962c4..41fd197 100644
--- a/contrib/cros_ca_linux/bin/test_win_local.py
+++ b/contrib/cros_ca_linux/bin/test_win_local.py
@@ -17,16 +17,20 @@
sys.path.append(str(Path(__file__).resolve().parents[1]))
from bin import utils
+import lib.config as cf
import lib.definition as df
from lib.host import win_local_host
from lib.runner import local_runner
from lib.utils import logging as lg
-logger = lg.logger
-
# pylint: enable=wrong-import-position
+logger = lg.logger
+# Remove the standard output from the local runner to avoid the logs
+# flushing into SSH pipe. Logs will be written to files.
+logger.removeHandler(lg.stream_handler)
+
def parse_arguments(argv):
"""Parse command line arguments
@@ -45,6 +49,7 @@
description="Run tests on Windows locally."
)
utils.add_vars(parser)
+ utils.add_config(parser)
utils.add_tests(parser)
utils.add_run_id(parser)
@@ -59,6 +64,7 @@
"""
arguments = parse_arguments(argv)
variables = utils.parse_vars(arguments.variables)
+ cf.args_to_config(arguments)
start_file = f"{df.PROJECT_ROOT_DIR}/{df.TEST_START_FILE}"
end_file = f"{df.PROJECT_ROOT_DIR}/{df.TEST_END_FILE}"
diff --git a/contrib/cros_ca_linux/bin/test_win_remote.py b/contrib/cros_ca_linux/bin/test_win_remote.py
index aca60a2..a5a597e 100644
--- a/contrib/cros_ca_linux/bin/test_win_remote.py
+++ b/contrib/cros_ca_linux/bin/test_win_remote.py
@@ -16,6 +16,7 @@
sys.path.append(str(Path(__file__).resolve().parents[1]))
from bin import utils
+import lib.config as cf
import lib.definition as df
from lib.host import win_paramiko_host
from lib.host import win_ssh_host
@@ -44,6 +45,7 @@
parser = argparse.ArgumentParser(description="Run tests on Windows.")
utils.add_vars(parser)
utils.add_transport(parser)
+ utils.add_config(parser)
utils.add_target(parser)
utils.add_tests(parser)
# With the above config, the program accept these optional arguments:
@@ -73,6 +75,7 @@
port = ssh_specs["port"]
username = ssh_specs["user"]
variables = utils.parse_vars(arguments.variables)
+ cf.args_to_config(arguments)
if arguments.transport == "ssh":
# When --transport=ssh argument is given.
diff --git a/contrib/cros_ca_linux/bin/utils.py b/contrib/cros_ca_linux/bin/utils.py
index 0d70088..feb3aba 100644
--- a/contrib/cros_ca_linux/bin/utils.py
+++ b/contrib/cros_ca_linux/bin/utils.py
@@ -8,6 +8,11 @@
import re
from typing import List
+import lib.config as cf
+
+
+config = cf.config
+
def add_vars(parser: argparse.ArgumentParser):
"""Add var optionatl argument to parser"""
@@ -22,6 +27,16 @@
)
+def parse_vars(arg_vars: List[str]) -> dict:
+ """Parse the variables list into key / value dictionary"""
+ variables = {}
+ if arg_vars:
+ for var in arg_vars:
+ key, value = var.split("=")
+ variables[key] = value
+ return variables
+
+
def add_run_id(parser: argparse.ArgumentParser):
"""Add run_id optionatl argument to parser"""
parser.add_argument(
@@ -42,6 +57,17 @@
)
+def add_config(parser: argparse.ArgumentParser):
+ """Add config optionatl argument to parser"""
+ parser.add_argument(
+ "--verbose",
+ dest="verbose",
+ action="store_true",
+ help="Verbose / debug logging mode.",
+ )
+ # Add other confiugrations after this.
+
+
def add_target(parser: argparse.ArgumentParser):
"""Add target argument to parser"""
parser.add_argument(
@@ -59,16 +85,6 @@
)
-def parse_vars(arg_vars: List[str]) -> dict:
- """Parse the variables list into key / value dictionary"""
- variables = {}
- if arg_vars:
- for var in arg_vars:
- key, value = var.split("=")
- variables[key] = value
- return variables
-
-
def parse_ssh_host_spec(host_spec, platform="ChromeOS"):
"""Parses an SSH host spec string into a dictionary.
diff --git a/contrib/cros_ca_linux/lib/config.py b/contrib/cros_ca_linux/lib/config.py
new file mode 100644
index 0000000..c7cd8b7
--- /dev/null
+++ b/contrib/cros_ca_linux/lib/config.py
@@ -0,0 +1,33 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Program global configuration."""
+
+from typing import NamedTuple
+
+import lib.utils.logging as lg
+
+
+class Config:
+ """Global configuration class."""
+
+ verbose: bool = False
+
+
+config = Config()
+
+
+def args_to_config(arguments: NamedTuple):
+ """Parse arguments to config"""
+ config.verbose = arguments.verbose
+ if config.verbose:
+ lg.logger.setLevel(lg.logging.DEBUG)
+ lg.logger.debug("Running with verbose mode.")
+
+
+def config_to_args():
+ args = ""
+ if config.verbose:
+ args += "--verbose"
+ return args
diff --git a/contrib/cros_ca_linux/lib/definition.py b/contrib/cros_ca_linux/lib/definition.py
index 796ad00..c70c1ed 100644
--- a/contrib/cros_ca_linux/lib/definition.py
+++ b/contrib/cros_ca_linux/lib/definition.py
@@ -7,7 +7,6 @@
import pathlib
-
# ==== Path for project folders and files
PROJECT_LIB_DIR = pathlib.Path(__file__).parent.resolve()
PROJECT_ROOT_DIR = PROJECT_LIB_DIR.parent
diff --git a/contrib/cros_ca_linux/lib/host/base_host.py b/contrib/cros_ca_linux/lib/host/base_host.py
index bf6851d..9e7dd5a 100644
--- a/contrib/cros_ca_linux/lib/host/base_host.py
+++ b/contrib/cros_ca_linux/lib/host/base_host.py
@@ -44,6 +44,7 @@
username: str = None
password: str = None
arc: bool = False # For CrOS to bring up ARC.
+ chrome_args: List[str] = []
class BaseHost:
@@ -98,7 +99,7 @@
if self.hostname:
logger.info("Connected to host: %s", self.hostname)
self._connected = True
- except Exception as e:
+ except Exception:
self._connected = False
raise # Re-raise the exception for caller handling
@@ -378,7 +379,7 @@
location = winreg.QueryValueEx(key, downloads_guid)[0]
return location
else:
- return os.path.join(os.path.expanduser("~"), "downloads")
+ return "/home/chronos/user/Downloads"
def deploy(self) -> None:
"""Deploy the environment for testing"""
diff --git a/contrib/cros_ca_linux/lib/host/cros_local_host.py b/contrib/cros_ca_linux/lib/host/cros_local_host.py
index 73cba30..9436a77 100644
--- a/contrib/cros_ca_linux/lib/host/cros_local_host.py
+++ b/contrib/cros_ca_linux/lib/host/cros_local_host.py
@@ -15,6 +15,7 @@
from selenium.webdriver.chrome.service import Service
from lib.host import base_host
+from lib.utils.autotest import autologin
class CrosLocalHost(base_host.BaseHost):
@@ -39,27 +40,17 @@
RuntimeError: if autologin fails.
"""
- command = "/usr/local/autotest/bin/autologin.py "
- # Don't keep state. Delete existing profile.
- # This is the only way it can work together with gaia login. Without
- # this option, if another account has already exists on the DUT,
- # the GAIA login would fail on the screen of "Choose your setup"
- # for personal use, for a child or for work.
- command += "-d "
- if option.arc:
- command += "--arc --no-arc-syncs "
- if option.username and option.password:
- command += f"-u {option.username} -p {option.password} "
- # TODO: Other Chrome options can be added here. These options
- # can be set in the "option" class and applied to the
- # autologin.py argument here.
-
- subprocess.run(
- command,
- shell=True,
- stdout=subprocess.DEVNULL, # Supress the stdout and stderr
- stderr=subprocess.DEVNULL,
- check=True,
+ autologin.autologin(
+ # This is the only way it can work together with gaia login. Without
+ # this option, if another account has already exists on the DUT,
+ # the GAIA login would fail on the screen of "Choose your setup"
+ # for personal use, for a child or for work.
+ dont_override_profile=True,
+ arc=option.arc,
+ no_arc_syncs=option.arc,
+ username=option.username,
+ password=option.password,
+ extra_args=option.chrome_args,
)
time.sleep(2)
diff --git a/contrib/cros_ca_linux/lib/host/ssh/port_forwarding.py b/contrib/cros_ca_linux/lib/host/ssh/port_forwarding.py
index e2a4964..2c0a02d 100644
--- a/contrib/cros_ca_linux/lib/host/ssh/port_forwarding.py
+++ b/contrib/cros_ca_linux/lib/host/ssh/port_forwarding.py
@@ -4,8 +4,6 @@
"""Implement a call that can do the SSH port forwarding."""
-import os
-import signal
import subprocess
import time
@@ -98,7 +96,7 @@
Terminates the SSH process established for the port forwarding tunnel.
"""
if self.ssh_process:
- os.killpg(os.getpgid(self.ssh_process.pid), signal.SIGTERM)
+ self.ssh_process.kill()
self.ssh_process = None
logger.info(
"Port forwarding for %s has been terminated.", self.local_port
diff --git a/contrib/cros_ca_linux/lib/runner/remote_runner_direct.py b/contrib/cros_ca_linux/lib/runner/remote_runner_direct.py
index 492caaf..d3e73e5 100644
--- a/contrib/cros_ca_linux/lib/runner/remote_runner_direct.py
+++ b/contrib/cros_ca_linux/lib/runner/remote_runner_direct.py
@@ -7,6 +7,7 @@
import time
from typing import List
+import lib.config as cf
import lib.definition as df
from lib.host import base_host
from lib.runner import base_runner as br
@@ -28,6 +29,7 @@
script += (
f" --run_id={run_id}" # Provide run_id so test_end can be tracked.
)
+ script += f" {cf.config_to_args()}"
for k in variables:
script += f" --var={k}={variables[k]}"
script += f" {parsed_test.test_name}"
@@ -40,7 +42,7 @@
# Create a temporary file on the host to get the DUT file time.
tmp_name = ".file_no_use"
tmp_file = f"{self.dut.test_dir}/{tmp_name}"
- self.dut.write_file(tmp_file, f"this file can be removed")
+ self.dut.write_file(tmp_file, "this file can be removed")
entries = self.dut.dir_entries(f"{self.dut.test_dir}")
mtime = 0
for e in entries:
@@ -49,6 +51,7 @@
break
self.dut.remove_path(tmp_file)
+ self.logger.debug("Run the script locally on the DUT: %s", script)
# Run the command in asynchronous mode.
_, _, is_done = self.dut.executing_command(script, timeout=10)
start_time = time.time() # Record the start time
diff --git a/contrib/cros_ca_linux/lib/runner/remote_runner_script.py b/contrib/cros_ca_linux/lib/runner/remote_runner_script.py
index ada299e..80057ef 100644
--- a/contrib/cros_ca_linux/lib/runner/remote_runner_script.py
+++ b/contrib/cros_ca_linux/lib/runner/remote_runner_script.py
@@ -7,6 +7,7 @@
import time
from typing import List
+import lib.config as cf
import lib.definition as df
from lib.host import base_host
from lib.runner import base_runner as br
@@ -32,12 +33,14 @@
script += (
f" --run_id={run_id}" # Provide run_id so test_end can be tracked.
)
+ script += f" {cf.config_to_args()}"
for k in variables:
script += f" --var={k}={variables[k]}"
script += f" {parsed_test.test_name}"
self.dut.make_dir(starter_path)
self.dut.remove_path(f"{starter_path}/test_ended.txt")
+ self.logger.debug("Run the script locally on the DUT: %s", script)
self.dut.write_file(f"{starter_path}/run.bat", script)
self.dut.write_file(f"{starter_path}/start_test.txt", "")
diff --git a/contrib/cros_ca_linux/lib/testing/lib/chrome_browser_test.py b/contrib/cros_ca_linux/lib/testing/lib/chrome_browser_test.py
index 1eb3b38..88c23b0 100644
--- a/contrib/cros_ca_linux/lib/testing/lib/chrome_browser_test.py
+++ b/contrib/cros_ca_linux/lib/testing/lib/chrome_browser_test.py
@@ -123,7 +123,7 @@
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (open - full): %s -- %s",
metric,
histogramSnapshot,
@@ -141,12 +141,12 @@
# Switch to monitoring mode
driver.find_element(By.ID, "enable_monitoring").click()
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(f"Monitoring mode enabled {metric}")
+ self.logger.info("Monitoring mode enabled %s", metric)
histogramSnapshot = self._get_histogram_snapshot(
driver, metric, True
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (monitor - delta): %s -- %s",
metric,
histogramSnapshot,
@@ -155,7 +155,7 @@
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (monitor - full): %s -- %s",
metric,
histogramSnapshot,
@@ -168,7 +168,7 @@
driver, metric, True
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (%s - delta): %s -- %s",
annotation,
metric,
@@ -178,7 +178,7 @@
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot ({annotation} - full): %s -- %s",
metric,
histogramSnapshot,
@@ -200,8 +200,9 @@
# capture screenshot before monitoring mode disabled
if not self.save_screenshot(f"stopping_{metric}"):
- self.loggger.debug(
- f"Failed to save a screenshot on DUT when stopping {metric}"
+ self.logger.info(
+ "Failed to save a screenshot on DUT when stopping %s",
+ metric,
)
time.sleep(0.5)
@@ -210,7 +211,7 @@
driver, metric, True
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (before monitoring stopped - delta): "
+ "%s -- %s",
metric,
@@ -220,7 +221,7 @@
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (before monitoring stopped - full): "
+ "%s -- %s",
metric,
@@ -230,9 +231,9 @@
# Stop monitoring mode
driver.find_element(By.ID, "stop").click()
time.sleep(0.25)
- self.logger.debug(f"monitoring mode stopped: {metric}")
+ self.logger.info("monitoring mode stopped: %s", metric)
if not self.save_screenshot(f"stopped_{metric}"):
- self.loggger.debug(
+ self.logger.info(
"Failed to save a screenshot on DUT after stopping %s",
metric,
)
@@ -243,7 +244,7 @@
driver, metric, True
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (monitoring stopped - delta): %s -- %s",
metric,
histogramSnapshot,
@@ -252,7 +253,7 @@
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (monitoring stopped - full): %s -- %s",
metric,
histogramSnapshot,
@@ -277,7 +278,7 @@
).text
word = header_text.split(" ")
samples, mean_value = word[3], word[7]
- self.logger.debug(
+ self.logger.info(
"%s mean: %s samples: %s",
histogram_name,
mean_value,
@@ -289,18 +290,18 @@
histogram_body = histograms.find_elements(
By.XPATH, "//div[@class='histogram-body']//p"
)[i]
- self.logger.debug(
- f"histogram body: \n{histogram_body.text}"
+ self.logger.info(
+ "histogram body: \n%s", histogram_body.text
)
except Exception:
- self.logger.warning(f"Failed to get data from {metric}")
+ self.logger.warning("Failed to get data from %s", metric)
histogram_dict[metric] = {"sample": samples, "mean": mean_value}
histogramSnapshot = self._get_histogram_snapshot(
driver, metric, False
)
time.sleep(self.getHistogram_wait_time)
- self.logger.debug(
+ self.logger.info(
"histogram snapshot (get data - full): %s -- %s",
metric,
histogramSnapshot,
diff --git a/contrib/cros_ca_linux/lib/testing/local/cuj/GoogleMeet.py b/contrib/cros_ca_linux/lib/testing/local/cuj/GoogleMeet.py
index cde3404..827c934 100644
--- a/contrib/cros_ca_linux/lib/testing/local/cuj/GoogleMeet.py
+++ b/contrib/cros_ca_linux/lib/testing/local/cuj/GoogleMeet.py
@@ -9,6 +9,7 @@
import json
import os
+import shutil
import subprocess
import time
@@ -18,6 +19,7 @@
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
+from lib.host import base_host
from lib.testing.lib import chrome_browser_test as cbt
@@ -73,31 +75,46 @@
return opt
def run(self):
+ if os.name != "nt":
+ # Only do this for CrOS
+ option = base_host.LoginOption()
+ option.username = self.var("gaia_account")
+ option.password = self.var("gaia_password")
+ option.arc = True
+ option.chrome_args = [
+ "--use-fake-ui-for-media-stream",
+ ]
+ self.dut.auto_login(option)
+ self.dut.mute(True)
+
# Get the webdriver at the beginning of the test.
driver = self.get_webdriver()
wait = WebDriverWait(driver, 15)
- # Sign in with the Google account (index = 0)
- driver.get("https://accounts.google.com/ServiceLogin")
- driver.find_element(By.TAG_NAME, "input").send_keys(
- self.var("gaia_account")
- )
- driver.find_element(By.XPATH, '//span[text()="Next"]').find_element(
- By.XPATH, "./.."
- ).click()
- _ = wait.until(
- EC.presence_of_element_located(
- (By.XPATH, '//span[text()="Welcome"]')
+ if os.name == "nt":
+ # Only do this for Windows. For CrOS, the DUT has been signed in
+ # with GAIA login.
+ # Sign in with the Google account (index = 0)
+ driver.get("https://accounts.google.com/ServiceLogin")
+ driver.find_element(By.TAG_NAME, "input").send_keys(
+ self.var("gaia_account")
)
- )
- submit = driver.find_element(By.ID, "passwordNext")
- _ = wait.until(EC.element_to_be_clickable(submit))
- driver.find_element(By.NAME, "Passwd").send_keys(
- self.var("gaia_password")
- )
- submit.click()
- # time.sleep(send_keys_wait_time)
- time.sleep(0.1)
+ driver.find_element(By.XPATH, '//span[text()="Next"]').find_element(
+ By.XPATH, "./.."
+ ).click()
+ _ = wait.until(
+ EC.presence_of_element_located(
+ (By.XPATH, '//span[text()="Welcome"]')
+ )
+ )
+ submit = driver.find_element(By.ID, "passwordNext")
+ _ = wait.until(EC.element_to_be_clickable(submit))
+ driver.find_element(By.NAME, "Passwd").send_keys(
+ self.var("gaia_password")
+ )
+ submit.click()
+ # time.sleep(send_keys_wait_time)
+ time.sleep(0.1)
# Open WebRTC Internals page (index = 0)
driver.get("chrome://webrtc-internals")
@@ -157,7 +174,6 @@
By.CSS_SELECTOR, 'button[aria-label="Turn off camera (ctrl + e)"]'
)
camera_button.click()
- driver.implicitly_wait(2)
chat_button = wait.until(
EC.element_to_be_clickable(
@@ -168,7 +184,6 @@
)
)
chat_button.click()
- driver.implicitly_wait(2)
text_area = wait.until(
EC.element_to_be_clickable(
@@ -180,7 +195,6 @@
)
)
text_area.click()
- driver.implicitly_wait(2)
# capture metric snapshot after meet call effect is in place and stable
self.get_histogram_snapshots("meet effect stablized and before typing")
@@ -260,7 +274,7 @@
self.get_histogram_snapshots("after typing")
self.logger.info(
- f"Typing stopped. Final counter value after typing: {counter}"
+ "Typing stopped. Final counter value after typing: %s", counter
)
if not self.save_screenshot("after_typing"):
@@ -280,10 +294,10 @@
capture_output=True,
check=True,
)
- self.logger.info("tasklist output:\n", task_output.stdout)
+ self.logger.info("tasklist output:\n%s", task_output.stdout)
etl_path = self.test_dir / "test.etl"
- self.logger.info(f"xperf -d {etl_path}")
+ self.logger.info("xperf -d %s", etl_path)
# subprocess.call(["xperf", "-d", "test.etl"])
xperf_output = subprocess.run(
["xperf", "-d", etl_path],
@@ -292,7 +306,7 @@
capture_output=True,
check=True,
)
- self.logger.info("xperf utput:\n", xperf_output.stdout)
+ self.logger.info("xperf utput:\n%s", xperf_output.stdout)
# If the dump file exists, remove it.
file_path = os.path.join(
@@ -314,14 +328,14 @@
histogram_dict = self.get_historam_data()
driver.quit()
- self.logger.info(f"Metrics: {histogram_dict}")
+ self.logger.info("Metrics: %s", histogram_dict)
# Add the data of dump file to result.
with open(file_path, "r", encoding="utf-8") as f:
webrtc_dump = json.load(f)
histogram_dict["webrtc"] = webrtc_dump
dst = os.path.join(self.histogram_dir, "webrtc_internals_dump.txt")
- os.rename(file_path, dst)
+ shutil.move(file_path, dst)
# Save data to result.json file.
with open(
diff --git a/contrib/cros_ca_linux/lib/utils/autotest/autologin.py b/contrib/cros_ca_linux/lib/utils/autotest/autologin.py
new file mode 100644
index 0000000..4d5ae71
--- /dev/null
+++ b/contrib/cros_ca_linux/lib/utils/autotest/autologin.py
@@ -0,0 +1,92 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Does the CrOS auto login. Borrowed from autotest."""
+
+import sys
+from typing import List
+
+
+# pylint: disable=wrong-import-position
+
+# Import autotest client
+client_dir = "/usr/local/autotest/bin"
+sys.path.insert(0, client_dir)
+# "common" does all the autotest lib setup.
+import common # pylint: disable=unused-import
+
+
+sys.path.pop(0)
+
+from autotest_lib.client.common_lib.cros import chrome
+
+
+# pylint: enable=wrong-import-position
+
+
+def autologin(
+ arc: bool = False,
+ arc_timeout: int = None,
+ no_arc_syncs: bool = False,
+ disable_arc_cpu_restriction: bool = False,
+ username: str = None,
+ password: str = None,
+ enable_default_apps: bool = False,
+ dont_override_profile: bool = False,
+ no_startup_window: bool = False,
+ url: str = "",
+ enable_features: List[str] = None,
+ disable_features: List[str] = None,
+ extra_args: List[str] = None,
+):
+ """ChromeOS auto login.
+
+ Args:
+ arc: Flag to enable ARC.
+ arc_timeout: The timeout value waiting for ARC.
+ no_arc_syncs: Flag to disable ARC syncs.
+ disable_arc_cpu_restriction: Flag to disable ARC CPU restriction.
+ username: User name. Do GAIA login if the user is given.
+ password: Password for the user.
+ enable_default_apps: Flag to enable default apps.
+ dont_override_profile: Flag to disable profile overriding.
+ no_startup_window: Don't open a Chrome window on startup.
+ url: The URL to navigate to when starting up the Chrome.
+ enable_features: Enable the given features.
+ disable_features: Disable the given features.
+ extra_args: Extra chrome args to pass to the Chrome process.
+ For example:
+ - pass in "--use-fake-ui-for-media-stream" to grant media
+ permission for Google Meet.
+ - pass in "--enable-benchmarking" to enable benchmark testing.
+ """
+ browser_args = []
+ if no_startup_window:
+ browser_args.append("--no-startup-window")
+ if enable_features and len(enable_features) > 0:
+ browser_args.append("--enable-features=%s" % ",".join(enable_features))
+ if disable_features and len(disable_features) > 0:
+ browser_args.append(
+ "--disable-features=%s" % ",".join(disable_features)
+ )
+ if extra_args and len(extra_args) > 0:
+ browser_args.extend(extra_args)
+
+ # Avoid calling close() on the Chrome object; this keeps the session active.
+ cr = chrome.Chrome(
+ extra_browser_args=browser_args,
+ arc_mode=("enabled" if arc else None),
+ arc_timeout=arc_timeout,
+ disable_arc_cpu_restriction=disable_arc_cpu_restriction,
+ disable_app_sync=no_arc_syncs,
+ disable_play_auto_install=no_arc_syncs,
+ username=username,
+ password=(password if username else None),
+ gaia_login=(username is not None),
+ disable_default_apps=(not enable_default_apps),
+ dont_override_profile=dont_override_profile,
+ )
+ if url:
+ tab = cr.browser.tabs[0]
+ tab.Navigate(url)
diff --git a/contrib/cros_ca_linux/lib/utils/logging.py b/contrib/cros_ca_linux/lib/utils/logging.py
index 2cb4682..d77757b 100644
--- a/contrib/cros_ca_linux/lib/utils/logging.py
+++ b/contrib/cros_ca_linux/lib/utils/logging.py
@@ -25,9 +25,15 @@
file_handler = logging.FileHandler(LOG_FILE)
file_handler.setFormatter(formatter)
-# Configure the logger
+# Disable the default logging that could be used by other libraries.
+root_logger = logging.getLogger()
+root_logger.addHandler(logging.NullHandler())
+
+# Configure the logger for CrOS CA.
logger = logging.getLogger("cros_ca")
+logger.propagate = False
logger.addHandler(stream_handler)
logger.addHandler(file_handler)
-# TODO: control level from a argument
-logger.setLevel(logging.DEBUG)
+# Default level is INFO. But can be changed by config.
+# See lib.config module.
+logger.setLevel(logging.INFO)