pkg/event/testevent/test.go (112 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
package testevent
import (
"encoding/json"
"fmt"
"time"
"github.com/facebookincubator/contest/pkg/event"
"github.com/facebookincubator/contest/pkg/event/internal/querytools"
"github.com/facebookincubator/contest/pkg/target"
"github.com/facebookincubator/contest/pkg/types"
"github.com/facebookincubator/contest/pkg/xcontext"
)
// Header models the header of a test event, which consists in metadata that defines the
// emitter of the events. The Header is under ConTest control and cannot be manipulated
// by the TestStep
type Header struct {
JobID types.JobID
RunID types.RunID
TestName string
TestStepLabel string
}
// Data models the data of a test event. It is populated by the TestStep
type Data struct {
Target *target.Target
EventName event.Name
Payload *json.RawMessage
}
// Event models an event object that can be emitted by a TestStep
type Event struct {
EmitTime time.Time
Header *Header
Data *Data
}
// New creates a new Event with zero value header and data
func New(header *Header, data *Data) Event {
return Event{Header: header, Data: data}
}
// Query wraps information that are used to build queries for
// test events, on top of the common EventQuery fields
type Query struct {
event.Query
RunID types.RunID
TestName string
TestStepLabel string
}
// QueryField defines a function type used to set a field's value on Query objects
type QueryField interface {
queryFieldPointer(query *Query) interface{}
}
// QueryFields is a set of field values for a Query object
type QueryFields []QueryField
// BuildQuery compiles a Query from scratch using values of queryFields.
// It does basically just creates an empty query an applies queryFields to it.
func (queryFields QueryFields) BuildQuery() (*Query, error) {
query := &Query{}
for idx, queryField := range queryFields {
if err := querytools.ApplyQueryField(queryField.queryFieldPointer(query), queryField); err != nil {
return nil, fmt.Errorf("unable to apply field %d:%T(%v): %w", idx, queryField, queryField, err)
}
}
return query, nil
}
// BuildQuery compiles a Query from scratch using values of queryFields.
// It does basically just creates an empty query an applies queryFields to it.
func BuildQuery(queryFields ...QueryField) (*Query, error) {
return QueryFields(queryFields).BuildQuery()
}
type queryFieldJobID types.JobID
type queryFieldEventNames []event.Name
type queryFieldEmittedStartTime time.Time
type queryFieldEmittedEndTime time.Time
type queryFieldTestName string
type queryFieldTestStepLabel string
type queryFieldRunID types.RunID
// QueryJobID sets the JobID field of the Query object
func QueryJobID(jobID types.JobID) QueryField { return queryFieldJobID(jobID) }
func (value queryFieldJobID) queryFieldPointer(query *Query) interface{} { return &query.JobID }
// QueryEventNames the EventNames field of the Query object
func QueryEventNames(eventNames []event.Name) QueryField { return queryFieldEventNames(eventNames) }
func (value queryFieldEventNames) queryFieldPointer(query *Query) interface{} {
return &query.EventNames
}
// QueryEventName sets a single EventName field in the Query objec
func QueryEventName(eventName event.Name) QueryField { return queryFieldEventNames{eventName} }
// QueryEmittedStartTime sets the EmittedStartTime field of the Query object
func QueryEmittedStartTime(emittedStartTime time.Time) QueryField {
return queryFieldEmittedStartTime(emittedStartTime)
}
func (value queryFieldEmittedStartTime) queryFieldPointer(query *Query) interface{} {
return &query.EmittedStartTime
}
// QueryEmittedEndTime sets the EmittedEndTime field of the Query object
func QueryEmittedEndTime(emittedEndTime time.Time) QueryField {
return queryFieldEmittedEndTime(emittedEndTime)
}
func (value queryFieldEmittedEndTime) queryFieldPointer(query *Query) interface{} {
return &query.EmittedEndTime
}
// QueryTestName sets the TestName field of the Query object
func QueryTestName(testName string) QueryField {
return queryFieldTestName(testName)
}
func (value queryFieldTestName) queryFieldPointer(query *Query) interface{} { return &query.TestName }
// QueryTestStepLabel sets the TestStepLabel field of the Query object
func QueryTestStepLabel(testStepLabel string) QueryField {
return queryFieldTestStepLabel(testStepLabel)
}
func (value queryFieldTestStepLabel) queryFieldPointer(query *Query) interface{} {
return &query.TestStepLabel
}
// QueryRunID sets the RunID field of the Query object
func QueryRunID(runID types.RunID) QueryField {
return queryFieldRunID(runID)
}
func (value queryFieldRunID) queryFieldPointer(query *Query) interface{} { return &query.RunID }
// Emitter defines the interface that emitter objects must implement
type Emitter interface {
Emit(ctx xcontext.Context, event Data) error
}
// Fetcher defines the interface that fetcher objects must implement
type Fetcher interface {
Fetch(ctx xcontext.Context, fields ...QueryField) ([]Event, error)
}
// EmitterFetcher defines the interface that objects supporting emitting and fetching events must implement
type EmitterFetcher interface {
Emitter
Fetcher
}
func (h *Header) String() string {
return fmt.Sprintf("[%d %d %s %s]", h.JobID, h.RunID, h.TestName, h.TestStepLabel)
}
func (d *Data) String() string {
ps := ""
if d.Payload != nil {
ps = fmt.Sprintf(" %q", d.Payload) //nolint SA5009 - works fine
}
return fmt.Sprintf("[%s %s%s]", d.Target, d.EventName, ps)
}