testkit

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Aug 16, 2026 License: MPL-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var StdSizes = []NamedSize{
	{"1MB", 1 * 1024 * 1024},
	{"10MB", 10 * 1024 * 1024},
	{"100MB", 100 * 1024 * 1024},
	{"1GB", 1024 * 1024 * 1024},
}

StdSizes is the size ladder repeated by 6 of the 10 size tables in tests/benchmark_test.go. Match a table by its ladder, not by line number.

The other four are deliberately NOT covered. They measure different things and keep their own ladders:

  • 10MB, 100MB, 600MB netem profiles
  • 1KB to 1GB, seven steps chunk-size sweep
  • 1KB, 10KB, 100KB, 1MB mount latency
  • a {name, count, size} triple multi-file write

Names must stay exactly as written. Subtest names depend on them.

Do not mutate it. A caller that writes `sizes := testkit.StdSizes` shares the backing array with every other test in the binary. Copy it first if a test needs its own ladder.

Functions

func DiscardLogger

func DiscardLogger() *slog.Logger

DiscardLogger drops all output. It replaces the inline slog.New(slog.NewTextHandler(io.Discard, nil)) construction. slog defaults to LevelInfo when the options are nil, so this is unchanged behaviour for those sites.

func Eventually

func Eventually(t testing.TB, timeout, interval time.Duration, cond func() bool, what string)

Eventually fails the test if cond does not become true inside timeout.

func Go

func Go(fn func() error) func() error

Go starts fn and returns a join function. Call the join function to wait for fn and get its error. The join function has the shape func() error, so it composes into fp.All with no wrapper.

func GoN

func GoN(n int, fn func(i int) error) func() error

GoN runs fn for i in [0,n) and returns a join function. The join function drains every result before it returns, so no goroutine leaks when one of them fails early. It reports the first error by index.

func Logger

func Logger(w io.Writer, level slog.Level) *slog.Logger

Logger returns a text logger that writes to w at the given level. It is the general form. Use it when a test must keep its output, for example an integration test that logs warnings to stdout for a human to read after a failure. Replacing such a logger with DiscardLogger loses that output.

func Must

func Must[T any](v T, err error) T

Must returns v, or aborts the enclosing Run with err.

ln := testkit.Must(quic.ListenAddr("127.0.0.1:0", cfg, nil))

Must takes no *testing.T on purpose. The Go spec allows a multi-value call to fill an argument list only when that call is the sole argument, so Must(t, f()) is not valid Go. Dropping t makes Must(f()) legal and lets T infer, including the two-value form.

Call Must only inside a Run body. Run turns the abort into an ordinary test failure. Outside Run the panic escapes and ends the test binary.

func Must2

func Must2[A, B any](a A, b B, err error) (A, B)

Must2 is Must for a call that returns two values and an error.

func Poll

func Poll(timeout, interval time.Duration, cond func() bool, what string) error

Poll waits for cond, or reports a timeout. It returns error, so it composes with fp.All and is safe off the test goroutine, where t.Fatal is a Go bug.

func RandBytes

func RandBytes(t testing.TB, n int) []byte

RandBytes returns n cryptographically random bytes.

func Run

func Run(t *testing.T, body func() error)

Run joins the error-returning code to testify. This is the only point that observes a test failure. Put the whole test body inside it, so Must is safe everywhere in the test.

func RunTable

func RunTable[C any](t *testing.T, cases []C, name func(C) string, body func(*testing.T, C) error)

RunTable runs one subtest per case. name supplies the subtest name, so a conversion keeps the original names. body returns an error, so a case composes with fp.All.

func StdoutLogger

func StdoutLogger(level slog.Level) *slog.Logger

StdoutLogger writes to stdout at the given level. The integration tests use this to keep warnings and errors visible.

func Within

func Within(d time.Duration, what string, body func() error) error

Within runs body and reports an error if body does not return inside d. It replaces the hand-rolled shape that starts a goroutine, reports through a bool channel and races a time.After.

A panic in body becomes an error, so Must is safe inside body. A bare goroutine cannot do this: only the goroutine that panics can recover it, so a Must in a plain go func ends the test binary instead of failing the test.

After a timeout body keeps running. Do not call t.Error or t.Fatal in body. A late call panics after the test ends. Return an error instead.

func WithinCtx

func WithinCtx(ctx context.Context, what string, body func() error) error

WithinCtx runs body and reports an error if body does not return before ctx ends. Use it where the deadline is held by a context and is shared by more than one wait. Within starts a new duration at each call, so it gives each wait its own budget, which is a different test.

A panic in body becomes an error, the same as Within. The same rule applies after a timeout: body keeps running, so return an error from it, never t.Error.

Types

type NamedSize

type NamedSize struct {
	Name string
	Size int
}

NamedSize is the shape of the size table repeated across the benchmarks.

type Stream

type Stream[Req any, Resp any] struct {
	// Requests are returned by Recv in order, then io.EOF.
	Requests []Req
	// Sent records every message passed to Send.
	Sent []Resp

	// SendErr, when set, is returned by Send instead of recording.
	SendErr error
	// RecvErr, when set, is returned by Recv instead of the next request.
	RecvErr error
	// Ctx overrides the stream context. Nil means context.Background.
	Ctx context.Context
	// contains filtered or unexported fields
}

Stream is a generic server stream stub. Req is the received message type, Resp the sent one. Both are concrete at every instantiation, so no cast is needed at a call site.

The existing hand-written stubs do not embed grpc.ServerStream. They implement the six methods directly, which avoids a nil-interface panic when the code under test calls one. This type does the same.

For a send-only RPC, instantiate Req as struct{}. The extra Recv method is harmless.

func (*Stream[Req, Resp]) Context

func (s *Stream[Req, Resp]) Context() context.Context

func (*Stream[Req, Resp]) Recv

func (s *Stream[Req, Resp]) Recv() (Req, error)

func (*Stream[Req, Resp]) RecvMsg

func (s *Stream[Req, Resp]) RecvMsg(any) error

func (*Stream[Req, Resp]) Send

func (s *Stream[Req, Resp]) Send(resp Resp) error

func (*Stream[Req, Resp]) SendHeader

func (s *Stream[Req, Resp]) SendHeader(metadata.MD) error

func (*Stream[Req, Resp]) SendMsg

func (s *Stream[Req, Resp]) SendMsg(any) error

func (*Stream[Req, Resp]) SetHeader

func (s *Stream[Req, Resp]) SetHeader(metadata.MD) error

The remaining methods satisfy grpc.ServerStream. SendMsg and RecvMsg take any because the gRPC interface requires it. This is the one place the no-any-as-a-value-type rule does not apply.

func (*Stream[Req, Resp]) SetTrailer

func (s *Stream[Req, Resp]) SetTrailer(metadata.MD)

Jump to

Keyboard shortcuts

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