Documentation
¶
Overview ¶
Package testutil provides shared test helpers and realistic fixtures for the gramaton test suite. Import this package in any *_test.go file to get access to engine setup, record builders, and a pre-populated store with ~50 records.
Index ¶
- func AssertDirMode(t *testing.T, path string, want os.FileMode)
- func AssertFileMode(t *testing.T, path string, want os.FileMode)
- func Edge(t *testing.T, eng *core.Engine, sourceID, targetID, edgeType string, ...)
- func EdgeDirect(eng *core.Engine, sourceID, targetID, edgeType string, weight float64)
- func NewEngine(t *testing.T) *core.Engine
- func RegisterEngineCleanup(t *testing.T, eng *core.Engine)
- func Timeout(base time.Duration) time.Duration
- type PopulatedStore
- type RecordBuilder
- func (b *RecordBuilder) AccessCount(n int64) *RecordBuilder
- func (b *RecordBuilder) Add(t *testing.T, eng *core.Engine) string
- func (b *RecordBuilder) AddDirect(eng *core.Engine) string
- func (b *RecordBuilder) Confidence(v float64) *RecordBuilder
- func (b *RecordBuilder) CreatedAt(t time.Time) *RecordBuilder
- func (b *RecordBuilder) Embedding(vec []float32) *RecordBuilder
- func (b *RecordBuilder) EpistemicStatus(v string) *RecordBuilder
- func (b *RecordBuilder) Importance(v float64) *RecordBuilder
- func (b *RecordBuilder) Keywords(kw ...string) *RecordBuilder
- func (b *RecordBuilder) KnowledgeType(v string) *RecordBuilder
- func (b *RecordBuilder) LastAccessed(t time.Time) *RecordBuilder
- func (b *RecordBuilder) Pending() *RecordBuilder
- func (b *RecordBuilder) Resolution(v string) *RecordBuilder
- func (b *RecordBuilder) ResolvedAt(t time.Time) *RecordBuilder
- func (b *RecordBuilder) SourceRef(v string) *RecordBuilder
- func (b *RecordBuilder) Summary(v string) *RecordBuilder
- func (b *RecordBuilder) Temporality(v string) *RecordBuilder
- func (b *RecordBuilder) ValidUntil(t time.Time) *RecordBuilder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AssertDirMode ¶
AssertDirMode is AssertFileMode for directories. Same Windows caveat: the mode-bit assertion is skipped on Windows but the path is verified to exist and to be a directory.
func AssertFileMode ¶
AssertFileMode verifies a regular file's mode matches `want` on POSIX systems. On Windows the mode-bit assertion is skipped (Windows reports a fixed 0o666 / 0o444 based on the read-only flag and does not honor full POSIX mode bits) but the file's existence + non-directory-ness is still verified so callers retain a basic correctness check.
Use this in place of direct `info.Mode().Perm() != 0o600` checks when the test runs on every platform.
func EdgeDirect ¶
EdgeDirect creates an edge without requiring *testing.T.
func NewEngine ¶
NewEngine creates a minimal engine backed by a temp directory. No embedding or LLM providers configured.
func RegisterEngineCleanup ¶
RegisterEngineCleanup attaches a t.Cleanup that calls eng.Close before the test's TempDir auto-cleanup runs. Required for any test that constructs an engine via core.LoadEngineWithOptions on a directory created by t.TempDir: without this, the engine's bbolt file handles outlive the test and Windows refuses to unlink them (POSIX inode semantics paper over the leak on Linux/macOS).
t.Cleanup runs LIFO -- registering this AFTER t.TempDir's auto- cleanup means engine.Close fires FIRST, draining bbolt handles before RemoveAll.
engine.Close is idempotent. Errors during close are surfaced via t.Logf rather than t.Errorf so a teardown hiccup doesn't fail an otherwise-healthy test.
func Timeout ¶
Timeout scales a base test timeout for the host platform. Windows runners (especially under race detector) are 3-5x slower than Linux or macOS for I/O-heavy paths, and many of our async tests use short hard-coded timeouts (1-5s) that cleanly fit POSIX timing but fail on Windows CI through no fault of the code under test.
Use this when a test waits on an event with a deadline:
pollUntilTerminal(t, a, jobID, testutil.Timeout(5*time.Second))
On Linux/macOS this returns base unchanged. On Windows it returns 5 * base. We initially used 3x but observed multiple legitimate flakes at the 30s/45s boundary (chunkNumBlocker waitParked, blockingInjector waitEntered, TestConcurrentReadsAndWrites under race). 5x is the documented upper end of "Windows under race can be 3-5x slower in practice"; the 1.5x buffer over realistic max gives genuine deadlocks ~50s to surface (still well under any per-package go-test budget).
Types ¶
type PopulatedStore ¶
type PopulatedStore struct {
// Work cluster (6 records)
WorkReorg string // episodic: team restructured
WorkNewManager string // episodic: new manager started
WorkDeadline string // temporal: project due date
WorkMeeting string // procedural: meeting cadence
WorkOldTool string // historical, superseded: old project tool
WorkNewTool string // durable: new project tool (supersedes old)
// Health cluster (6 records)
HealthDoctorVisit string // episodic: annual checkup notes
HealthExercise string // procedural: exercise routine
HealthAllergy string // immutable: allergy info
HealthSleep string // semantic: sleep discovery
HealthSupplement string // refuted: supplement claim
HealthPrescription string // temporal: prescription reminder
// Cooking cluster (5 records)
CookingRecipe string // procedural: favorite recipe
CookingSubstitution string // semantic: ingredient substitution
CookingDinnerParty string // episodic: dinner party menu
CookingDietary string // durable: dietary constraint
CookingTechnique string // procedural: technique tip
// Travel cluster (5 records)
TravelSeat string // immutable: flight seat preference
TravelPacking string // procedural: packing list
TravelTrip string // ephemeral: upcoming trip
TravelLoyalty string // durable: loyalty program info
TravelPassport string // temporal: passport renewal deadline
// Finance cluster (4 records)
FinanceBudget string // procedural: budget rule
FinanceExpense string // procedural: expense process
FinanceTax string // temporal: tax deadline
FinanceInvestment string // speculative: investment idea
// Learning cluster (4 records)
LearnBook string // reference: book recommendation
LearnCourse string // episodic: course notes
LearnRetention string // semantic: spaced repetition
LearnContested string // contested: study technique
// People (4 records)
PersonVendor string // temporal: vendor contact
PersonNeighbor string // durable: neighbor info
PersonBirthday string // durable: friend's birthday
PersonDoctor string // durable: doctor recommendation
// TODOs (5 records)
TodoOpen string // unresolved, high importance
TodoCompleted string // resolved: completed
TodoAbandoned string // resolved: abandoned
TodoObsolete string // resolved: obsolete
TodoOpenLow string // unresolved, low importance
// Orphans (4 records) -- no keywords, no edges
Orphan1 string
Orphan2 string
Orphan3 string
Orphan4 string
// Pending (3 records) -- unclassified
Pending1 string
Pending2 string
Pending3 string
// Ephemeral/stale (3 records)
EphemeralRecent string // created today
EphemeralStale string // created 2 weeks ago, never accessed
EphemeralMeeting string // yesterday's meeting agenda
// Chunked (1 parent + 3 chunks)
ChunkedParent string
Chunk1 string
Chunk2 string
Chunk3 string
}
PopulatedStore is the set of record IDs from a pre-populated engine. Fields are grouped by category for easy access in tests.
func PopulatedEngine ¶
func PopulatedEngine(t *testing.T) (*core.Engine, *PopulatedStore)
PopulatedEngine creates a new engine pre-loaded with ~50 realistic records covering every axis: all temporalities, knowledge types, epistemic statuses, resolution states, edge types, orphans, pending records, chunks, and multiple keyword clusters for concept emergence.
All timestamps are deterministic relative to now, so tests don't flake. Embeddings use simple deterministic vectors grouped by cluster.
type RecordBuilder ¶
type RecordBuilder struct {
// contains filtered or unexported fields
}
RecordBuilder constructs a graph node with a fluent API.
func Record ¶
func Record(content string) *RecordBuilder
Record starts building a new record with the given content.
func (*RecordBuilder) AccessCount ¶
func (b *RecordBuilder) AccessCount(n int64) *RecordBuilder
func (*RecordBuilder) Add ¶
Add inserts the record into the engine and returns its ID. Acquires and releases the write lock.
func (*RecordBuilder) AddDirect ¶
func (b *RecordBuilder) AddDirect(eng *core.Engine) string
AddDirect inserts the record without requiring *testing.T. Use in TestMain or other contexts where *testing.T is unavailable.
func (*RecordBuilder) Confidence ¶
func (b *RecordBuilder) Confidence(v float64) *RecordBuilder
func (*RecordBuilder) CreatedAt ¶
func (b *RecordBuilder) CreatedAt(t time.Time) *RecordBuilder
func (*RecordBuilder) Embedding ¶
func (b *RecordBuilder) Embedding(vec []float32) *RecordBuilder
func (*RecordBuilder) EpistemicStatus ¶
func (b *RecordBuilder) EpistemicStatus(v string) *RecordBuilder
func (*RecordBuilder) Importance ¶
func (b *RecordBuilder) Importance(v float64) *RecordBuilder
func (*RecordBuilder) Keywords ¶
func (b *RecordBuilder) Keywords(kw ...string) *RecordBuilder
func (*RecordBuilder) KnowledgeType ¶
func (b *RecordBuilder) KnowledgeType(v string) *RecordBuilder
func (*RecordBuilder) LastAccessed ¶
func (b *RecordBuilder) LastAccessed(t time.Time) *RecordBuilder
func (*RecordBuilder) Pending ¶
func (b *RecordBuilder) Pending() *RecordBuilder
func (*RecordBuilder) Resolution ¶
func (b *RecordBuilder) Resolution(v string) *RecordBuilder
func (*RecordBuilder) ResolvedAt ¶
func (b *RecordBuilder) ResolvedAt(t time.Time) *RecordBuilder
func (*RecordBuilder) SourceRef ¶
func (b *RecordBuilder) SourceRef(v string) *RecordBuilder
func (*RecordBuilder) Summary ¶
func (b *RecordBuilder) Summary(v string) *RecordBuilder
func (*RecordBuilder) Temporality ¶
func (b *RecordBuilder) Temporality(v string) *RecordBuilder
func (*RecordBuilder) ValidUntil ¶
func (b *RecordBuilder) ValidUntil(t time.Time) *RecordBuilder