blob: f17ec92bf60cb1e3d5560b90e022b338b5a03c3c [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package tastrpc
import (
"context"
"path/filepath"
"testing"
"time"
_go "go.chromium.org/chromiumos/config/go"
"go.chromium.org/chromiumos/config/go/test/api"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
"go.chromium.org/tast/core/framework/protocol"
)
func TestReportsServer_LogStream(t *testing.T) {
const (
testName1 = "test.Name1"
testID1 = "tast.test.Id1"
logSinkName1 = "tests/name01-20210123/test.Name1/log.txt"
requestName1 = "request_for_test_name1"
testLog1a = "log1a"
testLog1b = "log1b"
testName2 = "test.Name2"
testID2 = "tast.test.Id2"
requestName2 = "request_for_test_name2"
logSinkName2 = "tests/name01-20210123/test.Name2/log.txt"
testLog2a = "log2a"
resultDir = "/tmp/tast/results"
)
testNamesToIds := map[string]string{
testName1: testID1,
testName2: testID2,
}
testNamesToMetadata := map[string]*api.TestCaseMetadata{
"test.Name1": {
TestCase: &api.TestCase{
Name: "test.Name1",
},
TestCaseInfo: &api.TestCaseInfo{
Owners: []*api.Contact{
{
Email: "owner1@test.com",
},
},
Requirements: []*api.Requirement{
{
Value: "requirement 1",
},
},
BugComponent: &api.BugComponent{
Value: "b/1234",
},
Criteria: &api.Criteria{
Value: "criteria 1",
},
HwAgnostic: &api.HwAgnostic{
Value: true,
},
},
},
}
srv, err := NewReportsServer(0, []string{testName1, testName2}, testNamesToIds, testNamesToMetadata, resultDir)
if err != nil {
t.Fatalf("Failed to start Reports server: %v", err)
}
defer srv.Stop()
conn, err := grpc.Dial(srv.Address(), grpc.WithInsecure())
if err != nil {
t.Fatalf("Failed to dial: %v", err)
}
defer conn.Close()
cl := protocol.NewReportsClient(conn)
strm, err := cl.LogStream(context.Background())
if err != nil {
t.Fatalf("Failed at LogStream: %v", err)
}
if err := strm.Send(&protocol.LogStreamRequest{
Test: testName1,
LogPath: logSinkName1,
Data: []byte(testLog1a),
}); err != nil {
t.Errorf("failed to send: %v", err)
}
if err := strm.Send(&protocol.LogStreamRequest{
Test: testName1,
LogPath: logSinkName1,
Data: []byte(testLog1b),
}); err != nil {
t.Errorf("failed to send: %v", err)
}
if err := strm.Send(&protocol.LogStreamRequest{
Test: testName2,
LogPath: logSinkName2,
Data: []byte(testLog2a),
}); err != nil {
t.Errorf("failed to send: %v", err)
}
strm.CloseAndRecv()
}
// TestReportsServer_ReportResult makes sure reports server will pass on result to progress sink.
func TestReportsServer_ReportResult(t *testing.T) {
ctx := context.Background()
resultDir := "/tmp/tast/results"
tests := []string{
"PassedTest",
"PassedTestWithNoMetadata",
"FailedTest",
"SkippedTest",
"MissingTest", // Used for testing missing test report.
"MissingTestWithNoMetadata",
}
testIDs := []string{
"PassedTestId",
"PassedTestWithNoMetadataId",
"FailedTestId",
"SkippedTestId",
"MissingTestId", // Used for testing missing test report.
"MissingTestWithNoMetadataId",
}
testNamesToIds := map[string]string{
"PassedTest": "PassedTestId",
"PassedTestWithNoMetadata": "PassedTestWithNoMetadataId",
"FailedTest": "FailedTestId",
"SkippedTest": "SkippedTestId",
"MissingTest": "MissingTestId",
"MissingTestWithNoMetadata": "MissingTestWithNoMetadataId",
}
testNamesToMetadata := map[string]*api.TestCaseMetadata{
"PassedTest": {
TestCase: &api.TestCase{
Name: "PassedTest",
},
TestCaseInfo: &api.TestCaseInfo{
Owners: []*api.Contact{
{
Email: "owner1@test.com",
},
},
Requirements: []*api.Requirement{
{
Value: "requirement 1",
},
},
BugComponent: &api.BugComponent{
Value: "b/1234",
},
Criteria: &api.Criteria{
Value: "criteria 1",
},
HwAgnostic: &api.HwAgnostic{
Value: true,
},
},
},
"SkippedTest": {
TestCase: &api.TestCase{
Name: "SkippedTest",
},
TestCaseInfo: &api.TestCaseInfo{
BugComponent: &api.BugComponent{
Value: "b/1234",
},
},
},
"MissingTest": {
TestCase: &api.TestCase{
Name: "MissingTest",
},
TestCaseInfo: &api.TestCaseInfo{
Criteria: &api.Criteria{
Value: "criteria 2",
},
},
},
"FailedTest": {
TestCase: &api.TestCase{
Name: "FailedTest",
},
TestCaseInfo: &api.TestCaseInfo{
HwAgnostic: &api.HwAgnostic{
Value: false,
},
},
},
}
testTimePassedTest := timestamppb.New(time.Time{})
testTimeFailedTest := timestamppb.New(time.Time{}.Add(1))
testTimeSkippedTest := timestamppb.New(time.Time{}.Add(2))
requests := []*protocol.ReportResultRequest{
{
Test: "PassedTest",
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
},
{
Test: "PassedTestWithNoMetadata",
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
},
{
Test: "FailedTest",
Errors: []*protocol.ErrorReport{
{
Time: testTimeFailedTest,
Reason: "intentionally failed",
File: "/tmp/file.go",
Line: 21,
Stack: "None",
},
},
StartTime: testTimeFailedTest,
Duration: durationpb.New(time.Second),
},
{
Test: "SkippedTest",
SkipReason: "intentionally skipped",
StartTime: testTimeSkippedTest,
Duration: durationpb.New(0),
},
}
expectedReports := []*api.TestCaseResult{
{
TestCaseId: &api.TestCase_Id{Value: testIDs[0]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[0]),
},
Verdict: &api.TestCaseResult_Pass_{Pass: &api.TestCaseResult_Pass{}},
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
TestCaseMetadata: testNamesToMetadata[tests[0]],
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[1]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[1]),
},
Verdict: &api.TestCaseResult_Pass_{Pass: &api.TestCaseResult_Pass{}},
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
TestCaseMetadata: nil,
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[2]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[2]),
},
Verdict: &api.TestCaseResult_Fail_{Fail: &api.TestCaseResult_Fail{}},
Reason: "intentionally failed",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimeFailedTest,
Duration: durationpb.New(time.Second),
TestCaseMetadata: testNamesToMetadata[tests[2]],
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[3]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[3]),
},
Verdict: &api.TestCaseResult_Skip_{Skip: &api.TestCaseResult_Skip{}},
Reason: "intentionally skipped",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimeSkippedTest,
Duration: durationpb.New(0),
TestCaseMetadata: testNamesToMetadata[tests[3]],
},
}
expectedMissingReports := []*api.TestCaseResult{
{
TestCaseId: &api.TestCase_Id{Value: testIDs[4]},
Verdict: &api.TestCaseResult_NotRun_{NotRun: &api.TestCaseResult_NotRun{}},
Reason: "Test did not run",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
TestCaseMetadata: testNamesToMetadata[tests[4]],
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[5]},
Verdict: &api.TestCaseResult_NotRun_{NotRun: &api.TestCaseResult_NotRun{}},
Reason: "Test did not run",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
TestCaseMetadata: nil,
},
}
// Setting up reports server and client
reportsServer, err := NewReportsServer(0, tests, testNamesToIds, testNamesToMetadata, resultDir)
if err != nil {
t.Fatalf("Failed to start Reports server: %v", err)
}
defer reportsServer.Stop()
reportsConn, err := grpc.Dial(reportsServer.Address(), grpc.WithInsecure())
if err != nil {
t.Fatalf("Failed to dial: %v", err)
}
defer reportsConn.Close()
reportsClient := protocol.NewReportsClient(reportsConn)
// Testing for normal reports.
for i, r := range requests {
rspn, err := reportsClient.ReportResult(ctx, r)
if err != nil {
t.Fatalf("Failed at ReportResult: %v", err)
}
if rspn.Terminate {
t.Errorf("ReportResult(ctx, %+v) returned true; wanted false", r)
}
reportErrors := reportsServer.Errors()
if len(reportErrors) > 0 {
t.Fatal("Encountered errors at ReportResult: ", reportErrors)
}
reports := reportsServer.TestsReports()
if !proto.Equal(reports[i], expectedReports[i]) {
t.Errorf("Got unexpected report from test %q (-got +want):\n%v\n--\n%v\n", expectedReports[i].TestCaseId.Value, reports[i], expectedReports[i])
}
}
// Testing for missing reports.
missingReports := reportsServer.MissingTestsReports("Test did not run")
for i := range expectedMissingReports {
if !proto.Equal(missingReports[i], expectedMissingReports[i]) {
t.Errorf("unexpected test results for 'pass' (-got +want):\n%v\n--\n%v\n", missingReports[i], expectedMissingReports[i])
}
}
if reportsServer.Warnings()[0] != "failed to find test metadata for test PassedTestWithNoMetadata" {
t.Errorf("Did not encounter expected warning for PassedTestWithNoMetadata")
}
if reportsServer.Warnings()[1] != "failed to find test metadata for missing test MissingTestWithNoMetadata" {
t.Errorf("Did not encounter expected warning for MissingTestWithNoMetadata")
}
}
// TestReportsServer_ReportResult makes sure reports server will pass on result to progress sink.
func TestReportsServer_ReportResultRetry(t *testing.T) {
ctx := context.Background()
resultDir := "/tmp/tast/results"
tests := []string{
"PassedTest",
"FailedTest",
"SkippedTest",
"MissingTest", // Used for testing missing test report.
}
testIDs := []string{
"PassedTestId",
"FailedTestId",
"SkippedTestId",
"MissingTestId", // Used for testing missing test report.
}
testNamesToIds := map[string]string{
"PassedTest": "PassedTestId",
"FailedTest": "FailedTestId",
"SkippedTest": "SkippedTestId",
"MissingTest": "MissingTestId",
}
testNamesToMetadata := map[string]*api.TestCaseMetadata{
"PassedTest": {
TestCase: &api.TestCase{
Name: "PassedTest",
},
TestCaseInfo: &api.TestCaseInfo{
Owners: []*api.Contact{
{
Email: "owner1@test.com",
},
},
Requirements: []*api.Requirement{
{
Value: "requirement 1",
},
},
BugComponent: &api.BugComponent{
Value: "b/1234",
},
Criteria: &api.Criteria{
Value: "criteria 1",
},
HwAgnostic: &api.HwAgnostic{
Value: true,
},
},
},
"SkippedTest": {
TestCase: &api.TestCase{
Name: "SkippedTest",
},
TestCaseInfo: &api.TestCaseInfo{
BugComponent: &api.BugComponent{
Value: "b/1234",
},
},
},
"MissingTest": {
TestCase: &api.TestCase{
Name: "MissingTest",
},
TestCaseInfo: &api.TestCaseInfo{
Criteria: &api.Criteria{
Value: "criteria 2",
},
},
},
"FailedTest": {
TestCase: &api.TestCase{
Name: "FailedTest",
},
TestCaseInfo: &api.TestCaseInfo{
HwAgnostic: &api.HwAgnostic{
Value: false,
},
},
},
}
testTimePassedTest := timestamppb.New(time.Time{})
testTimeFailedTest := timestamppb.New(time.Time{}.Add(1))
testTimeSkippedTest := timestamppb.New(time.Time{}.Add(2))
testTimeFailedTestRetry := timestamppb.New(time.Time{}.Add(3))
requests := []*protocol.ReportResultRequest{
{
Test: "PassedTest",
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
},
{
Test: "FailedTest",
Errors: []*protocol.ErrorReport{
{
Time: testTimeFailedTest,
Reason: "intentionally failed",
File: "/tmp/file.go",
Line: 21,
Stack: "None",
},
},
StartTime: testTimeFailedTest,
Duration: durationpb.New(time.Second),
},
{
Test: "SkippedTest",
SkipReason: "intentionally skipped",
StartTime: testTimeSkippedTest,
Duration: durationpb.New(0),
},
{
Test: "FailedTest",
StartTime: testTimeFailedTestRetry,
Duration: durationpb.New(time.Second),
},
}
expectedReports := []*api.TestCaseResult{
{
TestCaseId: &api.TestCase_Id{Value: testIDs[0]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[0]),
},
Verdict: &api.TestCaseResult_Pass_{Pass: &api.TestCaseResult_Pass{}},
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimePassedTest,
Duration: durationpb.New(time.Second),
TestCaseMetadata: testNamesToMetadata[tests[0]],
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[2]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[2]),
},
Verdict: &api.TestCaseResult_Skip_{Skip: &api.TestCaseResult_Skip{}},
Reason: "intentionally skipped",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimeSkippedTest,
Duration: durationpb.New(0),
TestCaseMetadata: testNamesToMetadata[tests[2]],
},
{
TestCaseId: &api.TestCase_Id{Value: testIDs[1]},
ResultDirPath: &_go.StoragePath{
HostType: _go.StoragePath_LOCAL,
Path: filepath.Join(resultDir, "tests", tests[1]),
},
Verdict: &api.TestCaseResult_Pass_{Pass: &api.TestCaseResult_Pass{}},
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
StartTime: testTimeFailedTestRetry,
Duration: durationpb.New(time.Second),
TestCaseMetadata: testNamesToMetadata[tests[1]],
},
}
expectedMissingReports := []*api.TestCaseResult{
{
TestCaseId: &api.TestCase_Id{Value: testIDs[3]},
Verdict: &api.TestCaseResult_NotRun_{NotRun: &api.TestCaseResult_NotRun{}},
Reason: "Test did not run",
TestHarness: &api.TestHarness{
TestHarnessType: &api.TestHarness_Tast_{
Tast: &api.TestHarness_Tast{},
},
},
TestCaseMetadata: testNamesToMetadata[tests[3]],
},
}
// Setting up reports server and client
reportsServer, err := NewReportsServer(0, tests, testNamesToIds, testNamesToMetadata, resultDir)
if err != nil {
t.Fatalf("Failed to start Reports server: %v", err)
}
defer reportsServer.Stop()
reportsConn, err := grpc.Dial(reportsServer.Address(), grpc.WithInsecure())
if err != nil {
t.Fatalf("Failed to dial: %v", err)
}
defer reportsConn.Close()
reportsClient := protocol.NewReportsClient(reportsConn)
// Testing for normal reports.
for _, r := range requests {
rspn, err := reportsClient.ReportResult(ctx, r)
if err != nil {
t.Fatalf("Failed at ReportResult: %v", err)
}
if rspn.Terminate {
t.Errorf("ReportResult(ctx, %+v) returned true; wanted false", r)
}
reportErrors := reportsServer.Errors()
if len(reportErrors) > 0 {
t.Fatal("Encountered errors at ReportResult: ", reportErrors)
}
}
reports := reportsServer.TestsReports()
for i, report := range reports {
if !proto.Equal(report, expectedReports[i]) {
t.Errorf("Got unexpected report from test %q (-got +want):\n%v\n--\n%v\n", expectedReports[i].TestCaseId.Value, reports[i], expectedReports[i])
}
}
// Testing for missing reports.
missingReports := reportsServer.MissingTestsReports("Test did not run")
if !proto.Equal(missingReports[0], expectedMissingReports[0]) {
t.Errorf("unexpected test results for 'pass' (-got +want):\n%v\n--\n%v\n", missingReports[0], expectedMissingReports[0])
}
}