blob: 800ac61019a3bb4d6d46a50941b827db6628f5ca [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package lacrosfixt
import (
"io/ioutil"
"strings"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/lacros"
)
// Option is the function signature used to specify options of Config.
type Option func(*Config)
// ChromeOptions returns an Option which appends the given chrome.Options
// to lacros.Config. The options will be returned in lacros.Config.Opts.
func ChromeOptions(opts ...chrome.Option) Option {
return func(c *Config) {
c.chromeOpts = append(c.chromeOpts, opts...)
}
}
// Selection returns an Option which sets the selection on the lacros config.
func Selection(selection lacros.Selection) Option {
return func(c *Config) {
c.selection = selection
}
}
// Mode returns an Option which sets the mode on the lacros config.
func Mode(mode lacros.Mode) Option {
return func(c *Config) {
c.mode = mode
}
}
// KeepAlive returns an Option which sets lacros keep-alive to the desired value.
func KeepAlive(on bool) Option {
return func(c *Config) {
c.keepAlive = on
}
}
// EnableWebAppInstall returns whether to automatically install essential web apps on Lacros.
func EnableWebAppInstall() Option {
return func(c *Config) {
c.installWebApp = true
}
}
// Config holds runtime vars or other variables needed to set up Lacros.
type Config struct {
selection lacros.Selection
mode lacros.Mode
keepAlive bool
installWebApp bool
chromeOpts []chrome.Option
deployed bool
deployedPath string // dirpath to lacros executable file
}
// TestingState is a mixin interface that allows both testing.FixtState and
// testing.State to be passed into NewConfigFromState.
type TestingState interface {
Var(string) (string, bool)
}
// NewConfigFromState creates a new LacrosConfig instance.
// TestingState allows both testing.FixtState and testing.State to be passed in.
func NewConfigFromState(s TestingState, ops ...Option) *Config {
// TODO(crbug.com/1260037): Make lacros.LacrosPrimary the default.
cfg := &Config{
selection: lacros.Rootfs,
mode: lacros.NotSpecified,
keepAlive: false,
installWebApp: false,
}
for _, op := range ops {
op(cfg)
}
// The main motivation of this var is to allow Chromium CI to build and deploy a fresh
// lacros-chrome instead of always downloading from a gcs location.
// Note that this will override any Options changing the deployedPath if it
// is specified.
if deployedPath, deployed := s.Var(LacrosDeployedBinary); deployed {
cfg.deployed = deployed
cfg.deployedPath = deployedPath
}
return cfg
}
// ExtensionArgs returns a list of args needed to pass to a lacros instance to enable the test extension.
func ExtensionArgs(extID, extList string) []string {
return []string{
"--remote-debugging-port=0", // Let Chrome choose its own debugging port.
"--enable-experimental-extension-apis", // Allow Chrome to use the Chrome Automation API.
"--allowlisted-extension-id=" + extID, // Whitelists the test extension to access all Chrome APIs.
"--load-extension=" + extList, // Load extensions.
"--disable-extensions-except=" + extList, // Disable extensions other than the Tast test extension.
}
}
// Opts returns common chrome options for Lacros for the Config.
func (cfg *Config) Opts() ([]chrome.Option, error) {
var opts []chrome.Option
// Disable launching lacros on login.
opts = append(opts, chrome.ExtraArgs("--disable-login-lacros-opening"))
// Don't show the restore pages popup if lacros crashed in an earlier test.
// This can interfere with tests.
opts = append(opts, chrome.LacrosExtraArgs("--hide-crash-restore-bubble"))
// Suppress experimental Lacros infobar and possible others as well.
opts = append(opts, chrome.LacrosExtraArgs("--test-type"))
// The What's-New feature automatically redirects the browser to a WebUI page to display the
// new feature if this is first time the user opens the browser or the user has upgraded
// Chrome to a different milestone. Disables the feature in testing to make the test
// expectations more predirectable, and thus make the tests more stable.
opts = append(opts, chrome.LacrosDisableFeatures("ChromeWhatsNewUI"))
// Prevent showing up offer pages, e.g. google.com/chromebooks.
opts = append(opts, chrome.LacrosExtraArgs("--no-first-run"))
// Force color profile to sRGB regardless of device. See b/221643955 for details.
opts = append(opts, chrome.LacrosExtraArgs("--force-color-profile=srgb"))
opts = append(opts, chrome.LacrosExtraArgs("--force-raster-color-profile=srgb"))
// We reuse the custom extension from the chrome package for exposing private interfaces.
// TODO(hidehiko): Set up Tast test extension for lacros-chrome.
extDirs, err := chrome.DeprecatedPrepareExtensions()
if err != nil {
return nil, errors.Wrap(err, "failed to prepare extensions")
}
extList := strings.Join(extDirs, ",")
opts = append(opts, chrome.LacrosExtraArgs(ExtensionArgs(chrome.TestExtensionID, extList)...))
// Enable Lacros.
// Note that specifying the feature LacrosSupport has side-effects, so
// we specify it even if the lacros path is being overridden by lacrosDeployedBinary.
opts = append(opts, chrome.EnableFeatures("LacrosSupport", "ForceProfileMigrationCompletion"))
switch cfg.selection {
case lacros.Rootfs:
opts = append(opts, chrome.ExtraArgs("--lacros-selection=rootfs"))
case lacros.Omaha:
opts = append(opts, chrome.ExtraArgs("--lacros-selection=stateful"))
}
if cfg.deployed {
opts = append(opts, chrome.ExtraArgs("--lacros-chrome-path="+cfg.deployedPath))
}
// Set required options based on lacros.Mode.
switch cfg.mode {
case lacros.NotSpecified, lacros.LacrosSideBySide:
// No-op since it's the system default for now.
case lacros.LacrosPrimary:
opts = append(opts, chrome.EnableFeatures("LacrosPrimary"))
case lacros.LacrosOnly:
return nil, errors.New("options for LacrosOnly not implemented")
}
if !cfg.keepAlive {
opts = append(opts, chrome.ExtraArgs("--disable-lacros-keep-alive"))
}
if !cfg.installWebApp {
opts = append(opts, chrome.LacrosDisableFeatures("DefaultWebAppInstallation"))
}
// Let cfg.chromeOpts override any other options, except for lacrosDeployedBinary.
// Keep this last, but before the lacrosDeployedBinary code.
opts = append(opts, cfg.chromeOpts...)
// Throw an error if lacros has been deployed, but the var lacrosDeployedBinary is unset.
if !cfg.deployed && (cfg.selection == lacros.Omaha || cfg.selection == lacros.Rootfs) {
config, err := ioutil.ReadFile("/etc/chrome_dev.conf")
if err == nil {
for _, line := range strings.Split(string(config), "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "--lacros-chrome-path") {
return nil, errors.New(
"found --lacros-chrome-path in /etc/chrome_dev.conf, but lacrosDeployedBinary is not specified, " +
"you may need to pass `-var lacrosDeployedBinary=/usr/local/lacros-chrome` to `tast run` " +
"if you've deployed your own Lacros binary to the DUT, " +
"or you may need to comment out/remove --lacros-chrome-path in /etc/chrome_dev.conf")
}
}
}
}
return opts, nil
}