testutil

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Index

Constants

View Source
const TestHMACSecret = "test-hmac-secret-for-testing"

Variables

This section is empty.

Functions

func NewEventsAPIHarness

func NewEventsAPIHarness(t *testing.T, pool *pgxpool.Pool, store *identity.Store, outbox webhookpub.Outbox) *httptest.Server

NewEventsAPIHarness spins up a minimal httptest server with the agent.API wired for the slice 6/7 events API. The non-/v1 mux surface (OAuth, magic-link pages, health, etc.) is wrapped by the typed /v1 chi root (the same apiserver builder prod + TestServer use), so the e2e events tests hit the real /v1 handlers for events, webhooks, and agents.

Returns the *httptest.Server; caller must Close() on cleanup.

func OpenPreparedTestDB

func OpenPreparedTestDB(ctx context.Context, dbURL string) (*pgxpool.Pool, error)

func TestDB

func TestDB(t *testing.T) *pgxpool.Pool

func TestDBURL

func TestDBURL() string

func TruncateAll

func TruncateAll(t *testing.T, pool *pgxpool.Pool)

Types

type ContractServer

type ContractServer struct {
	BaseURL  string
	APIKey   string
	UserID   string
	DBPool   *pgxpool.Pool
	Store    *identity.Store
	WSHub    *ws.Hub
	SMTPAddr string
	// contains filtered or unexported fields
}

func StartContractServer

func StartContractServer(ctx context.Context, dbURL string) (*ContractServer, error)

func (*ContractServer) Close

func (s *ContractServer) Close(ctx context.Context) error

type E2ATestServer

type E2ATestServer struct {
	HTTPServer *httptest.Server
	SMTPAddr   string
	Store      *identity.Store
	WSHub      *ws.Hub

	// Webhooks-as-a-resource wiring (post-PR-180), now on the outbox + River
	// delivery path. The outbox is wired into both the agent API (so /send etc.
	// fire email.sent) and the SMTP server (so inbound mail fires email.received),
	// committing events to webhook_events. SubscriberStore lets tests insert /
	// inspect delivery rows. DrainAndDeliver() drives the outbox drain + River
	// DeliverWorker synchronously so tests get deterministic delivery without
	// waiting on any production tick.
	SubscriberStore *webhook.SubscriberStore
	// contains filtered or unexported fields
}

func TestServer

func TestServer(t *testing.T, pool *pgxpool.Pool, opts ...TestServerOption) *E2ATestServer

func (*E2ATestServer) DrainAndDeliver

func (ts *E2ATestServer) DrainAndDeliver(ctx context.Context)

DrainAndDeliver runs the outbox drain (webhook_events → webhook_subscriber_deliveries) then the River DeliverWorker over every pending delivery row, synchronously. It is the test-side replacement for the retired SubscriberRetryWorker.Tick — production drains via the OutboxWorker's LISTEN/ poll loop and River's queue; tests drive both stages by hand for determinism. Per-row Work errors (retryable failures are expected in some tests, e.g. a 503 receiver) are ignored so one failing subscriber doesn't stop the rest.

func (*E2ATestServer) StartJobs

func (ts *E2ATestServer) StartJobs(t *testing.T, ctx context.Context)

StartJobs starts the shared River client for a server built with WithManualJobs, releasing every queued job to its worker. Idempotent, and a no-op on a server whose client is already running. Pair it with a bounded poll on the state the worker produces (e.g. provider_message_id becoming non-empty) rather than a sleep.

type ReceivedPayload

type ReceivedPayload struct {
	Body    webhook.Payload
	Headers http.Header
	RawBody []byte
}

type SMTPAddr

type SMTPAddr struct {
	Host string
	Port int
}

SMTPAddr holds parsed host and port for a fake SMTP server.

func FakeSMTPServer

func FakeSMTPServer(t *testing.T) (SMTPAddr, func() []SMTPMessage)

FakeSMTPServer starts a minimal SMTP server that accepts messages. Returns the address and a function to call to stop the server and get received messages.

type SMTPMessage

type SMTPMessage struct {
	From       string
	To         string   // first RCPT TO (backward compat)
	Recipients []string // all RCPT TO addresses
	Data       string
}

SMTPMessage represents a message received by the fake SMTP server.

type SubscriberCaptured

