testlib

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 25, 2022 License: MIT Imports: 13 Imported by: 9

Documentation

Index

Constants

View Source
const (
	// StartStateLabel is the start state label of a state machine
	StartStateLabel = "startState"
	// FailStateLabel is the failure state label
	FailStateLabel = "failState"
	// SuccessStateLabel is the state label of the success state
	SuccessStateLabel = "successState"
)

Variables

This section is empty.

Functions

func NewReportStore

func NewReportStore() *reportStore

Types

type Action

type Action func(*types.Event, *Context) []*types.Message

Action is used to specify the consequence in the `If().Then()` handler

func DeliverMessage

func DeliverMessage() Action

DeliverMessage returns the message if the event is a message send event

func DropMessage

func DropMessage() Action

DropMessage returns an empty list of messages

func RecordMessageAs

func RecordMessageAs(label string) Action

RecordMessageAs returns an action. If the event is a message send or receive, the message is recorded in context with the label as reference

func RestartReplica added in v0.1.4

func RestartReplica(replicaFunc ReplicaFunc) Action

RestartReplica is the action to restart a replica. The replica details are fetched dynamically through the specified function

func StartReplica added in v0.1.4

func StartReplica(replicaFunc ReplicaFunc) Action

StartReplica is the action to start a replica. The replica details are fetched dynamically through the specified function

func StopReplica added in v0.1.4

func StopReplica(replicaFunc ReplicaFunc) Action

StopReplica is the action to stop a replica. The replica details are fetched dynamically through the specified function

type Condition

type Condition func(e *types.Event, c *Context) bool

Condition type to define predicates over the current event or the history of events

func IsEventOf added in v0.1.1

func IsEventOf(replica types.ReplicaID) Condition

IsEventOf returns true if the event if of the specified replica

func IsEventType

func IsEventType(t string) Condition

IsEventType condition returns true if the event is GenericEventType with T == t

func IsMessageFrom

func IsMessageFrom(from types.ReplicaID) Condition

IsMessageFrom condition returns true if the event is a message send or receive with message.From == from

func IsMessageFromF added in v0.1.3

func IsMessageFromF(replicaF func(*types.Event, *Context) (types.ReplicaID, bool)) Condition

IsMessageFromF works the same as IsMessageFrom but the replica is fetched from the event and context

func IsMessageReceive

func IsMessageReceive() Condition

IsMessageReceive condition returns true if the event is a message receive event

func IsMessageSend

func IsMessageSend() Condition

IsMessageSend condition returns true if the event is a message send event

func IsMessageTo

func IsMessageTo(to types.ReplicaID) Condition

IsMessageTo condition returns true if the event is a message send or receive with message.To == to

func IsMessageToF added in v0.1.3

func IsMessageToF(replicaF func(*types.Event, *Context) (types.ReplicaID, bool)) Condition

IsMessageToF works the same as IsMessageTo but the replica is fetched from the event and context

func IsMessageType

func IsMessageType(t string) Condition

IsMessageType condition returns true if the event is a message send or receive and the type of message is `t`

func Once added in v0.1.4

func Once(c Condition) Condition

Once is a meta condition that allows the inner condition to be true only once

func (Condition) And

func (c Condition) And(other Condition) Condition

And to create boolean conditional expressions

func (Condition) Not

func (c Condition) Not() Condition

Not to create boolean conditional expressions

func (Condition) Or

func (c Condition) Or(other Condition) Condition

Or to create boolean conditional expressions

type Context

type Context struct {
	// MessagePool reference to an instance of the MessageStore
	MessagePool *types.MessageStore
	// Replicas reference to the replica store
	Replicas *types.ReplicaStore
	// EventDAG is the directed acyclic graph all prior events
	EventDAG *types.EventDAG
	// Vars is a generic key value store to facilate maintaining auxilliary information
	// during the execution of a testcase
	Vars *VarSet
	// contains filtered or unexported fields
}

Context struct is passed to the calls of StateAction and Condition encapsulates all information needed by the StateAction and Condition to function

func (*Context) Abort

func (c *Context) Abort()

Abort stops the execution of the testcase

func (*Context) EndTestCase

func (c *Context) EndTestCase()

Ends the testcase without failing. The assertion will determine the success of the testcase

func (*Context) GetMessage

func (c *Context) GetMessage(e *types.Event) (*types.Message, bool)

GetMessage returns the `Message` struct from the Message pool if the event provided is a message send ot receive event

func (*Context) Log added in v0.1.1

func (c *Context) Log(keyvals map[string]string)

func (*Context) Logger

func (c *Context) Logger() *log.Logger

Logger returns the logger for the current testcase

func (*Context) NewMessage

