auditcoretest

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package auditcoretest provides testutil helpers for the auditcore Cell.

Purpose

Journey and integration tests need to drive the auditcore subscription seam (the auditappendsession EntryHandler registered during cell.Init) without going through broker delivery and without importing internal packages from cells/auditcore/internal/. This package exports the wiring that the integration tests previously duplicated inline, making it reusable across criterion test files.

Import scope

auditcoretest is a sibling package inside the cells/auditcore subtree. It may import cells/auditcore/* (including internal sub-packages) because Go's internal-package rule only restricts packages *outside* the parent tree. Production code must never import auditcoretest; the CELLTEST-IMPORT-SCOPE-01 archtest auto-discovers this package form and enforces that constraint.

Relationship to cells/auditcore/cell.go

BuildAuditcoreChain wires the same options as the production composition root (clock as the first positional parameter to NewAuditCore, then WithLedgerProtocol, WithLedgerStore, WithEmitter, WithTxManager, WithMetricsProvider, WithLogger) and then calls c.Init to trigger subscription registration — mirroring what bootstrap phase3 does in production. The resulting handler is the exact same outbox.EntryHandler that a broker delivery loop would invoke.

Usage

handler, store, ctx := auditcoretest.BuildAuditcoreChain(t)
entry := auditcoretest.NewSessionCreatedEntry("sess-1", "usr-1")
result := handler(ctx, entry)
// result.Disposition == outbox.DispositionAck
// store.Tail(ctx) has one entry

Debug Logging

By default the logger is discarded. To redirect logs to stderr during local investigation:

handler, store, ctx := auditcoretest.BuildAuditcoreChain(t,
    auditcoretest.WithChainLogger(slog.New(slog.NewTextHandler(os.Stderr, nil))))

Why t.Fatalf Instead of testify/require

builders.go and canonical.go use t.Fatalf instead of testify/require because depguard blocks testify imports in non-_test.go files under cells/. The _test.go suffix is the boundary at which testify imports are allowed.

Future Criterion Reuse

When the J-auditlogintrail http.audit.list.v1 criterion lands, reuse this chain by driving multiple NewSessionCreatedEntry(...) calls and querying store via Tail/Query/Verify.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildAuditcoreChain

func BuildAuditcoreChain(t *testing.T, opts ...BuildChainOption) (
	handler outbox.EntryHandler,
	store ledger.Store,
	ctx context.Context,
)

BuildAuditcoreChain wires a docker-free auditcore Cell and returns the bound EntryHandler for the event.session.created.v1 subscription, the in-memory ledger.Store (for Tail/Verify assertions), and a background context.

Protocol construction is delegated to storetest.NewTestProtocol, the single allowlisted entry for ledger.NewProtocol outside cmd/* composition roots (AUDIT-LEDGER-PROTOCOL-COMPOSITION-ROOT-01). The protocol shape is:

  • HMAC-SHA256 key (storetest-supplied test key)
  • ledger.ParseNamespaceID("auditcore")
  • RestartRecoveryStrictTailVerify + IdempotencyContentFingerprint

After proto, the wiring continues:

  • ledger.NewMemStore(proto, clock)
  • auditcore.NewAuditCore with all required options
  • c.Init via cell.NewRegistryRecorder(DurabilityDemo)
  • findSubscriptionHandler for "event.session.created.v1"

The entry factory is separated into NewSessionCreatedEntry so callers can drive multiple different entries through one chain (e.g., to test multi-entry hash chains or idempotency rejection on duplicate EventID).

func NewSessionCreatedEntry

func NewSessionCreatedEntry(sessionID, userID string) outbox.Entry

NewSessionCreatedEntry constructs an outbox.Entry with an event.session.created.v1 payload that satisfies the auditappendsession actor-acceptance rules (userId present, payload is a valid JSON object).

The entry ID format is "evt-{sessionID}" — each test scenario gets a unique ID by varying sessionID, preventing idempotency rejection when driving multiple entries through one chain. This diverges from PR #588's fixed literal "evt-j-auditlogintrail" so that multi-entry chain tests remain valid.

createdAt/occurredAt are stamped by outbox.NewEntry from clock.Real() at call time; the ledger MemStore assigns its own store-level Timestamp from the injected clock, so the entry times are informational only for test assertions. The deterministic ID "evt-{sessionID}" is pinned via outbox.WithID so each scenario gets a unique idempotency key.

ref: contracts/event/session/created/v1/payload.schema.json (sessionId + userId required). ref: cells/accesscore/internal/dto/session_events.go SessionCreatedEvent (same field names).

Types

type BuildChainOption

type BuildChainOption func(*buildChainConfig)

BuildChainOption configures BuildAuditcoreChain.

func WithChainClock

func WithChainClock(c clock.Clock) BuildChainOption

WithChainClock overrides the clock injected into the auditcore Cell and MemStore. Defaults to clock.Real().

func WithChainLogger

func WithChainLogger(l *slog.Logger) BuildChainOption

WithChainLogger overrides the logger injected into the auditcore Cell. Defaults to slog.New(slog.DiscardHandler) so test output stays clean.

Jump to

Keyboard shortcuts

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