tests/integration/find-*.test.ts and tests/unit/brainy/find*.test.ts each opened one or more Brainy instances (via beforeAll/beforeEach) and never closed them — the leaked instance's cadence timer stays armed for the rest of the single-forked vitest run and keeps narrating into every later file. find-unified-integration.test.ts was a real bug, not just a missing hook: its afterAll called a no-op TestCleanup().cleanup() (nothing was ever registered with it) and then discarded the brain reference with `brain = null` — the brain was never actually closed.
141 lines
5.3 KiB
TypeScript
141 lines
5.3 KiB
TypeScript
/**
|
|
* @module tests/integration/find-planner-door
|
|
* @description The optional `MetadataIndexProvider.planFindPage` door.
|
|
*
|
|
* The stage doors each serve one stage, so a `find()` that consults three of
|
|
* them crosses into the index three times and marshals a result set at every
|
|
* crossing — a filter matching a hundred thousand rows builds a hundred
|
|
* thousand id strings to return a page of twenty-five. An index that can decide
|
|
* the stage order itself answers the page in one call.
|
|
*
|
|
* These pins hold the three properties that make such a door safe to add:
|
|
*
|
|
* 1. **Absent, nothing changes.** The reference index has no planner, and every
|
|
* find is served by the stage doors exactly as before. That is also what
|
|
* makes this engine the ordering oracle for any index that implements one.
|
|
* 2. **Present, it is asked first and its answer is used** — above the branch
|
|
* selection, with the params already normalized, the hidden ids passed, and
|
|
* the graph provider handed over.
|
|
* 3. **`null` is routing, not an answer.** A door that declines a shape leaves
|
|
* it to the path that always served it, and the result is unchanged.
|
|
*
|
|
* Plus the serving law: an empty page stamped `emptyAt: 'graph'` is re-verified
|
|
* against the adjacency before it is believed, so a not-serving graph refuses
|
|
* loudly instead of answering `[]` as truth.
|
|
*/
|
|
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'
|
|
import { Brainy } from '../../src/brainy'
|
|
import { NounType, VerbType } from '../../src/types/graphTypes'
|
|
import { generateTestVector } from '../helpers/test-factory'
|
|
|
|
describe('find(): the optional planner door', () => {
|
|
let brain: Brainy<any>
|
|
const anchor = 'planner-anchor'
|
|
let neighbourId = ''
|
|
|
|
beforeAll(async () => {
|
|
brain = new Brainy({ requireSubtype: false, storage: { type: 'memory' } })
|
|
await brain.init()
|
|
await brain.add({
|
|
id: anchor,
|
|
data: 'anchor',
|
|
type: NounType.Person,
|
|
metadata: { kind: 'anchor' },
|
|
vector: generateTestVector()
|
|
})
|
|
for (let i = 0; i < 12; i++) {
|
|
const id = await brain.add({
|
|
id: `row-${i}`,
|
|
data: `row ${i}`,
|
|
type: NounType.Person,
|
|
metadata: { kind: 'note', rank: i },
|
|
vector: generateTestVector()
|
|
})
|
|
if (i === 0) neighbourId = id
|
|
await brain.relate({ from: anchor, to: id, type: VerbType.Knows })
|
|
}
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await brain.close()
|
|
})
|
|
|
|
/** Install a planner door for one call, then remove it. */
|
|
const withDoor = async <T>(
|
|
door: (...a: any[]) => Promise<any>,
|
|
body: () => Promise<T>
|
|
): Promise<T> => {
|
|
const index = (brain as any).metadataIndex
|
|
index.planFindPage = door
|
|
try {
|
|
return await body()
|
|
} finally {
|
|
delete index.planFindPage
|
|
}
|
|
}
|
|
|
|
it('is absent on the reference index — every find is served by the stage doors', async () => {
|
|
expect((brain as any).metadataIndex.planFindPage).toBeUndefined()
|
|
const results = await brain.find({ where: { kind: 'note' }, limit: 5 })
|
|
expect(results).toHaveLength(5)
|
|
})
|
|
|
|
it('is asked before the branches, with normalized params and the graph provider', async () => {
|
|
const door = vi.fn(async () => null)
|
|
await withDoor(door, async () => {
|
|
await brain.find({ where: { kind: 'note' }, limit: 5 })
|
|
})
|
|
expect(door).toHaveBeenCalledTimes(1)
|
|
const [params, hidden, graph] = door.mock.calls[0] as any[]
|
|
expect(params.where).toEqual({ kind: 'note' })
|
|
expect(Array.isArray(hidden)).toBe(true)
|
|
expect(graph).toBe((brain as any).graphIndex)
|
|
})
|
|
|
|
it('uses the page it answers, hydrated and in the door\'s order', async () => {
|
|
const results = await withDoor(
|
|
async () => ({ ids: [neighbourId], emptyAt: 'none' as const }),
|
|
async () => brain.find({ where: { kind: 'note' }, limit: 5 })
|
|
)
|
|
expect(results).toHaveLength(1)
|
|
expect(results[0].entity.id).toBe(neighbourId)
|
|
})
|
|
|
|
it('a declining door changes nothing — the shape is served as it always was', async () => {
|
|
const withoutDoor = await brain.find({ where: { kind: 'note' }, orderBy: 'rank', limit: 4 })
|
|
const declined = await withDoor(
|
|
async () => null,
|
|
async () => brain.find({ where: { kind: 'note' }, orderBy: 'rank', limit: 4 })
|
|
)
|
|
expect(declined.map((r) => r.entity.id)).toEqual(withoutDoor.map((r) => r.entity.id))
|
|
})
|
|
|
|
it('re-verifies the adjacency before believing an empty graph answer', async () => {
|
|
const verify = vi.spyOn(brain as any, 'verifyGraphAdjacencyLive')
|
|
try {
|
|
const results = await withDoor(
|
|
async () => ({ ids: [], emptyAt: 'graph' as const }),
|
|
async () => brain.find({ connected: { from: anchor }, where: { kind: 'note' }, limit: 5 })
|
|
)
|
|
expect(results).toEqual([])
|
|
expect(verify).toHaveBeenCalled()
|
|
} finally {
|
|
verify.mockRestore()
|
|
}
|
|
})
|
|
|
|
it('does not re-verify the adjacency for an empty the FILTER produced', async () => {
|
|
const verify = vi.spyOn(brain as any, 'verifyGraphAdjacencyLive')
|
|
verify.mockClear()
|
|
try {
|
|
const results = await withDoor(
|
|
async () => ({ ids: [], emptyAt: 'filter' as const }),
|
|
async () => brain.find({ where: { kind: 'note' }, limit: 5 })
|
|
)
|
|
expect(results).toEqual([])
|
|
expect(verify).not.toHaveBeenCalled()
|
|
} finally {
|
|
verify.mockRestore()
|
|
}
|
|
})
|
|
})
|