Documentation
¶
Overview ¶
Package storetest provides a reusable Protocol-driven contract test suite for session.Store implementations. Each backend (mem, postgres) supplies a Factory and runs Run with the same Protocol; the suite derives test cases from Protocol.RevokeOn() and Protocol.Fingerprint() so every backend is proved to honor the same protocol decisions (ADR-Session §4.3).
Helpers (NewTestProtocol / NewSessionFixture) are exported so future PG store integration tests in S3+S5 reuse the same fixture surface; the path runtime/auth/session/storetest/ is in the SESSION-PROTOCOL-COMPOSITION-ROOT-01 archtest allowlist so calls to session.NewProtocol from this package are permitted.
All test backends share NewTestProtocol so they prove parity on the same protocol decisions; backends differ only in their Factory implementation.
Index ¶
- func Bench(b *testing.B, factory BenchFactory)
- func EpochAnchor() time.Time
- func NewBenchProtocol(b *testing.B) *session.Protocol
- func NewSessionFixture(t *testing.T, subjectID, jti string, epoch int64, ttl time.Duration, ...) *session.Session
- func NewTestProtocol(t *testing.T) *session.Protocol
- func Run(t *testing.T, factory Factory, protocol *session.Protocol)
- type BenchFactory
- type Factory
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Bench ¶
func Bench(b *testing.B, factory BenchFactory)
Bench runs the canonical Session.Store benchmark suite against backend. MemStore and the PG-backed adapter share the same Bench so micro-benchmarks stay comparable across backends (PR #444 review carry-over — PR444-FU-SESSIONSTORE-BENCH-01). Mirrors the real-world hot paths:
BenchmarkRevokeForSubject_1000 — credential-event revoke fan-out BenchmarkMixedConcurrent — login/validate/logout interleave
The Protocol is constructed inside factory (e.g. via NewBenchProtocol), so Bench itself does not need a protocol parameter.
func EpochAnchor ¶
EpochAnchor returns the deterministic clock anchor used by storetest cases; backends constructing FakeClock from outside the suite (per-test setup hooks) should use this exact value so case timestamps line up.
func NewBenchProtocol ¶
NewBenchProtocol mirrors NewTestProtocol but takes *testing.B so callers inside Benchmark functions can construct the canonical S2 protocol shape without forking testing.TB. The returned *Protocol is identical in shape to NewTestProtocol(t).
func NewSessionFixture ¶
func NewSessionFixture(t *testing.T, subjectID, jti string, epoch int64, ttl time.Duration, now time.Time) *session.Session
NewSessionFixture constructs a Session with deterministic timestamps derived from now + ttl. Callers control SubjectID / JTI explicitly so cases can assert RevokeForSubject scoping precisely. ID is derived from JTI to keep cases readable (Session.ID is opaque to the protocol).
The epoch parameter is persisted as AuthzEpochAtIssue (S4d: row-level credential provenance; storetest conformance T-S4D-1 requires it non-zero so Create does not reject the fixture). Existing call sites that pass caseEpoch (7) continue to work; zero would trigger ErrValidationFailed.
func NewTestProtocol ¶
NewTestProtocol constructs the canonical S2 protocol shape: jti-only fingerprint (D1) + AuthzEpoch ordering (D2) + all 4 CredentialEvent values declared (D3 fail-closed). This call routes through session.NewProtocol; the archtest SESSION-PROTOCOL-COMPOSITION-ROOT-01 allowlist must include runtime/auth/session/storetest/ for this to compile-link cleanly.
func Run ¶
Run executes the Protocol-driven contract suite against factory. The suite runs the always-on cases unconditionally and derives one case per declared CredentialEvent in protocol.RevokeOn(). Fingerprint shape conformance keys off the runtime type of protocol.Fingerprint().
The suite calls Revoke bare. A Factory whose Store narrows Revoke with an ambient-transaction precondition — e.g. a cache decorator that registers a post-commit eviction hook, per the session.Store.Revoke contract — must return a Store that supplies the unit-of-work scope, as adapters/redis's txScopedRevokeStore conformance bridge does.
Types ¶
type BenchFactory ¶
type BenchFactory func(b *testing.B) (store session.Store, fakeClock *clockmock.FakeClock, cleanup func())
BenchFactory mirrors Factory but takes *testing.B so backend setup can use b.Fatal / b.Helper. Implementations must return:
- a fresh session.Store
- a *clockmock.FakeClock pinned at EpochAnchor() (Bench reads now from it)
- a cleanup func that is safe to call exactly once
type Factory ¶
type Factory func(t *testing.T) (store session.Store, fakeClock *clockmock.FakeClock, cleanup func())
Factory constructs a fresh Store with a deterministic clock. Backends with per-test setup (e.g. PG schema reset) do it inside Factory; cleanup is the returned func and must be safe to call exactly once.
The fakeClock return type is the concrete *clockmock.FakeClock rather than the clock.Clock interface — suite cases call fc.Advance() and fc.Now() directly, methods that only the concrete type carries. PG store factories in S3+S5 must therefore also construct and return *clockmock.FakeClock, even when wiring it through the store as a clock.Clock at construction.