Back to / testengine

Package testengine

Latest Go to latest

The highest tagged major version is .

Published: Aug 20, 2020 | License: Apache-2.0 | Module:


Package testengine provides a way to write deterministic, repeatable, serializable, and analyzable tests. Tests are deterministic because all time is fake, there is only ever a single go routine executing, and all randomness is derived from a seed. Tests are repeatable because given the same configuration and random seed, the test actions are deterministic. Tests are serializable because the actions performed are all represented as protobuf messages. And finally, tests are analyzable because the serialized representation of the test actions may be analyzed in tooling after the test has executed. TODO, the above is the plan, but, nothing is implemented at this point.


type ClientConfig

type ClientConfig struct {
	ID          uint64
	TxLatency   uint64
	MaxInFlight int
	Total       uint64

type CommitList

type CommitList struct {
	Commit *mirbft.Commit
	Next   *CommitList

type CompositeMangler

type CompositeMangler struct {
	Manglers []Mangler

func (*CompositeMangler) BeforeStep

func (cm *CompositeMangler) BeforeStep(random int, el *EventLog)

type ConditionalMangler

type ConditionalMangler struct {
	Mangler   Mangler
	Condition func() bool

func (*ConditionalMangler) BeforeStep

func (cm *ConditionalMangler) BeforeStep(random int, el *EventLog)

type DropMangler

type DropMangler struct{}

func (DropMangler) BeforeStep

func (DropMangler) BeforeStep(random int, el *EventLog)

type DuplicateMangler

type DuplicateMangler struct {
	MaxDelay int

func (*DuplicateMangler) BeforeStep

func (dm *DuplicateMangler) BeforeStep(random int, el *EventLog)

type EventLog

type EventLog struct {
	Name               string
	Description        string
	FirstEventLogEntry *EventLogEntry
	NextEventLogEntry  *EventLogEntry
	LastConsumed       *EventLogEntry
	FakeTime           uint64

func ReadEventLog

func ReadEventLog(source io.Reader) (el *EventLog, err error)

func (*EventLog) ConsumeAndAdvance

func (l *EventLog) ConsumeAndAdvance() *tpb.Event

func (*EventLog) Count

func (l *EventLog) Count() int

func (*EventLog) Insert

func (l *EventLog) Insert(event *tpb.Event)

func (*EventLog) InsertProcess

func (l *EventLog) InsertProcess(target uint64, fromNow uint64)

func (*EventLog) InsertProposeEvent

func (l *EventLog) InsertProposeEvent(target uint64, req *pb.Request, fromNow uint64)

func (*EventLog) InsertStateEvent

func (l *EventLog) InsertStateEvent(target uint64, stateEvent *pb.StateEvent, fromNow uint64)

func (*EventLog) InsertStepEvent

func (l *EventLog) InsertStepEvent(target uint64, stepEvent *pb.StateEvent_InboundMsg, fromNow uint64)

func (*EventLog) InsertTickEvent

func (l *EventLog) InsertTickEvent(target uint64, fromNow uint64)

func (*EventLog) Write

func (l *EventLog) Write(dest io.Writer) error

type EventLogEntry

type EventLogEntry struct {
	Event *tpb.Event
	Next  *EventLogEntry
	Prev  *EventLogEntry

type EventMangling

type EventMangling struct {
	Mangler Mangler

EventMangling is meant to be an easy way to construct test descriptions. Each method of EventMangling returns itself so that the constraints are easy to concatenate. For instance:


will drop ten percent of the messages from nodes 1 and 3. Note that order is important here. Another perfectly valid string would be:


But here, because filters are applied last to first, on 10 percent of events, if they are from nodes 1 and 3, they will be dropped.

func Drop

func Drop() *EventMangling

func Duplicate

func Duplicate(maxDelay int) *EventMangling

func Jitter

func Jitter(maxDelay int) *EventMangling

func (*EventMangling) AtPercent

func (em *EventMangling) AtPercent(percent int) *EventMangling

func (*EventMangling) BeforeStep

func (em *EventMangling) BeforeStep(random int, el *EventLog)

func (*EventMangling) ForNodes

func (em *EventMangling) ForNodes(nodes ...uint64) *EventMangling

func (*EventMangling) FromNodes

func (em *EventMangling) FromNodes(nodes ...uint64) *EventMangling

func (*EventMangling) Messages

func (em *EventMangling) Messages() *EventMangling

func (*EventMangling) When

func (em *EventMangling) When(when func() bool) *EventMangling

type EventTypeFilterMangler

type EventTypeFilterMangler struct {
	Type    string
	Mangler Mangler

func (*EventTypeFilterMangler) BeforeStep

func (etfm *EventTypeFilterMangler) BeforeStep(random int, el *EventLog)

type Hasher

type Hasher func() hash.Hash

type JitterMangler

type JitterMangler struct {
	MaxDelay int

JitterMangler will delay events a random amount of time, up to MaxDelay

func (*JitterMangler) BeforeStep

func (jm *JitterMangler) BeforeStep(random int, el *EventLog)

type Mangler

type Mangler interface {
	BeforeStep(random int, el *EventLog)

type MsgSourceFilterMangler

type MsgSourceFilterMangler struct {
	Mangler Mangler
	Source  uint64

func (*MsgSourceFilterMangler) BeforeStep

func (msfm *MsgSourceFilterMangler) BeforeStep(random int, el *EventLog)

type NodeState

type NodeState struct {
	LastCommittedSeqNo uint64
	OutstandingCommits []*mirbft.Commit
	Hasher             hash.Hash
	Value              []byte
	Length             uint64
	FirstCommit        *CommitList
	LastCommit         *CommitList

func (*NodeState) Commit

func (ns *NodeState) Commit(commits []*mirbft.Commit, node uint64) []*pb.CheckpointResult

type PlaybackNode

type PlaybackNode struct {
	ID           uint64
	StateMachine *mirbft.StateMachine
	Processing   *mirbft.Actions
	Actions      *mirbft.Actions
	Status       *mirbft.Status

type Player

type Player struct {
	LastEvent *tpb.Event
	EventLog  *EventLog
	Logger    *zap.Logger
	Nodes     map[uint64]*PlaybackNode

func NewPlayer

func NewPlayer(el *EventLog, logger *zap.Logger) (*Player, error)

func (*Player) Node

func (p *Player) Node(id uint64) *PlaybackNode

func (*Player) Step

func (p *Player) Step() error

type ProbabilisticMangler

type ProbabilisticMangler struct {
	Mangler    Mangler
	Percentage int

func (*ProbabilisticMangler) BeforeStep

func (pm *ProbabilisticMangler) BeforeStep(random int, el *EventLog)

type Recorder

type Recorder struct {
	NetworkState        *pb.NetworkState
	RecorderNodeConfigs []*RecorderNodeConfig
	ClientConfigs       []*ClientConfig
	Manglers            []Mangler
	Logger              *zap.Logger
	Hasher              Hasher
	RandomSeed          int64

func BasicRecorder

func BasicRecorder(nodeCount, clientCount int, reqsPerClient uint64) *Recorder

func (*Recorder) Recording

func (r *Recorder) Recording() (*Recording, error)

type RecorderClient

type RecorderClient struct {
	Config            *ClientConfig
	LastNodeReqNoSend []uint64

func (*RecorderClient) RequestByReqNo

func (rc *RecorderClient) RequestByReqNo(reqNo uint64) *pb.Request

type RecorderNode

type RecorderNode struct {
	PlaybackNode         *PlaybackNode
	State                *NodeState
	Config               *RecorderNodeConfig
	AwaitingProcessEvent bool

type RecorderNodeConfig

type RecorderNodeConfig struct {
	InitParms    *pb.StateEvent_InitialParameters
	RuntimeParms *RuntimeParameters

type Recording

type Recording struct {
	Hasher   Hasher
	EventLog *EventLog
	Player   *Player
	Nodes    []*RecorderNode
	Clients  []*RecorderClient
	Manglers []Mangler
	Rand     *rand.Rand

func (*Recording) DrainClients

func (r *Recording) DrainClients(timeout int) (int, error)

DrainClients will execute the recording until all client requests have committed. It will return with an error if the number of accumulated log entries exceeds timeout. If any step returns an error, this function returns that error.

func (*Recording) Step

func (r *Recording) Step() error

type RuntimeParameters

type RuntimeParameters struct {
	TickInterval   int
	LinkLatency    int
	ReadyLatency   int
	ProcessLatency int
	PersistLatency int

Package Files

Documentation was rendered with GOOS=linux and GOARCH=amd64.

Jump to identifier

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to identifier