blob: ac418443ec78e28c8a181b5587ed51d9660a5429 [file] [edit]
// Copyright 2020 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 planner
import (
gotesting "testing"
"github.com/google/go-cmp/cmp"
"chromiumos/tast/internal/protocol"
"chromiumos/tast/internal/timing"
)
type outputSink struct {
msgs []protocol.Event
}
func newOutputSink() *outputSink {
return &outputSink{}
}
func (s *outputSink) RunLog(msg string) error {
s.msgs = append(s.msgs, &protocol.RunLogEvent{
Text: msg,
})
return nil
}
func (s *outputSink) EntityStart(ei *protocol.Entity, outDir string) error {
s.msgs = append(s.msgs, &protocol.EntityStartEvent{
Entity: ei,
OutDir: outDir,
})
return nil
}
func (s *outputSink) EntityLog(ei *protocol.Entity, msg string) error {
s.msgs = append(s.msgs, &protocol.EntityLogEvent{
EntityName: ei.GetName(),
Text: msg,
})
return nil
}
func (s *outputSink) EntityError(ei *protocol.Entity, e *protocol.Error) error {
s.msgs = append(s.msgs, &protocol.EntityErrorEvent{
EntityName: ei.GetName(),
// Clear Error fields except for Reason.
Error: &protocol.Error{Reason: e.GetReason()},
})
return nil
}
func (s *outputSink) EntityEnd(ei *protocol.Entity, skipReasons []string, timingLog *timing.Log) error {
// Drop timingLog.
var skip *protocol.Skip
if len(skipReasons) > 0 {
skip = &protocol.Skip{Reasons: skipReasons}
}
s.msgs = append(s.msgs, &protocol.EntityEndEvent{EntityName: ei.GetName(), Skip: skip})
return nil
}
// ReadAll reads all control messages written to the sink.
func (s *outputSink) ReadAll() []protocol.Event {
return s.msgs
}
func TestTestOutputStream(t *gotesting.T) {
sink := newOutputSink()
test := &protocol.Entity{Name: "pkg.Test"}
tout := newEntityOutputStream(sink, test)
tout.Start("/tmp/out")
tout.Log("hello")
tout.Error(&protocol.Error{Reason: "faulty", Location: &protocol.ErrorLocation{File: "world.go"}})
tout.Log("world")
tout.End(nil, timing.NewLog())
got := sink.ReadAll()
want := []protocol.Event{
&protocol.EntityStartEvent{Entity: test, OutDir: "/tmp/out"},
&protocol.EntityLogEvent{EntityName: "pkg.Test", Text: "hello"},
&protocol.EntityErrorEvent{EntityName: "pkg.Test", Error: &protocol.Error{Reason: "faulty"}},
&protocol.EntityLogEvent{EntityName: "pkg.Test", Text: "world"},
&protocol.EntityEndEvent{EntityName: "pkg.Test"},
}
if diff := cmp.Diff(got, want); diff != "" {
t.Error("Output mismatch (-got +want):\n", diff)
}
}
func TestTestOutputStreamUnnamedEntity(t *gotesting.T) {
sink := newOutputSink()
test := &protocol.Entity{} // unnamed entity
tout := newEntityOutputStream(sink, test)
tout.Start("/tmp/out")
tout.Log("hello")
tout.Error(&protocol.Error{Reason: "faulty", Location: &protocol.ErrorLocation{File: "world.go"}})
tout.Log("world")
tout.End(nil, timing.NewLog())
got := sink.ReadAll()
var want []protocol.Event
if diff := cmp.Diff(got, want); diff != "" {
t.Error("Output mismatch (-got +want):\n", diff)
}
}
func TestTestOutputStreamErrors(t *gotesting.T) {
sink := newOutputSink()
test := &protocol.Entity{Name: "pkg.Test"}
tout := newEntityOutputStream(sink, test)
tout.Start("/tmp/out")
tout.Error(&protocol.Error{Reason: "error1", Location: &protocol.ErrorLocation{File: "test1.go"}})
tout.Error(&protocol.Error{Reason: "error2", Location: &protocol.ErrorLocation{File: "test2.go"}})
tout.End(nil, timing.NewLog())
tout.Error(&protocol.Error{Reason: "error3", Location: &protocol.ErrorLocation{File: "test3.go"}}) // error after End is ignored
got := tout.Errors()
want := []*protocol.Error{
{Reason: "error1", Location: &protocol.ErrorLocation{File: "test1.go"}},
{Reason: "error2", Location: &protocol.ErrorLocation{File: "test2.go"}},
}
if diff := cmp.Diff(got, want); diff != "" {
t.Error("Errors mismatch (-got +want):\n", diff)
}
}