| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 |
- // @vitest-environment node
- import { expect, it, vi } from 'vitest'
- import { OpenVikingMemoryProvider } from '../../src/server/openVikingMemoryProvider'
- import type { OpenVikingService } from '../../src/server/openVikingService'
- import type { WorkspaceKnowledge } from '../../src/server/workspaceKnowledge'
- function fixture() {
- const records = Array.from({ length: 20 }, (_, index) => ({
- schemaVersion: 1, revisions: [], memory: {
- id: index.toString(16).padStart(32, '0'), scope: 'agent', agentId: 'agent', content: `fact-${index}`,
- },
- }))
- const list = vi.fn(async () => records.map(record => `${record.memory.id}.json`))
- const read = vi.fn(async (uri: string) => JSON.stringify(records.find(record => uri.endsWith(`${record.memory.id}.json`))))
- const client = { list, read }
- const service = { enabled: true, ensureUser: vi.fn(async () => undefined), userClient: vi.fn(() => client) }
- const knowledge = { agent: vi.fn(() => ({ id: 'agent' })) }
- return { provider: new OpenVikingMemoryProvider(service as unknown as OpenVikingService, knowledge as unknown as WorkspaceKnowledge),
- records, read, list }
- }
- it('overlaps at most eight reads while preserving listing order and scope isolation', async () => {
- const f = fixture()
- let active = 0, peak = 0
- const release: Array<() => void> = []
- f.records[3]!.memory.agentId = 'another-agent'
- f.read.mockImplementation(async uri => {
- active++; peak = Math.max(peak, active)
- await new Promise<void>(resolve => release.push(resolve))
- active--
- return JSON.stringify(f.records.find(record => uri.endsWith(`${record.memory.id}.json`)))
- })
- const pending = f.provider.list('owner', [{ scope: 'agent', agentId: 'agent' }])
- await vi.waitFor(() => expect(release).toHaveLength(8))
- // Release batches in reverse order, forcing responses to arrive out of listing order.
- while (f.read.mock.calls.length < 20 || active) {
- release.splice(0).reverse().forEach(resolve => resolve())
- await new Promise(resolve => setTimeout(resolve, 0))
- }
- expect((await pending).map(memory => memory.content)).toEqual(f.records.filter(record => record.memory.agentId === 'agent').map(record => record.memory.content))
- expect(peak).toBe(8)
- expect(f.read).toHaveBeenCalledTimes(20)
- })
- it('keeps upstream failures visible and continues to reject corrupt records', async () => {
- const f = fixture()
- f.read.mockRejectedValueOnce(new Error('upstream unavailable'))
- await expect(f.provider.list('owner', [{ scope: 'agent', agentId: 'agent' }])).rejects.toThrow('upstream unavailable')
- f.read.mockResolvedValueOnce('invalid JSON')
- await expect(f.provider.list('owner', [{ scope: 'agent', agentId: 'agent' }])).rejects.toMatchObject({ code: 'openviking_memory_corrupt' })
- })
|