conformance

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

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

func RunAll(t *testing.T, b Backend)

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

func RunBlob(t *testing.T, b Backend)

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

func RunRelational(t *testing.T, b Backend)

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.

func BlobCases

func BlobCases() []BlobCase

BlobCases is the shared byte-plane case table.

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.

type SeedAsset

type SeedAsset struct {
	Name, Kind, Serial, SiteID string
}

SeedAsset is one asset to create before a relational case runs. Ids are minted by the command path; cases address rows by Name.

Jump to

Keyboard shortcuts

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