Documentation
¶
Overview ¶
Package xtesting provides utilities for testing.
Index ¶
- Constants
- Variables
- func AppendToEventStream(t testing.TB, x xsql.Executor, streamID *uuidpb.UUID, events ...dogma.Event) []*envelopepb.Envelope
- func AppendToNewEventStream(t testing.TB, x xsql.Executor, events ...dogma.Event) (*uuidpb.UUID, []*envelopepb.Envelope)
- func ContextWithManualDeadline(parent context.Context) (context.Context, func())
- func CreateEventStream(t testing.TB, x xsql.Executor) *uuidpb.UUID
- func CreateEventStreams(t testing.TB, x xsql.Executor, count int) []*uuidpb.UUID
- func DialGRPC(t testing.TB, engines ...*runkit.Engine) *grpc.ClientConn
- func DialGRPCAddr(t testing.TB, target string, options ...grpc.DialOption) *grpc.ClientConn
- func EnqueuePostponedCommand(t testing.TB, x xsql.Executor, command dogma.Command) *envelopepb.Envelope
- func ExecOne(t testing.TB, x xsql.Executor, query string, args ...any)
- func ExecuteCommand(t testing.TB, executor dogma.CommandExecutor, command dogma.Command, ...) *envelopepb.Envelope
- func ExecuteCommandAndWait(t testing.TB, executor dogma.CommandExecutor, db *sql.DB, ...) *envelopepb.Envelope
- func ExecuteCommandWithHook(t testing.TB, executor dogma.CommandExecutor, command dogma.Command, ...) *envelopepb.Envelope
- func ExecuteCommandsSequentially(t testing.TB, executor dogma.CommandExecutor, db *sql.DB, ...) []*envelopepb.Envelope
- func Expect[T any](t testing.TB, description string, got, want T)
- func ExpectCommandIDToBeQueued(t testing.TB, q xsql.Querier, messageID *uuidpb.UUID)
- func ExpectCommandToBeQueued(t testing.TB, q xsql.Querier, want dogma.Command)
- func ExpectCommandToBeUnattempted(t testing.TB, q xsql.Querier, messageID *uuidpb.UUID)
- func ExpectContiguousEvents(t testing.TB, q xsql.Querier, streamID *uuidpb.UUID, offset uint64, ...)
- func ExpectEventCount(t testing.TB, q xsql.Querier, want int)
- func ExpectN[T any](t testing.TB, description string, got []T, want ...T)
- func ExpectNoReceive[T any](t testing.TB, description string, ch <-chan T)
- func ExpectQueryResult[T comparable](t testing.TB, description string, want T, q xsql.Querier, query string, ...)
- func ExpectToReceiveN[T any](t testing.TB, description string, got <-chan T, want ...T)
- func Go(t testing.TB, fn func(ctx context.Context)) func()
- func GoE(t testing.TB, fn func(ctx context.Context) error) func()
- func NewDatabase(t testing.TB) *sql.DB
- func NewDatabaseWithFailingQueries(t testing.TB, fail func(query string, args []any) bool) *sql.DB
- func NewDatabaseWithoutSchema(t testing.TB) *sql.DB
- func PopulateEventStreams(t testing.TB, x xsql.Executor, ...) []*uuidpb.UUID
- func PostponeStreamConsumption(t testing.TB, x xsql.Executor, handlerKey string, streamID *uuidpb.UUID)
- func RunEngines(t *testing.T, fn func(testing.TB, *Cluster, *sql.DB), ...)
- func RunEnginesWithDB(t *testing.T, db *sql.DB, fn func(testing.TB, *Cluster, *sql.DB), ...)
- func SetupThenRunEngines(t *testing.T, setup func(testing.TB, *sql.DB), ...)
- func Transact(t testing.TB, db *sql.DB, fn func(*sql.Tx))
- func WaitFor(t testing.TB, description string, cond func() bool)
- func WaitForCommandToBePostponed(t testing.TB, q xsql.Querier, messageID *uuidpb.UUID)
- func WaitForCommandToBeRemovedFromQueue(t testing.TB, q xsql.Querier, messageID *uuidpb.UUID)
- func WaitForEmptyCommandQueue(t testing.TB, q xsql.Querier)
- func WaitForHandlerToConsumeAllEvents(t testing.TB, q xsql.Querier, handlerKey string)
- func WaitForHandlerToPostponeConsumingStream(t testing.TB, q xsql.Querier, handlerKey string, streamID *uuidpb.UUID)
- func WaitForLatches(t testing.TB, latches ...*cosyne.Latch)
- func WaitForNoPendingDeadlines(t testing.TB, q xsql.Querier)
- func WaitForObservable[T any](t testing.TB, description string, o cosyne.ObservableR[T], ok func(T) bool)
- func WaitForProcessHandlerInitialization(t testing.TB, db *sql.DB, handlerKey string)
- func WaitForQueryResult[T comparable](t testing.TB, description string, want T, q xsql.Querier, query string, ...)
- func WaitForStreamFailureCounter(t testing.TB, q xsql.Querier, handlerKey string, min uint64, ...)
- func WaitForStreamFailureCounterToReset(t testing.TB, q xsql.Querier, handlerKey string, streamIDs ...*uuidpb.UUID)
- type Cluster
Constants ¶
const ProjectionCompactInterval = 10 * time.Millisecond
ProjectionCompactInterval is the projection compaction interval configured on engines started by RunEngines and related functions.
Variables ¶
var WaitTimeout = 10 * time.Second
WaitTimeout is the maximum amount of time that the helpers in this package wait for a condition to be met before failing the test.
It is longer under CI, where tests run under heavier load.
Functions ¶
func AppendToEventStream ¶
func AppendToEventStream( t testing.TB, x xsql.Executor, streamID *uuidpb.UUID, events ...dogma.Event, ) []*envelopepb.Envelope
AppendToEventStream appends events to an existing event stream.
The returned envelopes have the envelopepb.EventStreamPosition extension set, as they would when read back from the stream.
func AppendToNewEventStream ¶ added in v0.2.0
func AppendToNewEventStream( t testing.TB, x xsql.Executor, events ...dogma.Event, ) (*uuidpb.UUID, []*envelopepb.Envelope)
AppendToNewEventStream creates a new event stream and appends the given events to it.
func ContextWithManualDeadline ¶ added in v0.2.0
ContextWithManualDeadline returns a context that has a deadline, and a function that makes the context behave as though that deadline had just passed. The deadline is never reached otherwise.
It allows a test to verify the behavior of an operation when its deadline passes, without depending on the wall clock.
func CreateEventStream ¶ added in v0.2.0
CreateEventStream creates a new event stream and returns its ID.
func CreateEventStreams ¶
CreateEventStreams creates the given number of event streams.
func DialGRPC ¶ added in v0.2.0
DialGRPC returns an insecure gRPC client connection to the given engines, which must be listening for gRPC requests.
The connection sends requests to the first of the engines, and moves to the next, in the order given, if that engine stops. It is closed when the test ends.
func DialGRPCAddr ¶ added in v0.2.0
func DialGRPCAddr( t testing.TB, target string, options ...grpc.DialOption, ) *grpc.ClientConn
DialGRPCAddr returns an insecure gRPC client connection to the given target, which is usually the address of a gRPC server. The options are applied after the defaults, so they may override them.
It is closed when the test ends.
func EnqueuePostponedCommand ¶
func EnqueuePostponedCommand( t testing.TB, x xsql.Executor, command dogma.Command, ) *envelopepb.Envelope
EnqueuePostponedCommand inserts a command directly into the command queue with deliver_at set far in the future, so it will not be picked up by the dequeue loop. It returns the envelope of the enqueued command.
func ExecOne ¶
ExecOne executes the given query and fails the test if it returns an error or does not affect exactly one row.
func ExecuteCommand ¶
func ExecuteCommand( t testing.TB, executor dogma.CommandExecutor, command dogma.Command, options ...dogma.ExecuteCommandOption, ) *envelopepb.Envelope
ExecuteCommand executes the given command using the executor, and fails the test if it returns an error.
func ExecuteCommandAndWait ¶
func ExecuteCommandAndWait( t testing.TB, executor dogma.CommandExecutor, db *sql.DB, command dogma.Command, options ...dogma.ExecuteCommandOption, ) *envelopepb.Envelope
ExecuteCommandAndWait executes the given command using the executor and waits for it to be removed from the command queue.
func ExecuteCommandWithHook ¶
func ExecuteCommandWithHook( t testing.TB, executor dogma.CommandExecutor, command dogma.Command, hook func(contexthook.ExecuteCommand), options ...dogma.ExecuteCommandOption, ) *envelopepb.Envelope
ExecuteCommandWithHook executes the given command using the executor, and fails the test if it returns an error.
func ExecuteCommandsSequentially ¶
func ExecuteCommandsSequentially( t testing.TB, executor dogma.CommandExecutor, db *sql.DB, commands ...dogma.Command, ) []*envelopepb.Envelope
ExecuteCommandsSequentially executes the given commands using the executor sequentially, and fails the test if any of them returns an error.
func ExpectCommandIDToBeQueued ¶
ExpectCommandIDToBeQueued asserts that the command with the given ID is present in the queue.
func ExpectCommandToBeQueued ¶
ExpectCommandToBeQueued asserts that the command queue contains the given command.
func ExpectCommandToBeUnattempted ¶
ExpectCommandToBeUnattempted asserts that the command with the given ID is present in the queue and has never been attempted (failures = 0).
func ExpectContiguousEvents ¶
func ExpectContiguousEvents( t testing.TB, q xsql.Querier, streamID *uuidpb.UUID, offset uint64, want ...dogma.Event, )
ExpectContiguousEvents asserts that an event stream contains the given events, starting at the given offset, with no gaps.
func ExpectEventCount ¶
ExpectEventCount asserts that the total number of events in the database matches the given value.
func ExpectNoReceive ¶ added in v0.2.0
ExpectNoReceive asserts that nothing is received on the channel within a short period.
func ExpectQueryResult ¶
func ExpectQueryResult[T comparable]( t testing.TB, description string, want T, q xsql.Querier, query string, args ...any, )
ExpectQueryResult executes a database query and fails the test if it does not produce a row with the wanted value in the first column.
func ExpectToReceiveN ¶ added in v0.2.0
ExpectToReceiveN asserts that a channel receives the values in the want slice, in order.
func Go ¶ added in v0.2.0
Go runs the given function in a goroutine until the test ends.
It returns a function that can be called to stop the goroutine early, which blocks until fn returns.
func GoE ¶ added in v0.2.0
GoE runs the given function in a goroutine until the test ends.
If fn returns an error before the goroutine is stopped or the test ends, the test fails. An error returned while the test is ending is ignored, as fn may fail because something it depends on has already stopped.
It returns a function that can be called to stop the goroutine early, which blocks until fn returns.
func NewDatabase ¶
NewDatabase returns a database pool that connects to an isolated test database that has the engine's schema DDL applied.
The database is removed when the test ends.
func NewDatabaseWithFailingQueries ¶ added in v0.2.0
func NewDatabaseWithFailingQueries( t testing.TB, fail func(query string, args []any) bool, ) *sql.DB
NewDatabaseWithFailingQueries returns a database pool like NewDatabase, except that each query for which the given function returns true fails without being sent to the database.
The function is called with the SQL and arguments of every query, including those that apply the schema.
func NewDatabaseWithoutSchema ¶
NewDatabaseWithoutSchema returns a database pool that connects to an isolated test database that does not have the engine's schema DDL applied.
The database is removed when the test ends.
func PopulateEventStreams ¶
func PopulateEventStreams( t testing.TB, x xsql.Executor, fn func(streamID *uuidpb.UUID, offset uint64) dogma.Event, counts ...uint64, ) []*uuidpb.UUID
PopulateEventStreams creates event streams and populates them with events generated by the given function.
Each element of counts specifies the number of events to append to one stream, so the number of streams created equals len(counts). Events are distributed by cycling through the streams, appending one event at a time to each in turn.
It returns the stream IDs that were created.
func PostponeStreamConsumption ¶
func PostponeStreamConsumption( t testing.TB, x xsql.Executor, handlerKey string, streamID *uuidpb.UUID, )
PostponeStreamConsumption inserts a handler_checkpoints row with resume_at set 24 hours in the future, preventing the handler from consuming the stream.
func RunEngines ¶
func RunEngines( t *testing.T, fn func( testing.TB, *Cluster, *sql.DB, ), routes ...dogma.HandlerRoute, )
RunEngines runs the given Dogma application on a cluster of nodes, and executes the given function while the cluster is running.
Multiple nodes are run to ensure that behavior is consistent when multiple engines run against the same database. fn receives the Cluster, which executes each command on a node chosen at random.
If any of the nodes stop before fn returns, the context passed to fn is canceled, and the test fails.
func RunEnginesWithDB ¶
func RunEnginesWithDB( t *testing.T, db *sql.DB, fn func(testing.TB, *Cluster, *sql.DB), routes ...dogma.HandlerRoute, )
RunEnginesWithDB is like RunEngines but uses the given database instead of creating one.
Unlike RunEngines and SetupThenRunEngines, it does not call t.Parallel().
func SetupThenRunEngines ¶
func SetupThenRunEngines( t *testing.T, setup func(testing.TB, *sql.DB), fn func(testing.TB, *Cluster, *sql.DB), routes ...dogma.HandlerRoute, )
SetupThenRunEngines is like RunEngines but accepts a setup function that receives the test database before any engines start.
func Transact ¶
Transact executes the given function within a database transaction, and fails the test if it returns an error.
func WaitFor ¶ added in v0.2.0
WaitFor polls cond until it returns true. It fails the test if that does not occur within WaitTimeout.
func WaitForCommandToBePostponed ¶
WaitForCommandToBePostponed waits until the command with the given ID has been postponed. If this does not occur within WaitTimeout, the test fails.
func WaitForCommandToBeRemovedFromQueue ¶
WaitForCommandToBeRemovedFromQueue waits until the command with the given ID is removed from the queue. If this does not occur within WaitTimeout, the test fails.
func WaitForEmptyCommandQueue ¶
WaitForEmptyCommandQueue waits until the command queue is empty. If this does not occur within WaitTimeout, the test fails.
func WaitForHandlerToConsumeAllEvents ¶
WaitForHandlerToConsumeAllEvents waits until the handler with the given key has caught up to the tail of all non-empty event streams. If this does not occur within WaitTimeout, the test fails.
It assumes that all events on all streams are of types that the handler consumes. If that is not the case this assertion will hang until it times out.
func WaitForHandlerToPostponeConsumingStream ¶
func WaitForHandlerToPostponeConsumingStream( t testing.TB, q xsql.Querier, handlerKey string, streamID *uuidpb.UUID, )
WaitForHandlerToPostponeConsumingStream waits until the handler with the given key has postponed consuming events from the given stream.
func WaitForLatches ¶ added in v0.2.0
WaitForLatches waits for all of the given latches to be set. It fails the test if all latches are not set within WaitTimeout.
func WaitForNoPendingDeadlines ¶
WaitForNoPendingDeadlines waits until there are no pending deadlines. If this does not occur within WaitTimeout, the test fails.
func WaitForObservable ¶ added in v0.2.0
func WaitForObservable[T any]( t testing.TB, description string, o cosyne.ObservableR[T], ok func(T) bool, )
WaitForObservable waits until the value of o satisfies ok. It fails the test if that does not occur within WaitTimeout, and reports the most recent value.
func WaitForProcessHandlerInitialization ¶
WaitForProcessHandlerInitialization waits until the given process message handler has been fully initialized.
func WaitForQueryResult ¶
func WaitForQueryResult[T comparable]( t testing.TB, description string, want T, q xsql.Querier, query string, args ...any, )
WaitForQueryResult executes a database query repeatedly until it produces a row with the wanted value in the first column. If this does not occur within WaitTimeout, the test fails.
An error from the query does not fail the test until the timeout, as it may be transient. If the timeout is reached, the most recent error is reported.
func WaitForStreamFailureCounter ¶
func WaitForStreamFailureCounter( t testing.TB, q xsql.Querier, handlerKey string, min uint64, streamIDs ...*uuidpb.UUID, )
WaitForStreamFailureCounter waits until the handler with the given key has its failures counter reach (or exceed) the given value on each of the given streams.
func WaitForStreamFailureCounterToReset ¶
func WaitForStreamFailureCounterToReset( t testing.TB, q xsql.Querier, handlerKey string, streamIDs ...*uuidpb.UUID, )
WaitForStreamFailureCounterToReset waits until the handler with the given key has its failures counter reset to zero for each of the given streams.
Types ¶
type Cluster ¶ added in v0.2.0
type Cluster struct {
// contains filtered or unexported fields
}
Cluster is a set of nodes that run the same application against the same database, which together form a single logical engine.
It implements dogma.CommandExecutor by executing each command on one of its running nodes, chosen at random.
It must only be used from the test's goroutine.
func StartCluster ¶ added in v0.2.0
func StartCluster( t testing.TB, db *sql.DB, app dogma.Application, n int, options ...runkit.EngineOption, ) *Cluster
StartCluster runs app against db on n nodes, and waits for them to converge into a cluster.
Each node's engine listens for gRPC requests on a random port of the loopback interface. The options are applied after the defaults, so they may override them.
The nodes run until they are stopped by Cluster.StopNode or Cluster.Stop, or the test ends. If any node stops before then, the test fails.
func (*Cluster) AddNode ¶ added in v0.2.0
AddNode starts another node in the cluster, and waits for every node to see all of the others. It returns the new node's engine.
func (*Cluster) ExecuteCommand ¶ added in v0.2.0
func (c *Cluster) ExecuteCommand( ctx context.Context, command dogma.Command, options ...dogma.ExecuteCommandOption, ) error
ExecuteCommand executes a command on one of the cluster's running nodes, chosen at random.
func (*Cluster) Failed ¶ added in v0.2.0
func (c *Cluster) Failed() <-chan struct{}
Failed returns a channel that is closed if any node stops other than by Cluster.StopNode or Cluster.Stop.
func (*Cluster) Nodes ¶ added in v0.2.0
Nodes returns the engines running on the cluster's current nodes, in no particular order.