func (c *Context) NewMessage(cur *types.Message, data []byte) *types.Message

NewMessage crafts a new message with a new ID The current message contents are replaced with `data`

type CountWrapper

type CountWrapper struct {
	CounterFunc func(*types.Event, *Context) (*Counter, bool)
}

CountWrapper encapsulates the function to fetch counter (CounterFunc) from state dynamically. CountWrapper is used to define actions and condition based on the counter.

func Count

func Count(label string) *CountWrapper

Count returns a CountWrapper where the CounterFunc fetches the counter based on the label

func CountF

func CountF(labelFunc func(*types.Event, *Context) (string, bool)) *CountWrapper

CountF returns a CountWrapper where the label is also fetched based on the event and context

func CountTo

func CountTo(label string) *CountWrapper

CountTo returns a CountWrapper where the counter label is `label` appended with message.To, if the event is a message send or receive

func (*CountWrapper) Eq

func (c *CountWrapper) Eq(val int) Condition

Eq condition that returns true if the counter value is equal to the specified value.

func (*CountWrapper) EqF

func (c *CountWrapper) EqF(val func(*types.Event, *Context) (int, bool)) Condition

EqF condition that returns true if the counter value is equal to the specified value. The input is a function that obtains the value dynamically based on the event and context.

func (*CountWrapper) Geq

func (c *CountWrapper) Geq(val int) Condition

Geq condition that returns true if the counter value is greater than or equal to the specified value.

func (*CountWrapper) GeqF

func (c *CountWrapper) GeqF(val func(*types.Event, *Context) (int, bool)) Condition

GeqF condition that returns true if the counter value is greather than or equal to the specified value. The input is a function that obtains the value dynamically based on the event and context.

func (*CountWrapper) Gt

func (c *CountWrapper) Gt(val int) Condition

Gt condition that returns true if the counter value is greater than the specified value.

func (*CountWrapper) GtF

func (c *CountWrapper) GtF(val func(*types.Event, *Context) (int, bool)) Condition

GtF condition that returns true if the counter value is greater than the specified value. The input is a function that obtains the value dynamically based on the event and context.

func (*CountWrapper) Incr

func (c *CountWrapper) Incr() Action

Incr returns an action which increments the counter value

func (*CountWrapper) Leq

func (c *CountWrapper) Leq(val int) Condition

Leq condition that returns true if the counter value is less than or equal to the specified value.

func (*CountWrapper) LeqF

func (c *CountWrapper) LeqF(val func(*types.Event, *Context) (int, bool)) Condition

LeqF condition that returns true if the counter value is less than or equal to the specified value. The input is a function that obtains the value dynamically based on the event and context.

func (*CountWrapper) Lt

func (c *CountWrapper) Lt(val int) Condition

Lt condition that returns true if the counter value is less than the specified value.

func (*CountWrapper) LtF

func (c *CountWrapper) LtF(valF func(*types.Event, *Context) (int, bool)) Condition

LtF condition that returns true if the counter value is less than the specified value. The input is a function that obtains the value dynamically based on the event and context.

type Counter

type Counter struct {
	// contains filtered or unexported fields
}

Counter threadsafe counter

func NewCounter

func NewCounter() *Counter

NewCounter returns a counter

func (*Counter) Incr

func (c *Counter) Incr()

Incr increments the counter

func (*Counter) SetValue

func (c *Counter) SetValue(v int)

SetValue sets the counter to the specified value

func (*Counter) Value

func (c *Counter) Value() int

Value returns the counter value

type HandlerCascade

type HandlerCascade struct {
	Handlers       []HandlerFunc
	DefaultHandler HandlerFunc
}

HandlerCascade implements Handler Executes handlers in the specified order until the event is handled If no handler handles the event then the default handler is called

func NewHandlerCascade

func NewHandlerCascade(opts ...HandlerCascadeOption) *HandlerCascade

NewHandlerCascade creates a new cascade handler with the specified state machine and options

func (*HandlerCascade) AddHandler

func (c *HandlerCascade) AddHandler(h HandlerFunc)

AddHandler adds a handler to the cascade

type HandlerCascadeOption

type HandlerCascadeOption func(*HandlerCascade)

HandlerCascadeOption changes the parameters of the HandlerCascade

func WithDefault

func WithDefault(d HandlerFunc) HandlerCascadeOption

WithDefault changes the HandlerCascade default handler

type HandlerFunc

type HandlerFunc func(*types.Event, *Context) ([]*types.Message, bool)

HandlerFunc type to define a conditional handler returns false in the second return value if the handler is not concerned about the event

func NewStateMachineHandler

func NewStateMachineHandler(stateMachine *StateMachine) HandlerFunc

