Conformance Suite¶
providertest verifies that a sender behaves like every other omnimail
provider. Adapters run it in their own unit tests against a fake provider
endpoint; no credentials or network access are needed.
Harness¶
type Harness interface {
Sender() omnimail.Sender // sender wired to the fake endpoint
Captured(t testing.TB) []*omnimail.Message // what the endpoint accepted since Reset
Reset() // clear captures and pending failures
InjectFailure(kind omnimail.Kind) bool // make the next send fail like the provider would
}
Captured returns the messages as the provider received them, decoded back
into omnimail.Message:
- Raw-MIME providers decode with
providertest.DecodeMIME(raw, envelopeRecipients). Envelope recipients not in To/Cc become Bcc; custom headers land inHeaders(a transmittedBccheader shows up there, so leaks fail the suite). - Structured-API providers build the message from the request fields.
- Fill
TagsandIdempotencyKeyfrom the request when the provider transmits them.
InjectFailure should produce the provider's native failure (an SMTP reply
code, an HTTP status and error code) so the adapter's real classification
code runs. Return false for kinds the fake cannot simulate; those checks are
skipped.
Config¶
| Field | Meaning |
|---|---|
Harness |
Required |
Provider |
Expected SendResult.Provider and Error.Provider (empty skips) |
From |
Sender used in test messages (default no-reply@example.com) |
SupportsTags |
Assert tags reach the provider |
SupportsIdempotencyKey |
Assert the idempotency key reaches the provider |
SupportsSMTPUTF8 |
Assert internationalized addresses are delivered |
SkipCustomHeaders |
Skip the custom header check |
Timeout |
Per-send timeout (default 10s) |
Checks¶
| Check | Verifies |
|---|---|
SendResult |
non-nil result, non-empty MessageID, expected Provider |
TextOnly, HTMLOnly, TextAndHTML |
bodies arrive intact (line endings normalized) and nothing extra is added |
Addressing |
multiple To/Cc with display names, Bcc delivered but not in headers, Bcc-only messages |
ReplyTo |
Reply-To transmitted |
UnicodeHeaders |
non-ASCII subject, display names and body |
CustomHeaders |
custom headers transmitted (unless skipped) |
Tags, IdempotencyKey |
accepted always; transmitted when supported |
InternationalAddress |
SMTPUTF8 addresses (when supported) |
DoesNotMutateMessage |
Send leaves the caller's message unchanged |
InvalidMessage |
missing recipients/body, header injection, bad address, reserved header and nil are rejected with ErrInvalidMessage before reaching the endpoint |
ContextCanceled |
canceled context returns context.Canceled, not retryable, nothing sent |
ErrorClassification |
each injected failure maps to the right Kind, Provider and IsRetryable; failures do not persist |
ConcurrentSends |
parallel sends all arrive |
Examples in This Repository¶
providertest/providertest_test.goruns the suite againstmemsender.smtp/smtp_test.goruns it against the SMTP sender over STARTTLS and implicit TLS with the in-processsmtptestserver, mapping each kind to an SMTP reply (550 5.1.1, 554 5.7.1, 450 4.7.0, 451 4.3.0, 535 5.7.8).