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. Each port is probed before calling its suite so one unimplemented port does not halt the others via a suite-level t.Skip. Follow-on plans add RunGraph, RunSearch, 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
// EmbeddingDim is the dimension required by the vector store.
// 0 means "no fixed dimension" (the fake accepts any size; RunVector uses
// 3-dimensional test vectors). Set to 768 for the postgres backend, which
// enforces the schema-declared vector(768) column.
EmbeddingDim int
}
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.