testlib

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2022 License: MIT Imports: 14 Imported by: 11

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

View Source
var (
	ErrNotEnoughReplicas  = errors.New("not enough replicas")
	ErrSizeLabelsMismatch = errors.New("sizes and labels are not of the same length")
)

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 OnceAction added in v0.1.1

func OnceAction(action Action) Action

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

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

func IsEventOf(replica types.ReplicaID) Condition

IsEventOf returns true if the event if of the specified replica

func IsEventOfF added in v0.1.1

func IsEventOfF(replicaFunc func(*types.Event, *Context) (types.ReplicaID, bool)) Condition

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

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 IsMessageFromPart added in v0.1.1

func IsMessageFromPart(partLabel string) Condition

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

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 OnceCondition added in v0.1.1

func OnceCondition(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) CreatePartition added in v0.1.1

func (c *Context) CreatePartition(sizes []int, labels []string)

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

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 FilterFunc

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

FilterFunc 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) FilterFunc

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 FilterSet

type FilterSet struct {
	Filters       []FilterFunc
	DefaultFilter FilterFunc
}

FilterSet 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 NewFilterSet

func NewFilterSet(opts ...FilterSetOption) *FilterSet

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

func (*FilterSet) AddFilter

func (c *FilterSet) AddFilter(h FilterFunc)

AddFilter adds a handler to the cascade

type FilterSetOption

type FilterSetOption func(*FilterSet)

FilterSetOption changes the parameters of the HandlerCascade

func WithDefault

func WithDefault(d FilterFunc) FilterSetOption

WithDefault changes the HandlerCascade default handler

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) FilterFunc

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

type ReplicaPartition added in v0.1.1

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

func NewPartition added in v0.1.1

func NewPartition(replicas *types.ReplicaStore, sizes []int, labels []string) (*ReplicaPartition, error)

func (*ReplicaPartition) InPart added in v0.1.1

func (p *ReplicaPartition) InPart(replicaID types.ReplicaID, partLabel string) bool

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 *FilterSet
	// 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 *FilterSet) *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 TestCaseDriver added in v0.1.1

type TestCaseDriver struct {
	TestCase *TestCase
	// contains filtered or unexported fields
}

func NewTestDriver added in v0.1.1

func NewTestDriver(ctx *context.RootContext, testcase *TestCase) *TestCaseDriver

func (*TestCaseDriver) Step added in v0.1.1

func (d *TestCaseDriver) Step(e *types.Event) []*types.Message

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