/** * Shard-bucket resolution for entity ids. * * `getShardId` buckets every entity id into one of 256 dirs (00-ff). It must * accept BOTH UUID-format ids (bucketed by first byte — the original on-disk * layout) AND arbitrary application ids like `'user-123'` (bucketed by a stable * hash). A refactor once required UUID format and threw on everything else, * which broke the documented `add({ id: '…' })` contract. These tests pin the * dual scheme, determinism, and distribution. */ import { describe, it, expect } from 'vitest' import { getShardId, getAllShardIds } from '../../../src/storage/sharding.js' describe('getShardId', () => { it('buckets a UUID by its first byte (with or without hyphens)', () => { expect(getShardId('ab123456-1234-5678-9abc-def012345678')).toBe('ab') expect(getShardId('ab123456123456789abcdef012345678')).toBe('ab') expect(getShardId('CD987654-4321-8765-cba9-fed543210987')).toBe('cd') // case-insensitive expect(getShardId('00000000-0000-0000-0000-000000000000')).toBe('00') }) it('buckets an arbitrary application id without throwing (the regression)', () => { const shard = getShardId('user-12345') expect(shard).toMatch(/^[0-9a-f]{2}$/) }) it('is deterministic for application ids', () => { expect(getShardId('order-42')).toBe(getShardId('order-42')) expect(getShardId('alice@example.com')).toBe(getShardId('alice@example.com')) }) it('distributes application ids across many buckets (not one hot bucket)', () => { const buckets = new Set() for (let i = 0; i < 1000; i++) { buckets.add(getShardId(`entity-${i}`)) } // FNV-1a over 1000 sequential keys should touch a large fraction of the // 256-bucket space; a degenerate hash would collapse to a handful. expect(buckets.size).toBeGreaterThan(200) }) it('every produced shard is a valid bucket id', () => { const valid = new Set(getAllShardIds()) for (const sample of ['user-1', 'café', '🚀', 'a', 'A_VERY_LONG_APPLICATION_KEY_0001']) { expect(valid.has(getShardId(sample))).toBe(true) } }) it('throws on an empty id', () => { expect(() => getShardId('')).toThrow(/id is required/) }) })