Files
deepseek-harness/packages/storage/storage/tests/registry.spec.ts
imccyu 80b3b6d917 fix(storage,workspace): post-review hardening
Review findings applied across the group:
- storage hub: stale disposers no longer remove a successor registration;
  the package now default-exports the Storage service class per the
  service-package export shape.
- json backend: failed publishes roll back the authoritative memory state
  (a rejected write can no longer resurface via get() or ride the next
  publish); close() drains in-flight writes and blocks in-flight opens;
  double-open rejects as a plain caller error instead of malformed-medium.
- sqlite backend: loadAll builds records on a null prototype (__proto__
  keys round-trip instead of polluting), user_version is stamped only
  after the schema is fully created, and corrupt record JSON rejects as
  malformed-medium instead of a bare SyntaxError.
- domain form: writes persist before mutating authoritative memory or
  emitting; DomainChanged is a put/deleted discriminated union.
- workspace: attach/detach idempotence decided on the write chain (stale
  snapshots no longer short-circuit), create() requires a directory, and
  startup fails loud on duplicate stored paths.

Eleven regression tests pin the fixed behaviors.
2026-07-25 11:08:04 +08:00

63 lines
2.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import Storage, { BackendRegistry } from '../src/index.ts'
import type { StorageBackend } from '../src/index.ts'
const fakeBackend = (): StorageBackend => ({ close: async () => {} })
describe('BackendRegistry', () => {
it('registers, resolves, and disposes names', () => {
const registry = new BackendRegistry()
const backend = fakeBackend()
const dispose = registry.register('json', backend)
expect(registry.get('json')).toBe(backend)
expect(registry.names()).toEqual(['json'])
dispose()
expect(registry.names()).toEqual([])
expect(() => registry.get('json')).toThrowMatchingObject({ code: 'backend-not-found' })
})
it('rejects duplicate names', () => {
const registry = new BackendRegistry()
registry.register('json', fakeBackend())
expect(() => registry.register('json', fakeBackend())).toThrowMatchingObject({ code: 'duplicate-backend' })
})
})
describe('Storage service', () => {
it('mounts on the context and exposes registry plus form mounting', async () => {
const ctx = new Context()
await ctx.plugin(Storage)
expect(ctx.storage).toBeInstanceOf(Storage)
const facility = { marker: true }
const dispose = ctx.storage.mount('domain' as never, facility as never)
expect(ctx.storage.form('domain' as never)).toBe(facility)
expect(() => ctx.storage.mount('domain' as never, facility as never)).toThrowMatchingObject({
code: 'duplicate-mount',
})
dispose()
expect(() => ctx.storage.form('domain' as never)).toThrowMatchingObject({ code: 'form-not-mounted' })
})
})
expect.extend({
toThrowMatchingObject(received: () => unknown, expected: object) {
try {
received()
} catch (error) {
const pass = Object.entries(expected).every(
(entry) => (error as Record<string, unknown>)[entry[0]] === entry[1],
)
return { pass, message: () => `expected thrown error to match ${JSON.stringify(expected)}, got ${String(error)}` }
}
return { pass: false, message: () => 'expected function to throw' }
},
})
declare module 'vitest' {
interface Assertion<T> {
toThrowMatchingObject(expected: object): T
}
}