blob: 71f51ee01acbe19ed540a3a698b875b84b5ec218 [file] [log] [blame]
// Copyright 2018 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 meta
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"chromiumos/tast/remote/bundles/cros/meta/tastrun"
"chromiumos/tast/testing"
)
// runTestsParam is a parameter to the meta.RunTests test.
type runTestsParam struct {
tests []string
wantResults []tastrun.TestResult
wantFiles map[string]string // special value exists/notExists is allowed
}
const (
localVarValue = "a_local_var"
remoteVarValue = "a_remote_var"
// exists can be set to runTestsParam.Files to indicate the file should exist
// without specifying its exact content.
exists = "*exists*"
// notexists can be set to runTestsParam.Files to indicate the file should
// not exist.
notExists = "*notexists*"
)
func init() {
testing.AddTest(&testing.Test{
Func: RunTests,
Desc: "Verifies that Tast can run tests",
Contacts: []string{"nya@chromium.org", "tast-owners@google.com"},
Params: []testing.Param{{
Name: "faillog",
Val: runTestsParam{
tests: []string{
"meta.LocalFail",
"meta.LocalPass",
"meta.RemoteFail",
"meta.RemotePass",
},
wantResults: []tastrun.TestResult{
{Name: "meta.LocalFail", Errors: []tastrun.TestError{{Reason: "Failed"}}},
{Name: "meta.LocalPass"},
{Name: "meta.RemoteFail", Errors: []tastrun.TestError{{Reason: "Failed"}}},
{Name: "meta.RemotePass"},
},
wantFiles: map[string]string{
"tests/meta.LocalFail/faillog/ps.txt": exists,
"tests/meta.LocalPass/faillog/ps.txt": notExists,
"tests/meta.RemoteFail/faillog/*/ps.txt": exists,
"tests/meta.RemotePass/faillog/*/ps.txt": notExists,
},
},
ExtraAttr: []string{"group:mainline", "informational"},
}, {
Name: "files",
Val: runTestsParam{
tests: []string{
"meta.LocalFiles",
},
wantResults: []tastrun.TestResult{
{Name: "meta.LocalFiles"},
},
wantFiles: map[string]string{
"tests/meta.LocalFiles/local_files_internal.txt": "This is an internal data file.\n",
"tests/meta.LocalFiles/local_files_external.txt": "This is an external data file.\n",
"fixtures/metaLocalDataFilesFixture/fixture_data_internal.txt": "This is an internal data file.\n",
"fixtures/metaLocalDataFilesFixture/fixture_data_external.txt": "This is an external data file.\n",
},
},
ExtraAttr: []string{"group:mainline", "group:meta"},
}, {
Name: "files_remote",
Val: runTestsParam{
tests: []string{
"meta.RemoteFiles",
},
wantResults: []tastrun.TestResult{
{Name: "meta.RemoteFiles"},
},
wantFiles: map[string]string{
"tests/meta.RemoteFiles/remote_files_internal.txt": "This is an internal data file for remote tests.\n",
"tests/meta.RemoteFiles/remote_files_external.txt": "This is an external data file for remote tests.\n",
"fixtures/metaRemoteDataFilesFixture/fixture_data_internal.txt": "This is an internal data file for remote tests.\n",
"fixtures/metaRemoteDataFilesFixture/fixture_data_external.txt": "This is an external data file for remote tests.\n",
},
},
ExtraAttr: []string{"group:mainline", "informational"},
}, {
Name: "panic",
Val: runTestsParam{
tests: []string{
"meta.LocalPanic",
},
wantResults: []tastrun.TestResult{
{Name: "meta.LocalPanic", Errors: []tastrun.TestError{{Reason: "Panic: intentionally panicking"}}},
},
},
ExtraAttr: []string{"group:mainline", "group:meta"},
}, {
Name: "vars",
Val: runTestsParam{
tests: []string{
"meta.LocalVars",
"meta.RemoteVars",
},
wantResults: []tastrun.TestResult{
{Name: "meta.LocalVars"},
{Name: "meta.RemoteVars"},
},
wantFiles: map[string]string{
"tests/meta.LocalVars/var.txt": localVarValue,
"tests/meta.RemoteVars/var.txt": remoteVarValue,
},
},
ExtraAttr: []string{"group:mainline", "group:meta"},
}},
})
}
func RunTests(ctx context.Context, s *testing.State) {
param := s.Param().(runTestsParam)
resultsDir := filepath.Join(s.OutDir(), "subtest_results")
flags := []string{
"-resultsdir=" + resultsDir,
"-var=meta.LocalVars.var=" + localVarValue,
"-var=meta.RemoteVars.var=" + remoteVarValue,
}
stdout, _, err := tastrun.Exec(ctx, s, "run", flags, param.tests)
if err != nil {
lines := strings.Split(strings.TrimSpace(string(stdout)), "\n")
s.Fatalf("Failed to run tast: %v (last line: %q)", err, lines[len(lines)-1])
}
results, err := tastrun.ParseResultsJSON(resultsDir)
if err != nil {
s.Fatal("Failed to get results for tests ", param.tests)
}
if !reflect.DeepEqual(results, param.wantResults) {
s.Errorf("Got results %+v; want %+v", results, param.wantResults)
}
// Some tests copy their data files to the output directory.
// These filenames and corresponding contents are hardcoded in the tests.
for p, v := range param.wantFiles {
p = filepath.Join(resultsDir, p)
b, err := readFileWithWildcard(p)
if v == notExists {
if err == nil {
s.Errorf("Output file %v exists unexpectedly", p)
} else if !os.IsNotExist(err) {
s.Errorf("Failed to read output file %v: %v", p, err)
}
continue
}
if err != nil {
s.Errorf("Failed to read output file %v: %v", p, err)
continue
}
if v == exists {
continue
}
if string(b) != v {
s.Errorf("Output file %v contains %q instead of %q", p, string(b), v)
}
}
}
func readFileWithWildcard(p string) ([]byte, error) {
matches, err := filepath.Glob(p)
if err != nil {
return nil, err
}
// Return nil and error of not found if no matched file exist.
if len(matches) <= 0 {
return nil, os.ErrNotExist
}
// Return the file byte of the first existing file found.
return ioutil.ReadFile(matches[0])
}