Documentation
¶
Overview ¶
Package conformance is fabriq's cross-port conformance kit: one exported Case table per capability port, run against BOTH the in-memory fabriqtest fakes and the real adapters, so the fakes cannot silently drift from Postgres / FalkorDB / Elasticsearch truth.
The defining property is "drift becomes a failing test": if the fake's List ordering changes, or a real adapter's filter semantics diverge from the fake's, a conformance subtest goes red — at go-test speed for the fakes, under the integration build tag for the adapters.
Deliberate fake-vs-real divergences (the fake serializes transactions, stores raw time-series points only, has no relevance scorer, …) are encoded as Capability requirements on individual cases and gated through skip-or-assert-degraded logic. Every capability is justified in the reviewed ledger (ledger.go); introducing a new divergence is mechanically forced through a ledger edit.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RunAll ¶
RunAll runs every applicable port suite against b. Ports the backend does not implement (nil Env field) are skipped wholesale. Follow-on plans add RunGraph, RunSearch, RunVector, RunSpatial, RunTimeseries, RunCommandStore and RunProjectionState here.
func RunBlob ¶
RunBlob drives a backend through the byte-plane case table. Backends that do not wire Env.Blob are skipped; capability-gated cases skip when the backend lacks the capability.
func RunRelational ¶
RunRelational runs the relational conformance suite against b. It skips the whole suite when the backend does not implement the relational port, and gates each capability-requiring case via skip-or-assert-degrade.
Types ¶
type Backend ¶
type Backend interface {
// Name identifies the backend in subtest names and skip reasons, e.g.
// "fake", "postgres", "falkordb", "elasticsearch".
Name() string
// Capabilities are the behaviors this backend supports exactly.
Capabilities() CapabilitySet
// Setup returns a fresh, isolated environment for ONE case. The backend
// registers its own t.Cleanup. Isolation is by unique tenant; no
// truncation is required.
Setup(t *testing.T) *Env
}
Backend is one system-under-test: the fakes, or a real adapter set over a container. The conformance runner drives it through the shared Case tables.
type BlobCase ¶
type BlobCase struct {
Name string
Requires []Capability
Run func(t *testing.T, env *Env)
}
BlobCase is one byte-plane behavior, run identically against every backend that wires Env.Blob. Capability-gated cases skip when Requires is unmet.
type Capability ¶
type Capability string
Capability names a behavior a backend either supports exactly or legitimately diverges on. Cases that Require a capability the system-under-test lacks are skipped or asserted-degraded.
const ( // CapConcurrentTx: real optimistic-concurrency version conflicts (the // fake serializes transactions one at a time). CapConcurrentTx Capability = "concurrent-tx" // CapBucketedAgg: TimescaleDB time_bucket aggregation (the fake stores // raw points only). CapBucketedAgg Capability = "ts-bucketed-agg" // CapRelevanceScore: real full-text relevance ranking (the fake returns // id-order, having no scorer). CapRelevanceScore Capability = "search-relevance" // CapRawSQL: the relational raw-SQL escape hatch (the fake has no SQL // engine). CapRawSQL Capability = "raw-sql" // CapRawCypher: uncanned openCypher (the fake serves canned responses). CapRawCypher Capability = "raw-cypher" // CapPersistence: survives a reopen (the fakes are in-memory). CapPersistence Capability = "cross-restart" // CapBlobPresign: the byte store issues presigned client-direct URLs. CapBlobPresign Capability = "blob-presign" // CapBlobMultipart: the byte store supports resumable multipart uploads. CapBlobMultipart Capability = "blob-multipart" // CapBlobRange: the byte store supports byte-range reads. CapBlobRange Capability = "blob-range" )
type CapabilitySet ¶
type CapabilitySet map[Capability]bool
CapabilitySet is the set of capabilities a backend supports exactly.
func (CapabilitySet) Has ¶
func (c CapabilitySet) Has(want Capability) bool
Has reports whether the set contains want.
type Degradation ¶
type Degradation struct {
// ExpectErrIs requires errors.Is(err, ExpectErrIs).
ExpectErrIs error
// ExpectErrContains requires the error message to contain this substring.
ExpectErrContains string
}
Degradation describes what a backend lacking a case's required capability must return INSTEAD of the happy-path result. Set one of the two fields.
type Env ¶
type Env struct {
Ctx context.Context // unique primary tenant for this case
ForeignCtx context.Context // a second, distinct tenant over the same store
Registry *registry.Registry // domain.RegisterAll(reg)
Exec *command.Executor // write path; nil → command/store suite skips
Relational query.RelationalQuerier // nil → relational suite skips
Graph query.GraphQuerier
Search query.SearchQuerier
Vector query.VectorQuerier
Spatial query.SpatialQuerier
TS query.TSQuerier
Projection projection.StateReader
Blob blob.Store // nil → blob suite skips
GraphTarget string // fresh graph/projection target for this case
}
Env is one isolated case environment. A nil port field means "not implemented by this backend" — that port's whole suite is skipped.
type RelationalCase ¶
type RelationalCase struct {
Name string
Requires []Capability // capabilities the happy path needs
Degrade *Degradation // when a Required capability is absent, assert this instead of skipping
Seed []SeedAsset
// Run executes the read under test. ids maps SeedAsset.Name -> minted id.
Run func(env *Env, ids map[string]string) ([]*domain.Asset, error)
WantNames []string // expected asset Names, in order
}
RelationalCase is one conformance scenario for query.RelationalQuerier.
func RelationalCases ¶
func RelationalCases() []RelationalCase
RelationalCases is the canonical relational conformance table. Universal cases (no Requires) must pass on EVERY backend; capability-gated cases run where supported and skip/assert-degrade elsewhere.