UNPKG

@joystick.js/db-canary

Version:

JoystickDB - A minimalist database server for the Joystick framework

276 lines (217 loc) 7.99 kB
import test from 'ava'; import { initialize_auto_index_database, cleanup_auto_index_database, record_query, record_index_usage, get_query_statistics, get_auto_index_statistics, force_index_evaluation, remove_automatic_indexes, is_auto_created_index } from '../../../src/server/lib/auto_index_manager.js'; import { initialize_database, cleanup_database } from '../../../src/server/lib/query_engine.js'; import { initialize_index_database, create_index, get_indexes, cleanup_index_database } from '../../../src/server/lib/index_manager.js'; test.beforeEach(async (t) => { initialize_database('./test_data'); initialize_index_database(); initialize_auto_index_database(); }); test.afterEach(async (t) => { cleanup_auto_index_database(); cleanup_index_database(); await cleanup_database(); }); test('should initialize auto index database', (t) => { t.notThrows(() => { initialize_auto_index_database(); }); }); test('should record query statistics', (t) => { const collection = 'test_collection'; const filter = { name: 'John', age: 25 }; const execution_time = 50; t.notThrows(() => { record_query(collection, filter, execution_time, false); }); const stats = get_query_statistics(collection); t.truthy(stats.name); t.truthy(stats.age); t.is(stats.name.query_count, 1); t.is(stats.age.query_count, 1); t.is(stats.name.total_time_ms, execution_time); t.is(stats.age.total_time_ms, execution_time); }); test('should record multiple queries and aggregate statistics', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; record_query(collection, filter, 30, false); record_query(collection, filter, 50, false); record_query(collection, filter, 70, false); const stats = get_query_statistics(collection); t.is(stats.name.query_count, 3); t.is(stats.name.total_time_ms, 150); t.is(stats.name.avg_time_ms, 50); }); test('should track slow queries', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; record_query(collection, filter, 100, false); record_query(collection, filter, 20, false); record_query(collection, filter, 80, false); const stats = get_query_statistics(collection); t.is(stats.name.slow_query_count, 2); }); test('should record index usage', (t) => { const collection = 'test_collection'; const field = 'name'; record_query(collection, { [field]: 'John' }, 30, true); record_index_usage(collection, field); const stats = get_query_statistics(collection); t.is(stats[field].used_index_count, 1); }); test('should get query statistics for all collections', (t) => { record_query('collection1', { name: 'John' }, 30, false); record_query('collection2', { age: 25 }, 40, false); const all_stats = get_query_statistics(); t.truthy(all_stats.collection1); t.truthy(all_stats.collection2); t.truthy(all_stats.collection1.name); t.truthy(all_stats.collection2.age); }); test('should get empty statistics for non-existent collection', (t) => { const stats = get_query_statistics('non_existent'); t.deepEqual(stats, {}); }); test('should get auto index statistics', (t) => { const stats = get_auto_index_statistics(); t.is(typeof stats, 'object'); t.is(stats.total_auto_indexes, 0); t.is(typeof stats.collections, 'object'); }); test('should force index evaluation', async (t) => { const collection = 'test_collection'; const field = 'name'; for (let i = 0; i < 150; i++) { record_query(collection, { [field]: `user${i}` }, 60, false); } const result = await force_index_evaluation(collection); t.is(result.acknowledged, true); }); test('should force index evaluation for all collections', async (t) => { record_query('collection1', { name: 'John' }, 60, false); record_query('collection2', { age: 25 }, 70, false); const result = await force_index_evaluation(); t.is(result.acknowledged, true); }); test('should remove automatic indexes', async (t) => { const collection = 'test_collection'; const field = 'name'; await create_index('default', collection, field); const result = await remove_automatic_indexes(collection, [field]); t.is(result.acknowledged, true); t.is(result.removed_count, 0); }); test('should remove all automatic indexes from collection', async (t) => { const collection = 'test_collection'; const result = await remove_automatic_indexes(collection); t.is(result.acknowledged, true); t.is(typeof result.removed_count, 'number'); }); test('should identify auto-created indexes', (t) => { const collection = 'test_collection'; const field = 'name'; const is_auto = is_auto_created_index(collection, field); t.is(typeof is_auto, 'boolean'); }); test('should handle excluded fields', (t) => { const collection = 'test_collection'; const filter = { _id: '123', created_at: new Date(), name: 'John' }; record_query(collection, filter, 30, false); const stats = get_query_statistics(collection); t.falsy(stats._id); t.falsy(stats.created_at); t.truthy(stats.name); }); test('should handle complex filter objects', (t) => { const collection = 'test_collection'; const filter = { name: { $regex: 'John' }, age: { $gt: 18, $lt: 65 }, status: { $in: ['active', 'pending'] } }; record_query(collection, filter, 45, false); const stats = get_query_statistics(collection); t.truthy(stats.name); t.truthy(stats.age); t.truthy(stats.status); t.is(stats.name.query_count, 1); t.is(stats.age.query_count, 1); t.is(stats.status.query_count, 1); }); test('should handle null and undefined filters', (t) => { const collection = 'test_collection'; t.notThrows(() => { record_query(collection, null, 30, false); record_query(collection, undefined, 30, false); record_query(collection, {}, 30, false); }); const stats = get_query_statistics(collection); t.deepEqual(stats, {}); }); test('should handle invalid collection names', (t) => { t.notThrows(() => { record_query('', { name: 'John' }, 30, false); record_query(null, { name: 'John' }, 30, false); record_query(undefined, { name: 'John' }, 30, false); }); }); test('should handle negative execution times', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; t.notThrows(() => { record_query(collection, filter, -10, false); }); const stats = get_query_statistics(collection); t.is(stats.name.total_time_ms, -10); }); test('should handle very large execution times', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; t.notThrows(() => { record_query(collection, filter, 999999, false); }); const stats = get_query_statistics(collection); t.is(stats.name.total_time_ms, 999999); t.is(stats.name.slow_query_count, 1); }); test('should update last_queried timestamp', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; const before = new Date(); record_query(collection, filter, 30, false); const stats = get_query_statistics(collection); const after = new Date(); t.true(stats.name.last_queried >= before); t.true(stats.name.last_queried <= after); }); test('should handle concurrent query recording', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; for (let i = 0; i < 100; i++) { record_query(collection, filter, 30 + i, false); } const stats = get_query_statistics(collection); t.is(stats.name.query_count, 100); t.is(stats.name.total_time_ms, 100 * 30 + (99 * 100) / 2); }); test('should cleanup auto index database', (t) => { const collection = 'test_collection'; const filter = { name: 'John' }; record_query(collection, filter, 30, false); t.notThrows(() => { cleanup_auto_index_database(); }); const stats = get_query_statistics(collection); t.deepEqual(stats, {}); });