type SubscriberCaptured struct {
	URL      string
	Envelope map[string]any
	RawBody  []byte
	Headers  http.Header
}

SubscriberCaptured is one POST the SubscriberReceiver caught. The envelope is the parsed JSON body ({event, id, created_at, data}) and RawBody is the verbatim bytes — useful for HMAC verification, which signs `t.body` and must use the exact bytes the worker POSTed.

type SubscriberReceiverResult

type SubscriberReceiverResult struct {
	Server *httptest.Server
	// contains filtered or unexported fields
}

SubscriberReceiverResult is a multi-path receiver for the new webhooks-as-a-resource path. Distinct from WebhookReceiverResult (which decodes the legacy webhook.Payload shape) because the new envelope is {event, id, created_at, data} and we need raw bytes for signature verification.

func SubscriberReceiver

func SubscriberReceiver(t *testing.T) *SubscriberReceiverResult

SubscriberReceiver returns a multi-path HTTP receiver wired for the new webhook-resource envelope. Routes work as plain paths under the receiver's base URL — e.g. receiver.Server.URL + "/sent" + ".../fail".

func (*SubscriberReceiverResult) Captured

func (*SubscriberReceiverResult) Reset

func (s *SubscriberReceiverResult) Reset()

Reset clears captured payloads. Useful between phases of a long test so per-phase assertions don't see prior posts.

func (*SubscriberReceiverResult) SetStatus

func (s *SubscriberReceiverResult) SetStatus(path string, code int)

SetStatus pins a non-200 response for the given path. Used by the auto-disable test to force the worker into the failure path.

func (*SubscriberReceiverResult) WaitFor

func (s *SubscriberReceiverResult) WaitFor(t *testing.T, timeout time.Duration, predicate func([]SubscriberCaptured) bool) []SubscriberCaptured

WaitFor polls until predicate returns true or the timeout expires. Returns the captured list at the moment predicate first matched (or the last seen list on timeout). Tests typically call Tick(ctx) on the worker once then WaitFor(..., 0) for an immediate check; the timeout exists for cases where the publisher may still be in flight.

type TestServerOption

type TestServerOption func(*testServerOpts)

func WithInboundAuthentication

func WithInboundAuthentication(authentication *emailauth.Authentication) TestServerOption

WithInboundAuthentication injects deterministic SMTP authentication evidence. It lets integration tests cover DMARC-pass policy paths without relying on mutable public DNS.

func WithManualJobs

func WithManualJobs() TestServerOption

WithManualJobs builds the shared River client but does NOT start it, so no queue is worked until the test calls StartJobs. Enqueue still works (an InsertTx is just a row), so an accepted send durably lands its outbound_send job and then SITS there — which is how a test pins the accept→submit window (delivery_status='accepted', provider_message_id still empty) with no sleeps and no race: an unstarted client has no producers, so the worker CANNOT run. Default (unset) keeps the production-shaped behavior every other test relies on: the client is started and drains the queue on its own.

func WithOutboundSMTP

func WithOutboundSMTP(host string, port int, fromDomain string) TestServerOption

WithOutboundSMTP wires an upstream relay for /send + HITL approve paths so they don't error with "outbound SMTP relay not configured". Tests that don't trigger outbound omit this. Pointing at Mailpit on localhost:1025 (started via `make docker-up`) is the typical pattern.

func WithOutboundSMTPMessageIDDomain

func WithOutboundSMTPMessageIDDomain(domain string) TestServerOption

WithOutboundSMTPMessageIDDomain sets the provider Message-ID domain the relay appends to bare ids from the 250 response (config message_id_domain). Tests dial the relay at 127.0.0.1, so the SES-host derivation can never fire — this override is how a test exercises the qualification path the way production does against a real email-smtp.<region>.amazonaws.com host.

type WebhookReceiverResult

type WebhookReceiverResult struct {
	Server *httptest.Server
	// contains filtered or unexported fields
}

func WebhookReceiver

func WebhookReceiver(t *testing.T) *WebhookReceiverResult

func (*WebhookReceiverResult) Payloads

func (w *WebhookReceiverResult) Payloads() []ReceivedPayload

func (*WebhookReceiverResult) WaitForPayloads

func (w *WebhookReceiverResult) WaitForPayloads(t *testing.T, count int, timeout time.Duration) []ReceivedPayload

Jump to

Keyboard shortcuts

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