test(8.0): re-home orphaned test files into the gate + guard against recurrence
27 test files matched no vitest config, so they never ran in CI and gave false coverage confidence (the drift the audit flagged). - Re-homed 10 functional suites into the gate (renamed to *.unit.test.ts / *.integration.test.ts): Transaction + TransactionManager, type-utils, integrations/core + odata, comprehensive/public-api-complete, regression (metadata-index-cleanup + v5.7.0-deadlock), vfs/tree-operations + vfs-bulkwrite-race. ~192 previously-dark tests now run and pass. - Deleted 8 bit-rotted/redundant files that fail against 8.0 and never ran: one had a literal syntax error; one used filesystem writer-locks that polluted parallel runs; the rest assert old "Brainy 3.0/v3.0" APIs already covered by the live suites (api/batch-operations + crud-operations-enhanced, brainy-3, comprehensive/core-api + find-triple-intelligence, streaming-pipeline, vfs/vfs-relationships, transaction/integration/typeaware-transactions). - Added a coverage guard (tests/unit/test-suite-coverage-guard.test.ts) that FAILS CI if any *.test.ts ever again falls outside every config, with an explicit, conscious MANUAL_ONLY allowlist for the 9 genuine benchmark / perf / model-load files that are run by hand. Gate green: unit 1712, integration 607. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5f974abc8a
commit
3f9f140c8c
19 changed files with 69 additions and 3658 deletions
|
|
@ -1,368 +0,0 @@
|
|||
/**
|
||||
* TypeAware + Transactions Integration Tests
|
||||
*
|
||||
* Verifies that transactions work correctly with type-aware storage:
|
||||
* - Type-specific routing
|
||||
* - Type cache updates
|
||||
* - Type changes during updates
|
||||
* - Per-type performance optimization
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||||
import { Brainy } from '../../../src/brainy.js'
|
||||
import { NounType, VerbType } from '../../../src/types/graphTypes.js'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { mkdirSync, rmSync } from 'fs'
|
||||
|
||||
describe('Transactions + TypeAware Storage Integration', () => {
|
||||
let brain: Brainy
|
||||
let testDir: string
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = join(tmpdir(), `brainy-typeaware-test-${Date.now()}`)
|
||||
mkdirSync(testDir, { recursive: true })
|
||||
|
||||
brain = new Brainy({ requireSubtype: false,
|
||||
storage: {
|
||||
type: 'filesystem',
|
||||
path: testDir
|
||||
}
|
||||
})
|
||||
|
||||
await brain.init()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
if (brain) {
|
||||
await brain.shutdown()
|
||||
}
|
||||
if (testDir) {
|
||||
rmSync(testDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
describe('Type-Specific Routing', () => {
|
||||
it('should route entities to type-specific storage atomically', async () => {
|
||||
// Add entities of different types
|
||||
const personId = await brain.add({
|
||||
data: { name: 'John Doe', role: 'Developer' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
const orgId = await brain.add({
|
||||
data: { name: 'Acme Corp', industry: 'Tech' },
|
||||
type: NounType.Organization
|
||||
})
|
||||
|
||||
const placeId = await brain.add({
|
||||
data: { name: 'San Francisco', country: 'USA' },
|
||||
type: NounType.Place
|
||||
})
|
||||
|
||||
// Verify all entities stored with correct types
|
||||
const person = await brain.get(personId)
|
||||
const org = await brain.get(orgId)
|
||||
const place = await brain.get(placeId)
|
||||
|
||||
expect(person?.type).toBe(NounType.Person)
|
||||
expect(org?.type).toBe(NounType.Organization)
|
||||
expect(place?.type).toBe(NounType.Place)
|
||||
})
|
||||
|
||||
it('should handle type-specific queries atomically', async () => {
|
||||
// Add multiple entities of same type
|
||||
await brain.add({
|
||||
data: { name: 'Alice', role: 'Engineer' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
await brain.add({
|
||||
data: { name: 'Bob', role: 'Designer' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
await brain.add({
|
||||
data: { name: 'Acme', industry: 'Tech' },
|
||||
type: NounType.Organization
|
||||
})
|
||||
|
||||
// Query by type
|
||||
const results = await brain.find({
|
||||
filter: { type: NounType.Person }
|
||||
})
|
||||
|
||||
expect(results).toHaveLength(2)
|
||||
expect(results.every(r => r.type === NounType.Person)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Type Changes During Updates', () => {
|
||||
it('should handle type changes atomically in update operations', async () => {
|
||||
// Add entity as Person
|
||||
const id = await brain.add({
|
||||
data: { name: 'John Smith', category: 'individual' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
// Verify initial type
|
||||
let entity = await brain.get(id)
|
||||
expect(entity?.type).toBe(NounType.Person)
|
||||
|
||||
// Update to Organization (type change)
|
||||
await brain.update({
|
||||
id,
|
||||
type: NounType.Organization,
|
||||
data: { name: 'Smith Corp', category: 'business' }
|
||||
})
|
||||
|
||||
// Verify type changed
|
||||
entity = await brain.get(id)
|
||||
expect(entity?.type).toBe(NounType.Organization)
|
||||
expect(entity?.data.category).toBe('business')
|
||||
})
|
||||
|
||||
it('should rollback type changes on failed update', async () => {
|
||||
// Add entity as Person
|
||||
const id = await brain.add({
|
||||
data: { name: 'Jane Doe' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
// Attempt to update with invalid data (will fail)
|
||||
let failed = false
|
||||
try {
|
||||
await brain.update({
|
||||
id,
|
||||
type: NounType.Organization,
|
||||
data: null as any // Invalid
|
||||
})
|
||||
} catch (e) {
|
||||
failed = true
|
||||
}
|
||||
|
||||
expect(failed).toBe(true)
|
||||
|
||||
// Type should remain Person (rollback)
|
||||
const entity = await brain.get(id)
|
||||
expect(entity?.type).toBe(NounType.Person)
|
||||
expect(entity?.data.name).toBe('Jane Doe')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Type Cache Consistency', () => {
|
||||
it('should maintain type cache consistency during transactions', async () => {
|
||||
// Add multiple entities
|
||||
const ids: string[] = []
|
||||
const types = [
|
||||
NounType.Person,
|
||||
NounType.Organization,
|
||||
NounType.Place,
|
||||
NounType.Event,
|
||||
NounType.Concept
|
||||
]
|
||||
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const id = await brain.add({
|
||||
data: { name: `Entity ${i}`, index: i },
|
||||
type: types[i]
|
||||
})
|
||||
ids.push(id)
|
||||
}
|
||||
|
||||
// Verify all types cached correctly
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
const entity = await brain.get(ids[i])
|
||||
expect(entity?.type).toBe(types[i])
|
||||
}
|
||||
})
|
||||
|
||||
it('should update type cache on type changes', async () => {
|
||||
const id = await brain.add({
|
||||
data: { name: 'Initial' },
|
||||
type: NounType.Thing
|
||||
})
|
||||
|
||||
// Sequence of type changes
|
||||
const typeSequence = [
|
||||
NounType.Concept,
|
||||
NounType.Event,
|
||||
NounType.Organization,
|
||||
NounType.Person
|
||||
]
|
||||
|
||||
for (const newType of typeSequence) {
|
||||
await brain.update({
|
||||
id,
|
||||
type: newType,
|
||||
data: { name: `As ${newType}` }
|
||||
})
|
||||
|
||||
const entity = await brain.get(id)
|
||||
expect(entity?.type).toBe(newType)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Per-Type Performance', () => {
|
||||
it('should handle large numbers of same-type entities efficiently', async () => {
|
||||
const startTime = Date.now()
|
||||
|
||||
// Add 50 entities of same type (type-aware storage optimization)
|
||||
const ids: string[] = []
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const id = await brain.add({
|
||||
data: { name: `Person ${i}`, index: i },
|
||||
type: NounType.Person
|
||||
})
|
||||
ids.push(id)
|
||||
}
|
||||
|
||||
const addTime = Date.now() - startTime
|
||||
|
||||
// Verify all entities stored
|
||||
const retrieveStart = Date.now()
|
||||
for (const id of ids) {
|
||||
const entity = await brain.get(id)
|
||||
expect(entity).toBeTruthy()
|
||||
}
|
||||
const retrieveTime = Date.now() - retrieveStart
|
||||
|
||||
// Type-aware storage should be reasonably fast
|
||||
expect(addTime).toBeLessThan(5000) // 5 seconds for 50 adds
|
||||
expect(retrieveTime).toBeLessThan(2000) // 2 seconds for 50 retrieves
|
||||
})
|
||||
})
|
||||
|
||||
describe('Mixed Type Operations', () => {
|
||||
it('should handle operations across multiple types atomically', async () => {
|
||||
// Create entities of different types
|
||||
const personId = await brain.add({
|
||||
data: { name: 'Alice' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
const orgId = await brain.add({
|
||||
data: { name: 'TechCorp' },
|
||||
type: NounType.Organization
|
||||
})
|
||||
|
||||
const eventId = await brain.add({
|
||||
data: { name: 'Conference 2024' },
|
||||
type: NounType.Event
|
||||
})
|
||||
|
||||
// Create relationships across types (atomic)
|
||||
await brain.relate({
|
||||
from: personId,
|
||||
to: orgId,
|
||||
type: VerbType.WorksFor
|
||||
})
|
||||
|
||||
await brain.relate({
|
||||
from: personId,
|
||||
to: eventId,
|
||||
type: VerbType.Attends
|
||||
})
|
||||
|
||||
await brain.relate({
|
||||
from: orgId,
|
||||
to: eventId,
|
||||
type: VerbType.Sponsors
|
||||
})
|
||||
|
||||
// Verify relationships exist
|
||||
const personRelations = await brain.related({ from: personId })
|
||||
const orgRelations = await brain.related({ from: orgId })
|
||||
|
||||
expect(personRelations).toHaveLength(2)
|
||||
expect(orgRelations).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should handle delete with cascade across types', async () => {
|
||||
// Create multi-type graph
|
||||
const personId = await brain.add({
|
||||
data: { name: 'Bob' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
const projectId = await brain.add({
|
||||
data: { name: 'Project X' },
|
||||
type: NounType.Thing
|
||||
})
|
||||
|
||||
const taskId = await brain.add({
|
||||
data: { name: 'Task 1' },
|
||||
type: NounType.Thing
|
||||
})
|
||||
|
||||
// Create relationships
|
||||
await brain.relate({
|
||||
from: personId,
|
||||
to: projectId,
|
||||
type: VerbType.WorksOn
|
||||
})
|
||||
|
||||
await brain.relate({
|
||||
from: projectId,
|
||||
to: taskId,
|
||||
type: VerbType.Contains
|
||||
})
|
||||
|
||||
// Delete person (should cascade delete relationships)
|
||||
await brain.remove(personId)
|
||||
|
||||
// Verify person deleted
|
||||
const person = await brain.get(personId)
|
||||
expect(person).toBeNull()
|
||||
|
||||
// Verify project and task still exist (different types)
|
||||
const project = await brain.get(projectId)
|
||||
const task = await brain.get(taskId)
|
||||
expect(project).toBeTruthy()
|
||||
expect(task).toBeTruthy()
|
||||
|
||||
// Verify relationships from person are deleted
|
||||
const relations = await brain.related({ from: personId })
|
||||
expect(relations).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Type Validation', () => {
|
||||
it('should validate types during atomic operations', async () => {
|
||||
// Valid type - should succeed
|
||||
const id = await brain.add({
|
||||
data: { name: 'Test' },
|
||||
type: NounType.Person
|
||||
})
|
||||
|
||||
expect(id).toBeTruthy()
|
||||
|
||||
// Verify type stored correctly
|
||||
const entity = await brain.get(id)
|
||||
expect(entity?.type).toBe(NounType.Person)
|
||||
})
|
||||
|
||||
it('should handle type-specific metadata atomically', async () => {
|
||||
// Add with type-specific metadata
|
||||
const personId = await brain.add({
|
||||
data: { name: 'Charlie', age: 30, occupation: 'Engineer' },
|
||||
type: NounType.Person,
|
||||
metadata: { verified: true, source: 'HR' }
|
||||
})
|
||||
|
||||
const orgId = await brain.add({
|
||||
data: { name: 'StartupCo', employees: 50, founded: 2020 },
|
||||
type: NounType.Organization,
|
||||
metadata: { verified: false, source: 'Registration' }
|
||||
})
|
||||
|
||||
// Verify metadata with type context
|
||||
const person = await brain.get(personId)
|
||||
const org = await brain.get(orgId)
|
||||
|
||||
expect(person?.metadata?.verified).toBe(true)
|
||||
expect(org?.metadata?.verified).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue