blob: e6c70d579525e9e8ecacc1b090dcf980af6c7aef [file] [edit]
// Copyright 2017 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 testing
import (
"context"
"reflect"
gotesting "testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/grpc"
)
// REGISTRYTEST is a public test function with a name that's chosen to be
// appropriate for this file's name (registry_test.go). The obvious choice,
// "RegistryTest", is unavailable since Go's testing package will interpret it
// as itself being a unit test, so let's just pretend that "registry" and "test"
// are acronyms.
func REGISTRYTEST(context.Context, *State) {}
// testsEqual returns true if a and b contain tests with matching fields.
// This is useful when comparing slices that contain copies of the same underlying tests.
func testsEqual(a, b []*TestInstance) bool {
if len(a) != len(b) {
return false
}
for i := range a {
// Just do a basic comparison, since we clone tests and set additional attributes
// when adding them to the registry.
if a[i].Name != b[i].Name {
return false
}
}
return true
}
// getDupeTestPtrs returns pointers present in both a and b.
func getDupeTestPtrs(a, b []*TestInstance) []*TestInstance {
am := make(map[*TestInstance]struct{}, len(a))
for _, t := range a {
am[t] = struct{}{}
}
var dupes []*TestInstance
for _, t := range b {
if _, ok := am[t]; ok {
dupes = append(dupes, t)
}
}
return dupes
}
func TestAllTests(t *gotesting.T) {
reg := NewRegistry("bundle")
allTests := []*TestInstance{
{Name: "test.Foo", Func: func(context.Context, *State) {}},
{Name: "test.Bar", Func: func(context.Context, *State) {}},
}
for _, test := range allTests {
reg.AddTestInstance(test)
}
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
tests := reg.AllTests()
if !testsEqual(tests, allTests) {
t.Errorf("AllTests() = %v; want %v", tests, allTests)
}
if dupes := getDupeTestPtrs(tests, allTests); len(dupes) != 0 {
t.Errorf("AllTests() returned non-copied test(s): %v", dupes)
}
}
func TestAddTestDuplicateName(t *gotesting.T) {
const name = "test.Foo"
reg := NewRegistry("bundle")
reg.AddTestInstance(&TestInstance{Name: name, Func: func(context.Context, *State) {}})
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Failed to add initial test: ", errs)
}
reg.AddTestInstance(&TestInstance{Name: name, Func: func(context.Context, *State) {}})
if errs := reg.Errors(); len(errs) == 0 {
t.Fatal("Duplicate test name unexpectedly not rejected")
}
}
func TestAddTestModifyOriginal(t *gotesting.T) {
reg := NewRegistry("bundle")
const origDep = "olddep"
test := &Test{
Func: REGISTRYTEST,
SoftwareDeps: []string{origDep},
}
reg.AddTest(test)
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
// Change the original Test struct's dependency slice's data.
test.SoftwareDeps[0] = "newdep"
// The test returned by the registry should still contain the original information.
tests := reg.AllTests()
if len(tests) != 1 {
t.Fatalf("AllTests returned %v; wanted 1 test: ", tests)
}
if want := []string{origDep}; !reflect.DeepEqual(tests[0].SoftwareDeps, want) {
t.Errorf("Test.Deps is %v; want %v", tests[0].SoftwareDeps, want)
}
}
func TestAddTestConflictingPre(t *gotesting.T) {
reg := NewRegistry("bundle")
// There are different preconditions with the same name. Registering tests
// using them should result in errors.
pre1 := &fakePre{"fake_pre"}
pre2 := &fakePre{"fake_pre"}
reg.AddTestInstance(&TestInstance{
Name: "pkg.Test1",
Func: func(context.Context, *State) {},
Pre: pre1,
})
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("AddTestInstance failed for pkg.Test1: ", errs)
}
reg.AddTestInstance(&TestInstance{
Name: "pkg.Test2",
Func: func(context.Context, *State) {},
Pre: pre1,
})
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("AddTestInstance failed for pkg.Test2: ", errs)
}
reg.AddTestInstance(&TestInstance{
Name: "pkg.Test3",
Func: func(context.Context, *State) {},
Pre: pre2,
})
if errs := reg.Errors(); len(errs) == 0 {
t.Fatal("AddTestInstance unexpectedly succeeded for pkg.Test3")
}
}
func TestAddFixtureDuplicateName(t *gotesting.T) {
const name = "foo"
reg := NewRegistry("bundle")
reg.AddFixture(&Fixture{Name: name}, "pkg")
if errs := reg.Errors(); len(errs) > 0 {
t.Fatalf("Fixture registration failed: %v", errs)
}
reg.AddFixture(&Fixture{Name: name}, "pkg2")
if errs := reg.Errors(); len(errs) == 0 {
t.Error("Duplicated fixture registration succeeded unexpectedly")
}
}
func TestAddFixtureInvalidName(t *gotesting.T) {
for _, tc := range []struct {
name string
ok bool
}{
{"", false},
{"a", true},
{"A", false},
{"1", false},
{"%", false},
{"abc", true},
{"aBc", true},
{"a1r", true},
{"a1R", true},
{"a r", false},
{"a_r", false},
{"a-r", false},
{"chromeLoggedIn", true},
{"ieee1394", true},
} {
reg := NewRegistry("bundle")
reg.AddFixture(&Fixture{Name: tc.name}, "pkg")
errs := reg.Errors()
if tc.ok && len(errs) > 0 {
t.Errorf("AddFixture(%q) failed: %v", tc.name, errs)
}
if !tc.ok && len(errs) == 0 {
t.Errorf("AddFixture(%q) passed unexpectedly", tc.name)
}
}
}
func TestAllServices(t *gotesting.T) {
reg := NewRegistry("bundle")
allSvcs := []*Service{
{Register: func(*grpc.Server, *ServiceState) {}},
{Register: func(*grpc.Server, *ServiceState) {}},
{Register: func(*grpc.Server, *ServiceState) {}},
}
for _, svc := range allSvcs {
reg.AddService(svc)
}
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
svcs := reg.AllServices()
if !reflect.DeepEqual(svcs, allSvcs) {
t.Errorf("AllServices() = %v; want %v", svcs, allSvcs)
}
}
func TestAllFixtures(t *gotesting.T) {
reg := NewRegistry("bundle")
allFixts := []*Fixture{
{Name: "a"},
{Name: "b"},
{Name: "c"},
}
for _, f := range allFixts {
reg.AddFixture(f, "pkg")
}
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
want := map[string]*FixtureInstance{
"a": {Name: "a", Pkg: "pkg", Bundle: "bundle"},
"b": {Name: "b", Pkg: "pkg", Bundle: "bundle"},
"c": {Name: "c", Pkg: "pkg", Bundle: "bundle"},
}
if diff := cmp.Diff(reg.AllFixtures(), want); diff != "" {
t.Errorf("Result mismatch (-got +want):\n%v", diff)
}
}
type varType struct {
name string
value string
}
func (v *varType) Unmarshal(data string) error {
v.value = data
return nil
}
func (v *varType) Name() string {
return v.name
}
// TestAllVars makes sure all registered global variables return correctly.
func TestAllVars(t *gotesting.T) {
reg := NewRegistry("bundle")
allVars := map[string]Var{
"a": &varType{name: "a"},
"b": &varType{name: "b"},
"c": &varType{name: "c"},
}
for _, v := range allVars {
reg.AddVar(v)
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
}
// Make sure we cannot register all the registered variable again.
var i int
for n, v := range allVars {
reg.AddVar(v)
i++
if errs := reg.Errors(); len(errs) != i {
t.Fatalf("Registration of the variable %q for the second time should result in failure", n)
}
}
}
// TestAddVarOnce makes sure global variables can only be register once.
func TestAddVarOnce(t *gotesting.T) {
reg := NewRegistry("bundle")
reg.AddVar(&varType{name: "a"})
if errs := reg.Errors(); len(errs) > 0 {
t.Fatal("Registration failed: ", errs)
}
reg.AddVar(&varType{name: "a"})
if errs := reg.Errors(); len(errs) == 0 {
t.Fatal("Variable registration was successful but failure was expected")
}
}
// TestInitializeVarsOnce makes sure global variables can only be initialized once.
func TestInitializeVarsOnce(t *gotesting.T) {
reg := NewRegistry("bundle")
v := varType{name: "a"}
reg.AddVar(&v)
vars := map[string]string{"a": "value"}
if err := reg.InitializeVars(vars); err != nil {
t.Fatal("InitializeVars failed: ", err)
}
if err := reg.InitializeVars(vars); err != nil {
t.Fatal("Failed to call InitializeVars twice with the same value: ", err)
}
if v.value != "value" {
t.Fatalf("Got %q for v.value; wanted value", v.value)
}
vars["a"] = "another value"
if err := reg.InitializeVars(vars); err == nil {
t.Fatal("Got no error when InitializeVars was called the second time with different value")
}
}
// TestInitializeVars tests if InitializeVars works correctly.
func TestInitializeVars(t *gotesting.T) {
const (
name1 = `var1`
name2 = `var2`
val1 = `value1`
val2 = `value2`
defaultVal1 = `v1`
defaultVal2 = `v2`
)
values := map[string]string{
name1: val1,
name2: val2,
}
reg := NewRegistry("bundle")
v1 := NewVarString(name1, val1, "")
v2 := NewVarString(name2, val2, "")
reg.AddVar(v1)
reg.AddVar(v2)
stringVars := map[string]*VarString{
name1: v1,
name2: v2,
}
if err := reg.InitializeVars(values); err != nil {
t.Fatal("Failed to call InitializeVars: ", err)
}
for k, v := range stringVars {
expectedVal, ok := values[k]
if !ok {
t.Error("Failed to find variable ", k)
}
val := v.Value()
if val != expectedVal {
t.Errorf("Variable %q has value %q; want %q", k, val, expectedVal)
}
}
}