259 lines
7.7 KiB
TypeScript
259 lines
7.7 KiB
TypeScript
import { MemoryDeltaStorage, LevelDBDeltaStorage, StorageFactory } from '../src/storage';
|
|
import { Delta } from '../src/core';
|
|
import { DeltaQueryStorage } from '../src/storage/interface';
|
|
|
|
describe('Delta Storage', () => {
|
|
const testDeltas = [
|
|
new Delta({
|
|
id: 'delta1',
|
|
creator: 'alice',
|
|
host: 'host1',
|
|
timeCreated: Date.now() - 1000,
|
|
pointers: [
|
|
{ localContext: 'user', target: 'user1', targetContext: 'name' },
|
|
{ localContext: 'value', target: 'Alice' }
|
|
]
|
|
}),
|
|
new Delta({
|
|
id: 'delta2',
|
|
creator: 'bob',
|
|
host: 'host1',
|
|
timeCreated: Date.now() - 500,
|
|
pointers: [
|
|
{ localContext: 'user', target: 'user1', targetContext: 'age' },
|
|
{ localContext: 'value', target: 25 }
|
|
]
|
|
}),
|
|
new Delta({
|
|
id: 'delta3',
|
|
creator: 'alice',
|
|
host: 'host2',
|
|
timeCreated: Date.now(),
|
|
pointers: [
|
|
{ localContext: 'user', target: 'user2', targetContext: 'name' },
|
|
{ localContext: 'value', target: 'Bob' }
|
|
]
|
|
})
|
|
];
|
|
|
|
describe('Memory Storage', () => {
|
|
let storage: DeltaQueryStorage;
|
|
|
|
beforeEach(() => {
|
|
storage = new MemoryDeltaStorage();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await storage.close();
|
|
});
|
|
|
|
runStorageTests(() => storage as DeltaQueryStorage);
|
|
});
|
|
|
|
describe('LevelDB Storage', () => {
|
|
let storage: DeltaQueryStorage;
|
|
|
|
beforeEach(async () => {
|
|
storage = new LevelDBDeltaStorage('./test-data/leveldb-test');
|
|
await (storage as LevelDBDeltaStorage).open();
|
|
await (storage as LevelDBDeltaStorage).clearAll();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await storage.close();
|
|
});
|
|
|
|
runStorageTests(() => storage);
|
|
});
|
|
|
|
describe('Storage Factory', () => {
|
|
it('creates memory storage', () => {
|
|
const storage = StorageFactory.create({ type: 'memory' });
|
|
expect(storage).toBeInstanceOf(MemoryDeltaStorage);
|
|
});
|
|
|
|
it('creates LevelDB storage', () => {
|
|
const storage = StorageFactory.create({
|
|
type: 'leveldb',
|
|
path: './test-data/factory-test'
|
|
});
|
|
expect(storage).toBeInstanceOf(LevelDBDeltaStorage);
|
|
});
|
|
|
|
it('throws on unknown storage type', () => {
|
|
expect(() => {
|
|
StorageFactory.create({ type: 'unknown' as 'memory' | 'leveldb' });
|
|
}).toThrow('Unknown storage type: unknown');
|
|
});
|
|
});
|
|
|
|
function runStorageTests(getStorage: () => DeltaQueryStorage) {
|
|
it('stores and retrieves deltas', async () => {
|
|
const storage = getStorage();
|
|
|
|
// Store deltas
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
// Retrieve individual deltas
|
|
const delta1 = await storage.getDelta('delta1');
|
|
expect(delta1).toBeDefined();
|
|
expect(delta1!.id).toBe('delta1');
|
|
expect(delta1!.creator).toBe('alice');
|
|
|
|
// Test non-existent delta
|
|
const nonExistent = await storage.getDelta('nonexistent');
|
|
expect(nonExistent).toBeNull();
|
|
});
|
|
|
|
it('gets all deltas', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
const allDeltas = await storage.getAllDeltas();
|
|
expect(allDeltas).toHaveLength(3);
|
|
|
|
const deltaIds = allDeltas.map(d => d.id);
|
|
expect(deltaIds).toContain('delta1');
|
|
expect(deltaIds).toContain('delta2');
|
|
expect(deltaIds).toContain('delta3');
|
|
});
|
|
|
|
it('filters deltas', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
// Filter by creator
|
|
const aliceDeltas = await storage.getAllDeltas(d => d.creator === 'alice');
|
|
expect(aliceDeltas).toHaveLength(2);
|
|
expect(aliceDeltas.every(d => d.creator === 'alice')).toBe(true);
|
|
});
|
|
|
|
it('gets deltas for entity', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
const user1Deltas = await storage.getDeltasForEntity('user1');
|
|
expect(user1Deltas).toHaveLength(2);
|
|
|
|
const user2Deltas = await storage.getDeltasForEntity('user2');
|
|
expect(user2Deltas).toHaveLength(1);
|
|
|
|
const nonExistentDeltas = await storage.getDeltasForEntity('user999');
|
|
expect(nonExistentDeltas).toHaveLength(0);
|
|
});
|
|
|
|
it('gets deltas by context', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
const nameDeltas = await storage.getDeltasByContext('user1', 'name');
|
|
expect(nameDeltas).toHaveLength(1);
|
|
expect(nameDeltas[0].id).toBe('delta1');
|
|
|
|
const ageDeltas = await storage.getDeltasByContext('user1', 'age');
|
|
expect(ageDeltas).toHaveLength(1);
|
|
expect(ageDeltas[0].id).toBe('delta2');
|
|
|
|
const nonExistentDeltas = await storage.getDeltasByContext('user1', 'email');
|
|
expect(nonExistentDeltas).toHaveLength(0);
|
|
});
|
|
|
|
it('queries deltas with complex criteria', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
// Query by creator
|
|
const aliceDeltas = await storage.queryDeltas({ creator: 'alice' });
|
|
expect(aliceDeltas).toHaveLength(2);
|
|
|
|
// Query by host
|
|
const host1Deltas = await storage.queryDeltas({ host: 'host1' });
|
|
expect(host1Deltas).toHaveLength(2);
|
|
|
|
// Query by entity
|
|
const user1Deltas = await storage.queryDeltas({ targetEntities: ['user1'] });
|
|
expect(user1Deltas).toHaveLength(2);
|
|
|
|
// Query by context
|
|
const nameDeltas = await storage.queryDeltas({ contexts: ['name'] });
|
|
expect(nameDeltas).toHaveLength(2);
|
|
|
|
// Combined query
|
|
const aliceUser1Deltas = await storage.queryDeltas({
|
|
creator: 'alice',
|
|
targetEntities: ['user1']
|
|
});
|
|
expect(aliceUser1Deltas).toHaveLength(1);
|
|
expect(aliceUser1Deltas[0].id).toBe('delta1');
|
|
});
|
|
|
|
it('applies pagination to queries', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
// Test limit
|
|
const limitedDeltas = await storage.queryDeltas({ limit: 2 });
|
|
expect(limitedDeltas).toHaveLength(2);
|
|
|
|
// Test offset
|
|
const offsetDeltas = await storage.queryDeltas({ offset: 1 });
|
|
expect(offsetDeltas).toHaveLength(2);
|
|
|
|
// Test limit + offset
|
|
const pagedDeltas = await storage.queryDeltas({ offset: 1, limit: 1 });
|
|
expect(pagedDeltas).toHaveLength(1);
|
|
});
|
|
|
|
it('counts deltas', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
const totalCount = await storage.countDeltas({});
|
|
expect(totalCount).toBe(3);
|
|
|
|
const aliceCount = await storage.countDeltas({ creator: 'alice' });
|
|
expect(aliceCount).toBe(2);
|
|
|
|
const user1Count = await storage.countDeltas({ targetEntities: ['user1'] });
|
|
expect(user1Count).toBe(2);
|
|
});
|
|
|
|
it('provides storage statistics', async () => {
|
|
const storage = getStorage();
|
|
|
|
for (const delta of testDeltas) {
|
|
await storage.storeDelta(delta);
|
|
}
|
|
|
|
const stats = await storage.getStats();
|
|
expect(stats.totalDeltas).toBe(3);
|
|
expect(stats.totalEntities).toBe(2); // user1 and user2
|
|
expect(stats.oldestDelta).toBeDefined();
|
|
expect(stats.newestDelta).toBeDefined();
|
|
expect(stats.oldestDelta! <= stats.newestDelta!).toBe(true);
|
|
});
|
|
}
|
|
}); |