zoobzio December 8, 2025 Edit this page

Testing Package Reference

Complete reference for github.com/zoobz-io/capitan/testing. For usage patterns and testing strategies, see the Testing Guide.

import capitantesting "github.com/zoobz-io/capitan/testing"

EventCapture

Captures events for testing and verification.

NewEventCapture

func NewEventCapture() *EventCapture

Creates a new capture instance.

Handler

func (ec *EventCapture) Handler() capitan.EventCallback

Returns a callback for use with Hook or Observe.

Events

func (ec *EventCapture) Events() []CapturedEvent

Returns all captured events as a defensive copy.

Count

func (ec *EventCapture) Count() int

Returns the number of captured events.

Reset

func (ec *EventCapture) Reset()

Clears all captured events.

WaitForCount

func (ec *EventCapture) WaitForCount(n int, timeout time.Duration) bool

Blocks until the capture has at least n events or timeout expires. Returns true if count was reached.

CapturedEvent

Snapshot of captured event data:

type CapturedEvent struct {
    Signal    capitan.Signal
    Timestamp time.Time
    Severity  capitan.Severity
    Fields    []capitan.Field
}

Example

func TestEmission(t *testing.T) {
    c := capitan.New(capitan.WithSyncMode())
    defer c.Shutdown()

    capture := capitantesting.NewEventCapture()
    c.Hook(orderCreated, capture.Handler())

    c.Emit(context.Background(), orderCreated, orderID.Field("ORD-123"))

    events := capture.Events()
    if len(events) != 1 {
        t.Fatalf("expected 1 event, got %d", len(events))
    }

    id := orderID.ExtractFromFields(events[0].Fields)
    if id != "ORD-123" {
        t.Errorf("expected ORD-123, got %s", id)
    }
}

EventCounter

Counts events without storing them.

NewEventCounter

func NewEventCounter() *EventCounter

Creates a new counter instance.

Handler

func (ec *EventCounter) Handler() capitan.EventCallback

Returns a callback for use with Hook or Observe.

Count

func (ec *EventCounter) Count() int64

Returns the current count.

Reset

func (ec *EventCounter) Reset()

Resets the count to zero.

WaitForCount

func (ec *EventCounter) WaitForCount(n int64, timeout time.Duration) bool

Blocks until count reaches n or timeout expires. Returns true if count was reached.

Example

func TestBulkEmission(t *testing.T) {
    c := capitan.New(capitan.WithSyncMode())
    defer c.Shutdown()

    counter := capitantesting.NewEventCounter()
    c.Hook(signal, counter.Handler())

    for i := 0; i < 1000; i++ {
        c.Emit(context.Background(), signal)
    }

    if counter.Count() != 1000 {
        t.Errorf("expected 1000, got %d", counter.Count())
    }
}

PanicRecorder

Records panics from listeners.

NewPanicRecorder

func NewPanicRecorder() *PanicRecorder

Creates a new recorder instance.

Handler

func (pr *PanicRecorder) Handler() func(capitan.Signal, any)

Returns a panic handler for use with WithPanicHandler.

Panics

func (pr *PanicRecorder) Panics() []PanicRecord

Returns all recorded panics as a defensive copy.

Count

func (pr *PanicRecorder) Count() int

Returns the number of recorded panics.

Reset

func (pr *PanicRecorder) Reset()

Clears all recorded panics.

PanicRecord

type PanicRecord struct {
    Signal    capitan.Signal
    Recovered any
    Timestamp time.Time
}

Example

func TestPanicRecovery(t *testing.T) {
    recorder := capitantesting.NewPanicRecorder()
    c := capitan.New(
        capitan.WithSyncMode(),
        capitan.WithPanicHandler(recorder.Handler()),
    )
    defer c.Shutdown()

    c.Hook(signal, func(ctx context.Context, e *capitan.Event) {
        panic("test panic")
    })

    c.Emit(context.Background(), signal)

    panics := recorder.Panics()
    if len(panics) != 1 {
        t.Fatalf("expected 1 panic, got %d", len(panics))
    }
    if panics[0].Recovered != "test panic" {
        t.Errorf("wrong panic value: %v", panics[0].Recovered)
    }
}

StatsWaiter

Polls stats until conditions are met.

NewStatsWaiter

func NewStatsWaiter(c *capitan.Capitan) *StatsWaiter

Creates a waiter for the given instance.

WaitForWorkers

func (sw *StatsWaiter) WaitForWorkers(n int, timeout time.Duration) bool

Blocks until at least n workers are active or timeout expires.

WaitForEmptyQueues

func (sw *StatsWaiter) WaitForEmptyQueues(timeout time.Duration) bool

Blocks until all signal queues are empty or timeout expires.

WaitForEmitCount

func (sw *StatsWaiter) WaitForEmitCount(signal capitan.Signal, n uint64, timeout time.Duration) bool

Blocks until the signal's emit count reaches n or timeout expires.

Example

func TestAsyncProcessing(t *testing.T) {
    c := capitan.New() // async mode
    defer c.Shutdown()

    waiter := capitantesting.NewStatsWaiter(c)

    c.Hook(signal, func(ctx context.Context, e *capitan.Event) {})
    c.Emit(context.Background(), signal)

    if !waiter.WaitForWorkers(1, time.Second) {
        t.Fatal("worker not created")
    }

    if !waiter.WaitForEmptyQueues(time.Second) {
        t.Fatal("queue not drained")
    }
}

FieldExtractor

Utility for extracting typed values from events.

NewFieldExtractor

func NewFieldExtractor() *FieldExtractor

Creates a new extractor.

GetString

func (fe *FieldExtractor) GetString(e *capitan.Event, key capitan.StringKey) string

Extracts a string value. Returns empty string if missing.

GetInt

func (fe *FieldExtractor) GetInt(e *capitan.Event, key capitan.IntKey) int

Extracts an int value. Returns zero if missing.

GetBool

func (fe *FieldExtractor) GetBool(e *capitan.Event, key capitan.BoolKey) bool

Extracts a bool value. Returns false if missing.

GetFloat64

func (fe *FieldExtractor) GetFloat64(e *capitan.Event, key capitan.Float64Key) float64

Extracts a float64 value. Returns zero if missing.

TestCapitan

TestCapitan

func TestCapitan(opts ...capitan.Option) *capitan.Capitan

Creates an instance for testing. Equivalent to capitan.New(opts...) but communicates test intent.