blob: b2433d6ccb6e5f075ce8acb681c714390150219e [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 fakereports provides a fake implementation of Reports service for unit testing.
package fakereports
import (
"context"
"io"
"net"
"sync"
"testing"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc"
"go.chromium.org/tast/core/framework/protocol"
)
// Server provides a fake resports server to test reports client implementation.
type Server struct {
mtx sync.Mutex
logData map[logKey][]byte
results []*protocol.ReportResultRequest
maxTestFailures int // maxTestFailures specifies maximum number of test allowed. Zero means unlimited.
failuresCount int // The number of test failures so far.
}
type logKey struct {
test string
logPath string
}
var _ protocol.ReportsServer = &Server{}
// Start starts a gRPC server serving ReportsServer in the background for tests.
// Callers are responsible for stopping the server by stopFunc().
func Start(t *testing.T, maxTestFailures int) (server *Server, stopFunc func(), addr string) {
s := &Server{}
srv := grpc.NewServer()
protocol.RegisterReportsServer(srv, s)
lis, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatal("Failed to listen: ", err)
}
s.logData = make(map[logKey][]byte)
s.maxTestFailures = maxTestFailures
go srv.Serve(lis)
return s, srv.Stop, lis.Addr().String()
}
// LogStream provides a means for reports clients to test LogStream requests.
func (s *Server) LogStream(stream protocol.Reports_LogStreamServer) error {
for {
req, err := stream.Recv()
if err == io.EOF {
return stream.SendAndClose(&empty.Empty{})
}
if err != nil {
return err
}
test := req.Test
key := logKey{
test: test,
logPath: req.LogPath,
}
s.mtx.Lock()
s.logData[key] = append(s.logData[key], req.Data...)
s.mtx.Unlock()
}
}
// GetLog returns logs for a particular test.
func (s *Server) GetLog(test, logPath string) []byte {
key := logKey{
test: test,
logPath: logPath,
}
s.mtx.Lock()
defer s.mtx.Unlock()
return s.logData[key]
}
// ReportResult provides a means for reports clients to test ReportResult requests.
func (s *Server) ReportResult(ctx context.Context, req *protocol.ReportResultRequest) (*protocol.ReportResultResponse, error) {
s.mtx.Lock()
defer s.mtx.Unlock()
s.results = append(s.results, req)
if len(req.Errors) > 0 {
s.failuresCount++
}
return &protocol.ReportResultResponse{Terminate: s.maxTestFailures > 0 && s.failuresCount >= s.maxTestFailures}, nil
}
// Results returns all results have been received for this server.
func (s *Server) Results() []*protocol.ReportResultRequest {
s.mtx.Lock()
defer s.mtx.Unlock()
return s.results
}