Help us shape the future of Go! Take the 2026 Go Developer Survey

pushtest

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package pushtest provides an outbound push fake and Driver conformance suite. Fake records accepted submissions, including resolved retention, without a delivery engine, network access, or lifecycle. It accepts both recipient variants after portable validation; real drivers may support only one.

fake := pushtest.New()
sender := push.New(fake)
_, err := sender.Send(ctx, push.NewMessage(push.Token("device-registration"), "Ready"))
if err != nil {
	return err
}
fake.AssertSent(t, func(submission pushtest.Submission) bool {
	return submission.Message.Title() == "Ready" && submission.Config.TTL == push.DefaultTTL
})

Run verifies portable direct-driver behavior with a valid driver-specific recipient supplied by each factory. It does not verify delivery, endpoint security, native error mapping, or provider retention encoding; those need focused driver tests. Factories must arrange successful backend acceptance.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run(t *testing.T, newDriver func(t *testing.T) (push.Driver, push.Recipient))

Run verifies portable direct-driver submission requirements. Each subtest gets a fresh ready driver and a valid recipient from newDriver; arrange any infrastructure cleanup with t.Cleanup. Receipts may legitimately have no ID. The suite checks validation, context errors, ownership, raw retention, and concurrency, not actual device delivery or provider-specific wire encoding.

Example:

func TestDriver(t *testing.T) {
	pushtest.Run(t, func(t *testing.T) (push.Driver, push.Recipient) {
		return pushtest.New(), push.Token("device-registration")
	})
}

Types

type Fake

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

Fake is a concurrency-safe push.Driver that records accepted submissions. It performs portable preflight before consuming injected failures and returns sequential acceptance IDs, not delivery confirmations. Its zero value works.

Example:

fake := pushtest.New()
_, err := push.New(fake).Send(ctx, push.NewMessage(push.Token("device-registration"), "Ready"))
if err != nil { return err }
fake.AssertSentCount(t, 1)
Example
package main

import (
	"context"
	"fmt"
	"time"

	"arkoren.dev/core/service/push"
	"arkoren.dev/core/service/push/pushtest"
)

func main() {
	fake := pushtest.New()
	sender := push.New(fake)

	_, err := sender.Send(context.Background(), push.NewMessage(push.Token("native"), "Ready"), push.TTL(time.Hour))

	if err != nil {
		fmt.Println("submission failed")

		return
	}

	for _, submission := range fake.Sent() {
		fmt.Println(submission.Message.Title(), submission.Config.TTL)
	}
}
Output:
Ready 1h0m0s

func New

func New() *Fake

New creates an empty Fake without I/O, delivery work, or retained callbacks. Failure injection and recordings are owned by this instance.

Example:

fake := pushtest.New()
fake.AssertNothingSent(t)

func (*Fake) AssertNotSent

func (fake *Fake) AssertNotSent(t testing.TB, predicates ...func(Submission) bool)

AssertNotSent reports failure if any accepted submission matches all predicates. Without predicates it requires no accepted submissions. Assertion diagnostics never print sensitive content or recipient values.

Example:

fake.AssertNotSent(t, func(submission pushtest.Submission) bool {
	return submission.Message.Title() == "Unexpected"
})

func (*Fake) AssertNothingSent

func (fake *Fake) AssertNothingSent(t testing.TB)

AssertNothingSent reports failure if any submission succeeded since creation or Reset. It checks acceptance only, not whether device delivery occurred.

Example:

fake.AssertNothingSent(t)

func (*Fake) AssertSent

func (fake *Fake) AssertSent(t testing.TB, predicates ...func(Submission) bool)

AssertSent reports failure unless one accepted submission matches all predicates. No predicates matches any submission; nil predicates panic. Predicates run on a snapshot outside the lock and may inspect the fake.

Example:

fake.AssertSent(t, func(submission pushtest.Submission) bool {
	return submission.Message.Title() == "Ready"
})

func (*Fake) AssertSentCount

func (fake *Fake) AssertSentCount(t testing.TB, count int)

AssertSentCount reports failure unless exactly count submissions succeeded. Rejections from preflight or failure injection do not contribute to the count.

Example:

fake.AssertSentCount(t, 2)

func (*Fake) FailNext

func (fake *Fake) FailNext(err error)

FailNext replaces the one-shot failure for the next valid Send. Nil clears it. One-shot failures take precedence over FailWith.

Example:

fake.FailNext(push.ErrUnavailable)

func (*Fake) FailWith

func (fake *Fake) FailWith(err error)

FailWith replaces the persistent error used by subsequent valid sends. Nil clears it; FailNext can temporarily override it without clearing it.

Example:

fake.FailWith(push.ErrRateLimited)
fake.FailWith(nil)

func (*Fake) Reset

func (fake *Fake) Reset()

Reset clears recorded submissions and both injected failures atomically. Subsequent acceptance IDs restart at fake-1; no device delivery is simulated.

Example:

fake.Reset()
fake.AssertNothingSent(t)

func (*Fake) Send

func (fake *Fake) Send(ctx context.Context, message push.Message, config push.SendConfig) (push.Receipt, error)

Send validates message, context, and raw policy, then records acceptance. Invalid input does not consume FailNext. Injected failures return unchanged with a zero receipt and are not recorded. No defaults or retries are applied.

Example:

_, err := fake.Send(ctx, push.NewMessage(push.Token("device-registration"), "Ready"), push.SendConfig{})
if err != nil { return err }
fake.AssertSent(t)

func (*Fake) Sent

func (fake *Fake) Sent() []Submission

Sent returns an independent slice in acceptance order, or nil when empty. Message values are immutable and their metadata getters clone; changing a returned record, Config, or inspected map cannot alter future snapshots.

Example:

for _, submission := range fake.Sent() { _ = submission.Config.TTL }

type Submission

type Submission struct {
	// Message is the accepted immutable declaration, never a live draft.
	// Its content is sensitive and is not printed by assertion failures.
	//
	// Example:
	//
	//	for _, submission := range fake.Sent() { _ = submission.Message.Title() }
	Message push.Message

	// Config is the exact raw policy received by Fake.Send, with no defaults.
	// Zero TTL records explicit no-store, not an omitted sender setting.
	//
	// Example:
	//
	//	for _, submission := range fake.Sent() { _ = submission.Config.TTL }
	Config push.SendConfig
}

Submission records an accepted immutable message and its resolved policy. Message inspection returns independent data; Config is a plain value.

Example:

for _, submission := range fake.Sent() {
	if submission.Config.TTL == 0 { _ = submission.Message.Title() }
}

Jump to

Keyboard shortcuts

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