NewStateMachineHandler returns a HandlerFunc that encodes the execution logic of the StateMachine For every invocation of the handler, internall a state machine step is executed which may or may not transition. If the StateMachine transitions to FailureState, the handler aborts the testcase

type IfThenHandler

type IfThenHandler struct {
	// contains filtered or unexported fields
}

IfThenHandler struct is used to wrap the attributes of the `If().Then()` handler

func If

func If(cond Condition) *IfThenHandler

If creates a IfThenHandler with the specified condition

func (*IfThenHandler) Then

func (i *IfThenHandler) Then(action Action, rest ...Action) HandlerFunc

Then returns a HandlerFunc which encodes the `If().Then()` semantics. Accepts actions as arguments

type ReplicaFunc added in v0.1.4

type ReplicaFunc func(*types.Event, *Context) (types.ReplicaID, bool)

func EventReplica added in v0.1.4

func EventReplica() ReplicaFunc

EventReplica ReplicaFunc returns the replica of the current event.

func MessageFrom added in v0.1.4

func MessageFrom() ReplicaFunc

MessageFrom ReplicaFunc returns the message from replica, if the event is a message send/receive

func MessageTo added in v0.1.4

func MessageTo() ReplicaFunc

MessageTo ReplicaFunc returns the message to replica, if the event is a message send/receive

type SetWrapper

type SetWrapper struct {
	SetFunc func(*types.Event, *Context) (*types.MessageStore, bool)
}

SetWrapper encapsulates the mechanism to fetch a message set from the state. SetFunc should return a message set given the current event and context.

func Set

func Set(label string) *SetWrapper

Set returns a SetWrapper where the set is fetched based on the label

func SetF

func SetF(labelFunc func(*types.Event, *Context) (string, bool)) *SetWrapper

SetF returns a SetWrapper where the label is determined dynamically by the event and context

func (*SetWrapper) Contains

func (s *SetWrapper) Contains() Condition

Contains condition returns true if the event is a message send or receive and the message is apart of the message set.

func (*SetWrapper) Count

func (s *SetWrapper) Count() *CountWrapper

Count returns a counter where the value is size of the message set

func (*SetWrapper) DeliverAll

func (s *SetWrapper) DeliverAll() Action

DeliverAll returns an action which inturn returns all the messages in the message set and removes the messages from the set.

func (*SetWrapper) Store

func (s *SetWrapper) Store() Action

Store returns an action. If the event is a message send or receive, the action adds the message to the message set

type State

type State struct {
	Label       string               `json:"label"`
	Transitions map[string]Condition `json:"-"`
	Success     bool                 `json:"success"`
	// contains filtered or unexported fields
}

State of the testcase state machine

func (*State) Eq

func (s *State) Eq(other *State) bool

Eq returns true if the two state labels are the same

func (*State) Is

func (s *State) Is(l string) bool

Is returns true if the label matches with the current state label

func (*State) MarshalJSON

func (s *State) MarshalJSON() ([]byte, error)

type StateMachine

type StateMachine struct {
	// contains filtered or unexported fields
}

StateMachine is a deterministic transition system where the transitions are labelled by conditions

func NewStateMachine

func NewStateMachine() *StateMachine

NewStateMachine instantiate a StateMachine

func (*StateMachine) Builder

func (s *StateMachine) Builder() StateMachineBuilder

Builder retruns a StateMachineBuilder instance which provides a builder patter to construct the state machine

func (*StateMachine) CurState

func (s *StateMachine) CurState() *State

CurState return the State that the StateMachine is currently in

func (*StateMachine) InState

func (s *StateMachine) InState(state string) Condition

InState returns a condition which is true if the StateMachine is in a specific state. This can be used to define handler that access the state

func (*StateMachine) InSuccessState

func (s *StateMachine) InSuccessState() bool

InSuccessState returns true if the current state of the state machine is a success state

func (*StateMachine) Transition

func (s *StateMachine) Transition(to string)

Transition moves the current stat eof the StateMachine to the specified state

type StateMachineBuilder

type StateMachineBuilder struct {
	// contains filtered or unexported fields
}

StateMachineBuilder struct defines a builder pattern to create a state machine

func (StateMachineBuilder) MarkSuccess

func (s StateMachineBuilder) MarkSuccess() StateMachineBuilder

MarkSuccess marks the current state of the builder as a success state

func (StateMachineBuilder) On

On can be used to create a transition relation between states based on the specified condition

type TestCase

type TestCase struct {
	// Name name of the testcase
	Name string
	// Timeout maximum duration of the testcase execution
	Timeout time.Duration

	// Cascade instance of *HandlerCascade
	Cascade *HandlerCascade
	// StateMachine instance of *StateMachine to assert a property
	StateMachine *StateMachine

	// Logger to log information
	Logger *log.Logger
	// contains filtered or unexported fields
}

