blob: 9cf98b5115f4453b38d422681b4f3ab50a489ffb [file] [edit]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package config_test
import (
"flag"
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"go.chromium.org/tast/core/cmd/tast/internal/run/config"
"go.chromium.org/tast/core/internal/debugger"
"go.chromium.org/tast/core/internal/protocol"
"go.chromium.org/tast/core/testutil"
)
func TestMutableConfigRunDefaults(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
const desc = "SetFlags for RunTestsMode"
if !cfg.CollectSysInfo {
t.Errorf("%s didn't set CollectSysInfo", desc)
}
if !cfg.CheckTestDeps {
t.Errorf("%s set CheckTestDeps to %v; want true", desc, cfg.CheckTestDeps)
}
}
func TestMutableConfigListDefaults(t *testing.T) {
cfg := config.NewMutableConfig(config.ListTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
desc := "SetFlags for ListTestsMode"
if cfg.CollectSysInfo {
t.Errorf("%s set CollectSysInfo", desc)
}
if !cfg.CheckTestDeps {
t.Errorf("%s set CheckTestDeps to %v; want true", desc, cfg.CheckTestDeps)
}
}
func TestMutableConfigDeriveDefaultsNoBuild(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.Build = false
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
}
func TestMutableConfigDeriveDefaultsSystemServicesTimeout(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.Build = false
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
if cfg.SystemServicesTimeout.Seconds() != 120 {
t.Errorf("DeriveDefault failed to set default value of SystemServicesTimeout. Expected %f seconds, Found: %f seconds", 120.0, cfg.SystemServicesTimeout.Seconds())
}
}
func TestMutableConfigDeriveDefaultsWaitUntilReadyTimeout(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.Build = false
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
if cfg.WaitUntilReadyTimeout.Seconds() != 120 {
t.Errorf("DeriveDefault failed to set default value of WaitUntilReadyTimeout. Expected %f seconds, Found: %f seconds", 120.0, cfg.WaitUntilReadyTimeout.Seconds())
}
}
func TestMutableConfigDeriveDefaultsBuild(t *testing.T) {
const buildBundle = "cros"
td := testutil.TempDir(t)
defer os.RemoveAll(td)
cfg := config.NewMutableConfig(config.RunTestsMode, "", td)
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.BuildBundle = buildBundle
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
if cfg.BuildWorkspace == "" {
t.Error("BuildWorkspace is not set")
}
if cfg.LocalBundleDir == "" {
t.Error("LocalBundleDir is not set")
}
if cfg.RemoteBundleDir == "" {
t.Error("RemoteBundleDir is not set")
}
}
func TestMutableConfigDeriveDefaultsBuildNonStandardBundle(t *testing.T) {
const buildBundle = "nonstandardbundle"
td := testutil.TempDir(t)
defer os.RemoveAll(td)
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.BuildBundle = buildBundle
// Since buildBundle is a not known bundle, DeriveDefaults fails to compute
// BuildWorkspace.
if err := cfg.DeriveDefaults(); err == nil {
t.Error("DeriveDefaults succeeded; want failure")
}
// It works if BuildWorkspace is set explicitly.
cfg.BuildWorkspace = td
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
if cfg.LocalBundleDir == "" {
t.Error("LocalBundleDir is not set")
}
if cfg.LocalBundleDir == "" {
t.Error("LocalBundleDir is not set")
}
if cfg.RemoteBundleDir == "" {
t.Error("RemoteBundleDir is not set")
}
}
func TestMutableConfigDeriveDefaultsBuildMissingBundle(t *testing.T) {
const buildBundle = "nosuchbundle"
td := testutil.TempDir(t)
defer os.RemoveAll(td)
cfg := config.NewMutableConfig(config.RunTestsMode, "", td)
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.BuildBundle = buildBundle
// At least either one of local/remote bundle package should exist.
if err := cfg.DeriveDefaults(); err == nil {
t.Error("DeriveDefaults succeeded; want failure")
}
}
func TestMutableConfigDeriveDefaultsVars(t *testing.T) {
for _, tc := range []struct {
name string
vars map[string]string
overrides map[string]string
defaults map[string]string
defaults2 map[string]string
want map[string]string
wantError bool
}{
{
name: "empty",
vars: map[string]string{},
want: map[string]string{},
},
{
name: "merge",
vars: map[string]string{"a": "1"},
overrides: map[string]string{"override.yaml": "b: 2"},
defaults: map[string]string{"default.yaml": "c: 3"},
want: map[string]string{"a": "1", "b": "2", "c": "3"},
},
{
name: "var_overrides_default",
vars: map[string]string{"a": "1"},
defaults: map[string]string{"default.yaml": "a: 2"},
want: map[string]string{"a": "1"},
},
{
name: "varsfile_overrides_default",
vars: map[string]string{},
overrides: map[string]string{"override.yaml": "a: 1"},
defaults: map[string]string{"default.yaml": "a: 2"},
want: map[string]string{"a": "1"},
},
{
name: "conflict_between_var_and_varsfile",
vars: map[string]string{"a": "1"},
overrides: map[string]string{"override.yaml": "a: 2"},
wantError: true,
},
{
name: "conflict_within_varsfile",
vars: map[string]string{},
overrides: map[string]string{
"override1.yaml": "a: 1",
"override2.yaml": "a: 2",
},
wantError: true,
},
{
name: "conflict_within_defaults",
vars: map[string]string{},
defaults: map[string]string{
"default1.yaml": "a: 1",
"default2.yaml": "a: 2",
},
wantError: true,
},
{
name: "multiple_defaults",
vars: map[string]string{},
defaults: map[string]string{"a.yaml": "a: 1"},
defaults2: map[string]string{"a.yaml": "b: 2"},
want: map[string]string{"a": "1", "b": "2"},
},
{
name: "multiple_defaults_conflict",
vars: map[string]string{},
defaults: map[string]string{"a.yaml": "a: 1"},
defaults2: map[string]string{"a.yaml": "a: 2"},
wantError: true,
},
{
name: "defaults_deep",
vars: map[string]string{},
defaults: map[string]string{
"x/a.yaml": "a: 1",
"y/a.yaml": "b: 2",
},
want: map[string]string{"a": "1", "b": "2"},
},
} {
t.Run(tc.name, func(t *testing.T) {
td := testutil.TempDir(t)
defer os.RemoveAll(td)
var defaultVarsDirs []string
for i, m := range []map[string]string{tc.defaults, tc.defaults2} {
dir := filepath.Join(td, fmt.Sprintf("default_vars%d", i+1))
defaultVarsDirs = append(defaultVarsDirs, dir)
if len(m) > 0 {
os.MkdirAll(dir, 0777)
if err := testutil.WriteFiles(dir, m); err != nil {
t.Fatal(err)
}
}
}
overrideVarsDir := filepath.Join(td, "override_vars")
os.MkdirAll(overrideVarsDir, 0777)
if err := testutil.WriteFiles(overrideVarsDir, tc.overrides); err != nil {
t.Fatal(err)
}
cfg := config.NewMutableConfig(config.RunTestsMode, "", td)
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.Build = false
cfg.TestVars = tc.vars
cfg.DefaultVarsDirs = defaultVarsDirs
for p := range tc.overrides {
cfg.VarsFiles = append(cfg.VarsFiles, filepath.Join(overrideVarsDir, p))
}
if err := cfg.DeriveDefaults(); err != nil {
if !tc.wantError {
t.Fatal("DeriveDefaults failed: ", err)
}
return
}
if tc.wantError {
t.Fatal("DeriveDefaults unexpectedly succeeded")
}
if diff := cmp.Diff(tc.vars, tc.want); diff != "" {
t.Fatalf("Unexpected vars after DeriveDefaults (-got +want):\n%s", diff)
}
})
}
}
func TestMutableConfigDeriveExtraAllowedBuckets(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
cfg.Build = false
cfg.ExtraAllowedBuckets = []string{"bucket1", "bucket2"}
cfg.BuildArtifactsURLOverride = "gs://bucket3/dir/"
if err := cfg.DeriveDefaults(); err != nil {
t.Error("DeriveDefaults failed: ", err)
}
want := []string{"bucket1", "bucket2", "bucket3"}
if got := cfg.ExtraAllowedBuckets; !reflect.DeepEqual(got, want) {
t.Errorf("cfg.ExtraAllowedBuckets() = %q; want %q", got, want)
}
}
func TestConfigLocalBundleGlob(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
cfg.LocalBundleDir = "/mock/local_bundle_dir"
cfg.BuildBundle = "mock_build_bundle"
cfg.Build = true
if g := cfg.Freeze().LocalBundleGlob(); g != "/mock/local_bundle_dir/mock_build_bundle" {
t.Fatalf(`Unexpected build LocalBundleGlob: got %q; want "/mock/local_bundle_dir/mock_bundle_dir"`, g)
}
cfg.Build = false
if g := cfg.Freeze().LocalBundleGlob(); g != "/mock/local_bundle_dir/*" {
t.Fatalf(`Unexpected non-build LocalBundleGlob: got %q; want "/mock/local_bundle_dir/*"`, g)
}
}
func TestConfigRemoteBundleGlob(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
cfg.RemoteBundleDir = "/mock/remote_bundle_dir"
cfg.BuildBundle = "mock_build_bundle"
cfg.Build = true
if g := cfg.Freeze().RemoteBundleGlob(); g != "/mock/remote_bundle_dir/mock_build_bundle" {
t.Fatalf(`Unexpected build RemoteBundleGlob: got %q; want "/mock/remote_bundle_dir/mock_bundle_dir"`, g)
}
cfg.Build = false
if g := cfg.Freeze().RemoteBundleGlob(); g == "/mock/remote_budnle_dir/*" {
t.Fatalf(`Unexpected non-build RemoteBundleGlob: got %q, want "/mock/remote_budnle_dir/*"`, g)
}
}
func TestConfigAttachDebugger(t *testing.T) {
for _, tc := range []struct {
name string
args []string
want map[debugger.DebugTarget]int
wantError bool
}{
{
name: "empty",
args: []string{},
want: map[debugger.DebugTarget]int{
debugger.LocalBundle: 0,
debugger.RemoteBundle: 0,
},
}, {
name: "single",
args: []string{"-attachdebugger=local:2345"},
want: map[debugger.DebugTarget]int{
debugger.LocalBundle: 2345,
debugger.RemoteBundle: 0,
},
}, {
name: "many",
args: []string{"-attachdebugger=local:2345", "-attachdebugger=remote:2346"},
want: map[debugger.DebugTarget]int{
debugger.LocalBundle: 2345,
debugger.RemoteBundle: 2346,
},
}, {
name: "invalid-name-only",
args: []string{"-attachdebugger=local"},
wantError: true,
}, {
name: "invalid-port-only",
args: []string{"-attachdebugger=:2345"},
wantError: true,
}, {
name: "invalid-unknown-target",
args: []string{"-attachdebugger=unknown:2348"},
wantError: true,
}, {
name: "invalid-mutually-exclusive",
args: []string{"-attachdebugger=local:2345", "-build=false"},
wantError: true,
},
} {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
reflect.DeepEqual("string", []string{})
err := flags.Parse(tc.args)
if err == nil {
err = cfg.DeriveDefaults()
}
if tc.wantError {
if err == nil {
t.Fatalf(`Expected an error to be thrown in %s, but it succeeded`, tc.name)
}
} else {
if err != nil {
t.Fatalf(`Unexpected error in %s: %s`, tc.name, err.Error())
}
if got := cfg.DebuggerPorts; !reflect.DeepEqual(got, tc.want) {
t.Errorf("cfg.DebuggerPorts = %v; want %v", got, tc.want)
}
}
}
}
func TestConfigTestFilterFilePass(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
td := testutil.TempDir(t)
defer os.RemoveAll(td)
filterFile := filepath.Join(td, "filter.txt")
content := `
# testing
-test1 # comment
-test2
`
if err := os.WriteFile(filterFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to create filter file %s: %v", filterFile, err)
}
if err := flags.Parse([]string{fmt.Sprintf("-testfilterfile=%s", filterFile)}); err != nil {
t.Fatalf("Failed to parse filter file %s: %v", filterFile, err)
}
if err := cfg.DeriveDefaults(); err != nil {
t.Fatal("Failed to derive defaults: ", err)
}
want := map[string]*protocol.ForceSkip{
"test1": {Reason: fmt.Sprintf("Test test1 is disabled by test filter file %s", filterFile)},
"test2": {Reason: fmt.Sprintf("Test test2 is disabled by test filter file %s", filterFile)},
}
cmpOptIgnoreUnexported := cmpopts.IgnoreUnexported(protocol.ForceSkip{})
if diff := cmp.Diff(cfg.ForceSkips, want, cmpOptIgnoreUnexported); diff != "" {
t.Fatalf("got unexpected ForceSkips from config (-got +want):\n%s", diff)
}
}
func TestConfigTestFilterFileFail(t *testing.T) {
cfg := config.NewMutableConfig(config.RunTestsMode, "", "")
flags := flag.NewFlagSet("", flag.ContinueOnError)
cfg.SetFlags(flags)
td := testutil.TempDir(t)
defer os.RemoveAll(td)
filterFile := filepath.Join(td, "filter.txt")
content := `
# testing
-test1 # comment
test2
`
if err := os.WriteFile(filterFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to create filter file %s: %v", filterFile, err)
}
if err := flags.Parse([]string{fmt.Sprintf("-testfilterfile=%s", filterFile)}); err == nil {
t.Fatal("Failed to identify error in filter file ", filterFile)
}
}