tasq/node_modules/@claude-flow/memory/dist/database-provider.test.js

285 lines
12 KiB
JavaScript

/**
* Database Provider Tests - Cross-Platform Compatibility
*
* Tests for platform-aware database selection and fallback mechanisms
*/
import { describe, it, expect, afterEach } from 'vitest';
import { createDatabase, getPlatformInfo, getAvailableProviders } from './database-provider.js';
import { createDefaultEntry } from './types.js';
import { unlinkSync, existsSync } from 'node:fs';
describe('DatabaseProvider', () => {
const testDbPath = './test-database-provider.db';
afterEach(() => {
// Cleanup test database
if (existsSync(testDbPath)) {
try {
unlinkSync(testDbPath);
}
catch (error) {
// Ignore cleanup errors
}
}
});
describe('Platform Detection', () => {
it('should detect platform information', () => {
const info = getPlatformInfo();
expect(info).toHaveProperty('os');
expect(info).toHaveProperty('isWindows');
expect(info).toHaveProperty('isMacOS');
expect(info).toHaveProperty('isLinux');
expect(info).toHaveProperty('recommendedProvider');
// Should recommend sql.js on Windows, better-sqlite3 on Unix
if (info.isWindows) {
expect(info.recommendedProvider).toBe('sql.js');
}
else {
expect(info.recommendedProvider).toBe('better-sqlite3');
}
});
});
describe('Provider Availability', () => {
it('should check available providers', async () => {
const available = await getAvailableProviders();
expect(available).toHaveProperty('betterSqlite3');
expect(available).toHaveProperty('sqlJs');
expect(available).toHaveProperty('json');
// JSON backend should always be available
expect(available.json).toBe(true);
});
});
describe('Automatic Provider Selection', () => {
it('should create database with auto provider selection', async () => {
const db = await createDatabase(':memory:');
expect(db).toBeDefined();
await expect(db.count()).resolves.toBe(0);
await db.shutdown();
});
it('should create persistent database with auto provider', async () => {
const db = await createDatabase(testDbPath);
expect(db).toBeDefined();
// Store test entry
const entry = createDefaultEntry({
key: 'test-key',
content: 'test content',
namespace: 'test',
});
await db.store(entry);
await expect(db.count()).resolves.toBe(1);
await db.shutdown();
});
});
describe('Explicit Provider Selection', () => {
it('should create database with sql.js provider', async () => {
const available = await getAvailableProviders();
if (!available.sqlJs) {
console.log('sql.js not available, skipping test');
return;
}
const db = await createDatabase(':memory:', {
provider: 'sql.js',
verbose: false,
});
expect(db).toBeDefined();
// Test basic operations
const entry = createDefaultEntry({
key: 'sqljs-test',
content: 'testing sql.js backend',
namespace: 'test',
});
await db.store(entry);
await expect(db.count()).resolves.toBe(1);
const retrieved = await db.get(entry.id);
expect(retrieved).toBeDefined();
expect(retrieved?.key).toBe('sqljs-test');
await db.shutdown();
});
it('should create database with better-sqlite3 provider', async () => {
const available = await getAvailableProviders();
if (!available.betterSqlite3) {
console.log('better-sqlite3 not available, skipping test');
return;
}
const db = await createDatabase(':memory:', {
provider: 'better-sqlite3',
verbose: false,
});
expect(db).toBeDefined();
// Test basic operations
const entry = createDefaultEntry({
key: 'sqlite-test',
content: 'testing better-sqlite3 backend',
namespace: 'test',
});
await db.store(entry);
await expect(db.count()).resolves.toBe(1);
const retrieved = await db.get(entry.id);
expect(retrieved).toBeDefined();
expect(retrieved?.key).toBe('sqlite-test');
await db.shutdown();
});
it('should create database with JSON provider', async () => {
const db = await createDatabase(testDbPath, {
provider: 'json',
verbose: false,
});
expect(db).toBeDefined();
// Test basic operations
const entry = createDefaultEntry({
key: 'json-test',
content: 'testing JSON backend',
namespace: 'test',
});
await db.store(entry);
await expect(db.count()).resolves.toBe(1);
const retrieved = await db.get(entry.id);
expect(retrieved).toBeDefined();
expect(retrieved?.key).toBe('json-test');
await db.shutdown();
});
});
describe('Cross-Platform Functionality', () => {
it('should handle CRUD operations consistently across providers', async () => {
const available = await getAvailableProviders();
const providers = [];
if (available.betterSqlite3)
providers.push('better-sqlite3');
if (available.sqlJs)
providers.push('sql.js');
providers.push('json'); // Always available
for (const provider of providers) {
const db = await createDatabase(':memory:', { provider });
// Create
const entry = createDefaultEntry({
key: `test-${provider}`,
content: `testing ${provider}`,
namespace: 'cross-platform',
tags: ['test', provider],
});
await db.store(entry);
// Read
const retrieved = await db.get(entry.id);
expect(retrieved).toBeDefined();
expect(retrieved?.key).toBe(`test-${provider}`);
expect(retrieved?.tags).toContain(provider);
// Update
const updated = await db.update(entry.id, {
content: `updated ${provider}`,
});
expect(updated).toBeDefined();
expect(updated?.content).toBe(`updated ${provider}`);
// Query
const results = await db.query({
type: 'hybrid',
namespace: 'cross-platform',
limit: 10,
});
expect(results.length).toBe(1);
expect(results[0].key).toBe(`test-${provider}`);
// Delete
const deleted = await db.delete(entry.id);
expect(deleted).toBe(true);
await expect(db.count()).resolves.toBe(0);
await db.shutdown();
}
});
it('should handle namespace operations across providers', async () => {
const db = await createDatabase(':memory:');
// Create entries in different namespaces
const entries = [
createDefaultEntry({ key: 'entry1', content: 'content1', namespace: 'ns1' }),
createDefaultEntry({ key: 'entry2', content: 'content2', namespace: 'ns1' }),
createDefaultEntry({ key: 'entry3', content: 'content3', namespace: 'ns2' }),
];
for (const entry of entries) {
await db.store(entry);
}
// List namespaces
const namespaces = await db.listNamespaces();
expect(namespaces).toContain('ns1');
expect(namespaces).toContain('ns2');
// Count by namespace
await expect(db.count('ns1')).resolves.toBe(2);
await expect(db.count('ns2')).resolves.toBe(1);
// Clear namespace
const cleared = await db.clearNamespace('ns1');
expect(cleared).toBe(2);
await expect(db.count('ns1')).resolves.toBe(0);
await expect(db.count('ns2')).resolves.toBe(1);
await db.shutdown();
});
it('should handle bulk operations across providers', async () => {
const db = await createDatabase(':memory:');
// Bulk insert
const entries = Array.from({ length: 10 }, (_, i) => createDefaultEntry({
key: `bulk-${i}`,
content: `content ${i}`,
namespace: 'bulk-test',
}));
await db.bulkInsert(entries);
await expect(db.count('bulk-test')).resolves.toBe(10);
// Bulk delete
const idsToDelete = entries.slice(0, 5).map((e) => e.id);
const deletedCount = await db.bulkDelete(idsToDelete);
expect(deletedCount).toBe(5);
await expect(db.count('bulk-test')).resolves.toBe(5);
await db.shutdown();
});
});
describe('Health Check', () => {
it('should perform health check', async () => {
const db = await createDatabase(':memory:');
const health = await db.healthCheck();
expect(health).toHaveProperty('status');
expect(health).toHaveProperty('components');
expect(health).toHaveProperty('timestamp');
expect(health).toHaveProperty('issues');
expect(health).toHaveProperty('recommendations');
expect(health.components).toHaveProperty('storage');
expect(health.components).toHaveProperty('index');
expect(health.components).toHaveProperty('cache');
await db.shutdown();
});
});
describe('Statistics', () => {
it('should provide backend statistics', async () => {
const db = await createDatabase(':memory:');
// Add some test data
const entries = [
createDefaultEntry({ key: 'stat1', content: 'content1', namespace: 'stats', type: 'semantic' }),
createDefaultEntry({ key: 'stat2', content: 'content2', namespace: 'stats', type: 'episodic' }),
createDefaultEntry({ key: 'stat3', content: 'content3', namespace: 'stats', type: 'semantic' }),
];
for (const entry of entries) {
await db.store(entry);
}
const stats = await db.getStats();
expect(stats).toHaveProperty('totalEntries');
expect(stats).toHaveProperty('entriesByNamespace');
expect(stats).toHaveProperty('entriesByType');
expect(stats).toHaveProperty('memoryUsage');
expect(stats).toHaveProperty('avgQueryTime');
expect(stats.totalEntries).toBe(3);
await db.shutdown();
});
});
describe('Error Handling', () => {
it('should handle missing entries gracefully', async () => {
const db = await createDatabase(':memory:');
const entry = await db.get('non-existent-id');
expect(entry).toBeNull();
const byKey = await db.getByKey('non-existent-ns', 'non-existent-key');
expect(byKey).toBeNull();
await db.shutdown();
});
it('should handle empty queries', async () => {
const db = await createDatabase(':memory:');
const results = await db.query({
type: 'hybrid',
limit: 10,
});
expect(results).toEqual([]);
await db.shutdown();
});
});
});
//# sourceMappingURL=database-provider.test.js.map