TestCase represents a unit test case

func NewTestCase

func NewTestCase(name string, timeout time.Duration, sm *StateMachine, cascade *HandlerCascade) *TestCase

NewTestCase instantiates a TestCase based on the parameters specified The new testcase has three states by default. - Start state where the execution starts from - Fail state that can be used to fail the testcase - Success state that can be used to indicate a success of the testcase

func (*TestCase) Abort

func (t *TestCase) Abort()

Abort the testcase

func (*TestCase) End

func (t *TestCase) End()

End the testcase

func (*TestCase) SetupFunc

func (t *TestCase) SetupFunc(setupFunc func(*Context) error)

SetupFunc can be used to set the setup function

type TestingServer

type TestingServer struct {
	*types.BaseService
	// contains filtered or unexported fields
}

TestingServer is used to run the scheduler tool for unit testing

func NewTestingServer

func NewTestingServer(config *config.Config, messageParser types.MessageParser, testcases []*TestCase) (*TestingServer, error)

NewTestingServer instantiates TestingServer testcases are passed as arguments

func (*TestingServer) Done

func (srv *TestingServer) Done() chan string

Done returns the channel which will be closed once all testcases are run

func (*TestingServer) Name

func (srv *TestingServer) Name() string

Name implements DashboardRouter

func (*TestingServer) SetupRouter

func (srv *TestingServer) SetupRouter(router *gin.RouterGroup)

SetupRouter for setting up the dashboard routes implements DashboardRouter

func (*TestingServer) Start

func (srv *TestingServer) Start()

Start starts the TestingServer and implements Service

func (*TestingServer) Stop

func (srv *TestingServer) Stop()

Stop stops the TestingServer and implements Service

type TimeoutDriver

type TimeoutDriver struct {
	// contains filtered or unexported fields
}

Flow of execution

  1. Update the timeout context with the current event that is observed a. Keep track of pending timeouts b. Keep track of messages that have been delivered but not acknowledged
  2. Check delivery of messages that are currently intended to be delivered a. Easy to modify graph (mark nodes as clean and dirty) b. Check spuriousness (this can be configured explicitly) c. Easy algorithm to check spuriousness d. algorithm to order the timeouts that need to be fired.
  3. Update with additional timers that need to be fired a. Parameterized strategy to pick timeouts b. Ability for filters to mark certain timeouts to be fired earlier

func NewTimeoutDriver

func NewTimeoutDriver(store *types.TimeoutStore) *TimeoutDriver

func (*TimeoutDriver) NewEvent

func (t *TimeoutDriver) NewEvent(e *types.Event)

func (*TimeoutDriver) ToDispatch

func (t *TimeoutDriver) ToDispatch() []*types.ReplicaTimeout

type VarSet

type VarSet struct {
	// contains filtered or unexported fields
}

VarSet is a dictionary for storing auxilliary state during the execution of the testcase VarSet is stored in the context passed to actions and conditions

func NewVarSet

func NewVarSet() *VarSet

NewVarSet instantiates Vars

func (*VarSet) Exists

func (v *VarSet) Exists(label string) bool

Exists returns true if there is a variable of the specified key

func (*VarSet) Get

func (v *VarSet) Get(label string) (interface{}, bool)

Get returns the value stored of the specified label the second return argument is false if the label does not exist

func (*VarSet) GetBool

func (v *VarSet) GetBool(label string) (bool, bool)

GetBool casts the value at label (if it exists) into boolean and returns it

func (*VarSet) GetCounter

func (v *VarSet) GetCounter(label string) (*Counter, bool)

GetCounter returns the counter at the label if it exists (nil, false) otherwise

func (*VarSet) GetInt

func (v *VarSet) GetInt(label string) (int, bool)

GetInt casts the value at label (if it exists) into integer and returns it

func (*VarSet) GetMessageSet

func (v *VarSet) GetMessageSet(label string) (*types.MessageStore, bool)

GetMessageSet returns the message set at label if one exists (nil, false) otherwise

func (*VarSet) GetString

func (v *VarSet) GetString(label string) (string, bool)

GetString casts the value at label (if it exists) into string and returns it

func (*VarSet) NewMessageSet

func (v *VarSet) NewMessageSet(label string)

NewMessageSet creates a message set at the specified label

func (*VarSet) Set

func (v *VarSet) Set(label string, value interface{})

Set the value at the specified label

func (*VarSet) SetCounter

func (v *VarSet) SetCounter(label string)

SetCounter sets a counter instance at the specified label with initial value 1

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL