blob: 3c02f3c978acd32b9d44d2d77936e74309746bda [file]
// Copyright 2019 The Chromium 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 testspec
import (
"fmt"
"io"
"strings"
"testing"
"github.com/kylelemons/godebug/pretty"
"go.chromium.org/chromiumos/infra/proto/go/chromite/api"
"go.chromium.org/luci/common/errors"
)
func TestGetReturnsPartialResults(t *testing.T) {
fl := newFakeLoader()
fl.AddSuites([]string{"suite", "non_existent_suite"})
fl.AddTests([]string{"test", "non_existent_test"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test": testWithNameAndSuites("test", []string{}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{
"suite": {Name: "suite"},
})
g := getter{fl, ft, fs}
resp, err := g.Get("ignored")
if err == nil {
t.Errorf("getter.Get() did not report parse failures")
}
wantTests := []string{"test"}
gotTests := []string{}
for _, t := range resp.GetAutotest().GetTests() {
gotTests = append(gotTests, t.Name)
}
if diff := pretty.Compare(wantTests, gotTests); diff != "" {
t.Errorf("Tests differ, -want +got, %s", diff)
}
wantSuites := []string{"suite"}
gotSuites := []string{}
for _, s := range resp.GetAutotest().GetSuites() {
gotSuites = append(gotSuites, s.Name)
}
if diff := pretty.Compare(wantSuites, gotSuites); diff != "" {
t.Errorf("Suites differ, -want +got, %s", diff)
}
}
func TestGetSuiteWithoutTests(t *testing.T) {
fl := newFakeLoader()
fl.AddSuites([]string{"suite"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{
"suite": {Name: "suite"},
})
g := getter{fl, ft, fs}
resp, err := g.Get("ignored")
if err != nil {
t.Fatalf("getter.Get(): %s", err)
}
want := map[string][]string{"suite": {}}
got := extractSuiteTests(resp.GetAutotest().GetSuites())
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("Suite.Tests differ, -want +got, %s", diff)
}
}
func TestGetSuiteWithOneTest(t *testing.T) {
fl := newFakeLoader()
fl.AddTests([]string{"test"})
fl.AddSuites([]string{"suite"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test": testWithNameAndSuites("test", []string{"suite"}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{
"suite": {Name: "suite"},
})
g := getter{fl, ft, fs}
resp, err := g.Get("root")
if err != nil {
t.Fatalf("getter.Get(): %s", err)
}
want := map[string][]string{"suite": {"test"}}
got := extractSuiteTests(resp.GetAutotest().GetSuites())
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("Suite.Tests differ, -want +got, %s", diff)
}
}
func TestGetSuiteWithTwoTests(t *testing.T) {
fl := newFakeLoader()
fl.AddTests([]string{"test1", "test2"})
fl.AddSuites([]string{"suite"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test1": testWithNameAndSuites("test1", []string{"suite"}),
"test2": testWithNameAndSuites("test2", []string{"suite"}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{
"suite": {Name: "suite"},
})
g := getter{fl, ft, fs}
resp, err := g.Get("root")
if err != nil {
t.Fatalf("getter.Get(): %s", err)
}
want := map[string][]string{"suite": {"test1", "test2"}}
got := extractSuiteTests(resp.GetAutotest().GetSuites())
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("Suite.Tests differ, -want +got, %s", diff)
}
}
func TestGetTwoSuitesWithSameTest(t *testing.T) {
fl := newFakeLoader()
fl.AddTests([]string{"test"})
fl.AddSuites([]string{"suite1", "suite2"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test": testWithNameAndSuites("test", []string{"suite1", "suite2"}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{
"suite1": {Name: "suite1"},
"suite2": {Name: "suite2"},
})
g := getter{fl, ft, fs}
resp, err := g.Get("root")
if err != nil {
t.Fatalf("getter.Get(): %s", err)
}
want := map[string][]string{
"suite1": {"test"},
"suite2": {"test"},
}
got := extractSuiteTests(resp.GetAutotest().GetSuites())
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("Suite.Tests differ, -want +got, %s", diff)
}
}
func TestGetTestInNonExistentSuite(t *testing.T) {
fl := newFakeLoader()
fl.AddTests([]string{"test"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test": testWithNameAndSuites("test", []string{"non_existent_suite"}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{})
g := getter{fl, ft, fs}
resp, err := g.Get("ignored")
if err != nil {
t.Fatalf("getter.Get(): %s", err)
}
want := map[string][]string{}
got := extractSuiteTests(resp.GetAutotest().GetSuites())
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("Suite.Tests differ, -want +got, %s", diff)
}
}
func TestGetValidatesTestName(t *testing.T) {
fl := newFakeLoader()
fl.AddTests([]string{"test", "corrupt_test"})
ft := newFakeParseTestControlFn(map[string]*testMetadata{
"test": testWithNameAndSuites("test", []string{"non_existent_suite"}),
"corrupt_test": testWithNameAndSuites("", []string{}),
})
fs := newFakeParseSuiteControlFn(map[string]*api.AutotestSuite{})
g := getter{fl, ft, fs}
resp, err := g.Get("ignored")
if err == nil {
t.Fatalf("getter.Get() did not report validation failure")
}
wantTests := []string{"test"}
gotTests := []string{}
for _, t := range resp.GetAutotest().GetTests() {
gotTests = append(gotTests, t.Name)
}
if diff := pretty.Compare(wantTests, gotTests); diff != "" {
t.Errorf("Tests differ, -want +got, %s", diff)
}
}
// newFakeParseTestControlFn returns a fake parseTestControlFn that returns
// canned parse results.
//
// canned must map *contents of the control file* to their parse results. The
// returned parseTestControlFn returns error for any control file not in canned.
func newFakeParseTestControlFn(canned map[string]*testMetadata) parseTestControlFn {
return func(text string) (*testMetadata, errors.MultiError) {
tm, ok := canned[text]
if !ok {
return nil, errors.NewMultiError(errors.Reason("uncanned control file: %s", text).Err())
}
return tm, nil
}
}
func testWithNameAndSuites(name string, suites []string) *testMetadata {
return &testMetadata{
AutotestTest: api.AutotestTest{
Name: name,
ExecutionEnvironment: api.AutotestTest_EXECUTION_ENVIRONMENT_CLIENT,
},
Suites: suites,
}
}
// newFakeParseSuiteControlFn returns a fake parseSuiteControlFn that returns
// canned parse results.
//
// canned must map *contents of the control file* to their parse results. The
// returned parseSuiteControlFn returns error for any control file not in
// canned.
func newFakeParseSuiteControlFn(canned map[string]*api.AutotestSuite) parseSuiteControlFn {
return func(text string) (*api.AutotestSuite, errors.MultiError) {
as, ok := canned[text]
if !ok {
return nil, errors.NewMultiError(errors.Reason("uncanned control file: %s", text).Err())
}
return as, nil
}
}
func newFakeLoader() *fakeLoader {
return &fakeLoader{
tests: make(map[string]io.Reader),
suites: make(map[string]io.Reader),
}
}
type fakeLoader struct {
tests map[string]io.Reader
suites map[string]io.Reader
pathSuffix int
}
// AddTests adds the given texts as a test new control files at arbitrary
// paths.
func (d *fakeLoader) AddTests(texts []string) {
for _, t := range texts {
d.tests[fmt.Sprintf("test%d", d.pathSuffix)] = strings.NewReader(t)
d.pathSuffix++
}
}
// RegisterSuite adds the given texts as a new suite control files at arbitrary
// paths.
func (d *fakeLoader) AddSuites(texts []string) {
for _, t := range texts {
d.suites[fmt.Sprintf("test%d", d.pathSuffix)] = strings.NewReader(t)
d.pathSuffix++
}
}
func (d *fakeLoader) Discover(string) error {
return nil
}
func (d *fakeLoader) Tests() map[string]io.Reader {
return d.tests
}
func (d *fakeLoader) Suites() map[string]io.Reader {
return d.suites
}
func extractSuiteTests(suites []*api.AutotestSuite) map[string][]string {
m := make(map[string][]string)
for _, s := range suites {
ts := []string{}
for _, t := range s.GetTests() {
ts = append(ts, t.Name)
}
m[s.Name] = ts
}
return m
}