@joystick.js/db-canary
Version:
JoystickDB - A minimalist database server for the Joystick framework
186 lines (147 loc) • 5.85 kB
JavaScript
import test from 'ava';
import { PerformanceMonitor } from '../../../src/server/lib/performance_monitor.js';
test('PerformanceMonitor - should initialize with empty metrics', t => {
const monitor = new PerformanceMonitor();
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 0);
t.is(stats.total_errors, 0);
t.is(stats.ops_per_second, 0);
t.is(stats.avg_response_time_ms, 0);
t.is(stats.error_rate_percent, 0);
});
test('PerformanceMonitor - should track successful operations', t => {
const monitor = new PerformanceMonitor();
monitor.track_operation('find_one', 50, 'success');
monitor.track_operation('insert_one', 100, 'success');
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 2);
t.is(stats.total_errors, 0);
t.is(stats.error_rate_percent, 0);
t.true(stats.ops_per_second >= 0);
t.true(stats.avg_response_time_ms > 0);
});
test('PerformanceMonitor - should track failed operations', t => {
const monitor = new PerformanceMonitor();
monitor.track_operation('find_one', 25, 'error', 'Document not found');
monitor.track_operation('insert_one', 75, 'success');
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 2);
t.is(stats.total_errors, 1);
t.is(stats.error_rate_percent, 50);
t.is(stats.top_errors.length, 1);
t.is(stats.top_errors[0].error, 'Document not found');
t.is(stats.top_errors[0].count, 1);
});
test('PerformanceMonitor - should track operation breakdown', t => {
const monitor = new PerformanceMonitor();
monitor.track_operation('find_one', 50, 'success');
monitor.track_operation('find_one', 100, 'error', 'Timeout');
monitor.track_operation('insert_one', 75, 'success');
const stats = monitor.get_performance_stats();
t.truthy(stats.operations.find_one);
t.is(stats.operations.find_one.count, 2);
t.is(stats.operations.find_one.error_count, 1);
t.is(stats.operations.find_one.error_rate, 50);
t.is(stats.operations.find_one.avg_duration_ms, 75);
t.truthy(stats.operations.insert_one);
t.is(stats.operations.insert_one.count, 1);
t.is(stats.operations.insert_one.error_count, 0);
t.is(stats.operations.insert_one.error_rate, 0);
t.is(stats.operations.insert_one.avg_duration_ms, 75);
});
test('PerformanceMonitor - should get memory stats', t => {
const monitor = new PerformanceMonitor();
const memory_stats = monitor.get_memory_stats();
t.true(typeof memory_stats.rss_mb === 'number');
t.true(typeof memory_stats.heap_total_mb === 'number');
t.true(typeof memory_stats.heap_used_mb === 'number');
t.true(typeof memory_stats.heap_used_percent === 'number');
t.true(typeof memory_stats.external_mb === 'number');
t.true(memory_stats.rss_mb > 0);
t.true(memory_stats.heap_total_mb > 0);
t.true(memory_stats.heap_used_mb > 0);
t.true(memory_stats.heap_used_percent >= 0 && memory_stats.heap_used_percent <= 100);
});
test('PerformanceMonitor - should get system stats', t => {
const monitor = new PerformanceMonitor();
const system_stats = monitor.get_system_stats();
t.true(typeof system_stats.node_version === 'string');
t.true(typeof system_stats.platform === 'string');
t.true(typeof system_stats.arch === 'string');
t.true(typeof system_stats.pid === 'number');
t.true(typeof system_stats.cpu_user_ms === 'number');
t.true(typeof system_stats.cpu_system_ms === 'number');
t.true(system_stats.pid > 0);
t.true(system_stats.cpu_user_ms >= 0);
t.true(system_stats.cpu_system_ms >= 0);
});
test('PerformanceMonitor - should log structured operations', t => {
const monitor = new PerformanceMonitor();
// This should not throw
t.notThrows(() => {
monitor.log_structured_operation(
'client_123',
'find_one',
'users',
45,
'success',
null,
1024,
2048
);
});
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 1);
t.is(stats.total_errors, 0);
});
test('PerformanceMonitor - should log structured operations with errors', t => {
const monitor = new PerformanceMonitor();
monitor.log_structured_operation(
'client_456',
'insert_one',
'users',
100,
'error',
'Validation failed',
512,
0
);
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 1);
t.is(stats.total_errors, 1);
t.is(stats.error_rate_percent, 100);
});
test('PerformanceMonitor - should reset metrics', t => {
const monitor = new PerformanceMonitor();
monitor.track_operation('find_one', 50, 'success');
monitor.track_operation('insert_one', 100, 'error', 'Test error');
let stats = monitor.get_performance_stats();
t.is(stats.total_requests, 2);
t.is(stats.total_errors, 1);
monitor.reset_metrics();
stats = monitor.get_performance_stats();
t.is(stats.total_requests, 0);
t.is(stats.total_errors, 0);
t.is(stats.ops_per_second, 0);
t.is(stats.avg_response_time_ms, 0);
t.is(stats.error_rate_percent, 0);
});
test('PerformanceMonitor - should limit response times array size', t => {
const monitor = new PerformanceMonitor();
// Add more than max_response_times (1000) operations
for (let i = 0; i < 1200; i++) {
monitor.track_operation('test_op', 10, 'success');
}
const stats = monitor.get_performance_stats();
t.is(stats.total_requests, 1200);
// Response times array should be limited
t.true(monitor.metrics.response_times.length <= monitor.max_response_times);
});
test('PerformanceMonitor - should handle database stats gracefully', t => {
const monitor = new PerformanceMonitor();
// This should not throw even if database is not available
t.notThrows(() => {
const db_stats = monitor.get_database_stats();
t.true(typeof db_stats === 'object');
});
});