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 ¶
- func Run(t *testing.T, newDriver func(t *testing.T) (push.Driver, push.Recipient))
- type Fake
- func (fake *Fake) AssertNotSent(t testing.TB, predicates ...func(Submission) bool)
- func (fake *Fake) AssertNothingSent(t testing.TB)
- func (fake *Fake) AssertSent(t testing.TB, predicates ...func(Submission) bool)
- func (fake *Fake) AssertSentCount(t testing.TB, count int)
- func (fake *Fake) FailNext(err error)
- func (fake *Fake) FailWith(err error)
- func (fake *Fake) Reset()
- func (fake *Fake) Send(ctx context.Context, message push.Message, config push.SendConfig) (push.Receipt, error)
- func (fake *Fake) Sent() []Submission
- type Submission
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Run ¶
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 ¶
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 ¶
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 ¶
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 ¶
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() }
}