slo-tracker-simple.test.js
1 /** 2 * Simplified SLO Tracker Tests 3 * Focused on core functionality without complex async hooks 4 */ 5 6 import { test, before, mock } from 'node:test'; 7 import assert from 'node:assert'; 8 import Database from 'better-sqlite3'; 9 import { createPgMock } from '../helpers/pg-mock.js'; 10 11 // Shared in-memory database with minimal schema 12 const db = new Database(':memory:'); 13 db.exec(` 14 CREATE TABLE IF NOT EXISTS sites ( 15 id INTEGER PRIMARY KEY, 16 domain TEXT, 17 status TEXT, 18 rescored_at DATETIME 19 ); 20 CREATE TABLE IF NOT EXISTS site_status ( 21 id INTEGER PRIMARY KEY AUTOINCREMENT, 22 site_id INTEGER, 23 status TEXT, 24 created_at DATETIME DEFAULT CURRENT_TIMESTAMP 25 ); 26 `); 27 28 mock.module('../../src/utils/db.js', { namedExports: createPgMock(db) }); 29 30 const { 31 SLO_DEFINITIONS, 32 calculateStagePerformance, 33 checkSLOCompliance, 34 getSLOSummary, 35 } = await import('../../src/agents/utils/slo-tracker.js'); 36 37 // Clear tables before each test via test setup 38 before(() => { 39 db.exec('DELETE FROM site_status; DELETE FROM sites;'); 40 }); 41 42 function clearTables() { 43 db.exec('DELETE FROM site_status; DELETE FROM sites;'); 44 } 45 46 test('SLO Definitions exist', () => { 47 assert.ok(Array.isArray(SLO_DEFINITIONS)); 48 assert.ok(SLO_DEFINITIONS.length >= 3); 49 assert.ok(SLO_DEFINITIONS[0].stage_name); 50 assert.ok(SLO_DEFINITIONS[0].target_duration_minutes); 51 }); 52 53 test('calculateStagePerformance - empty database', async () => { 54 clearTables(); 55 56 const result = await calculateStagePerformance('found', 'assets_captured', 24); 57 58 assert.strictEqual(result.totalSites, 0); 59 assert.deepStrictEqual(result.durations, []); 60 }); 61 62 test('calculateStagePerformance - with data', async () => { 63 clearTables(); 64 65 // Insert test data: site transitions in 30 minutes 66 const now = new Date(); 67 const start = new Date(now.getTime() - 30 * 60 * 1000); 68 69 db.prepare('INSERT INTO sites (id, domain, status) VALUES (?, ?, ?)').run( 70 1, 71 'test.com', 72 'assets_captured' 73 ); 74 db.prepare('INSERT INTO site_status (site_id, status, created_at) VALUES (?, ?, ?)').run( 75 1, 76 'found', 77 start.toISOString() 78 ); 79 db.prepare('INSERT INTO site_status (site_id, status, created_at) VALUES (?, ?, ?)').run( 80 1, 81 'assets_captured', 82 now.toISOString() 83 ); 84 85 const result = await calculateStagePerformance('found', 'assets_captured', 24); 86 87 assert.strictEqual(result.totalSites, 1); 88 assert.strictEqual(result.durations.length, 1); 89 assert.ok(Math.abs(result.p50 - 30) < 2); // Within 2 minutes tolerance 90 }); 91 92 test('checkSLOCompliance - no violations', async () => { 93 clearTables(); 94 95 const violations = await checkSLOCompliance(); 96 97 assert.strictEqual(violations.length, 0); 98 }); 99 100 test('getSLOSummary - basic structure', async () => { 101 clearTables(); 102 103 const summary = await getSLOSummary(); 104 105 assert.ok(summary.total_slos > 0); 106 assert.strictEqual(summary.violations, 0); 107 assert.strictEqual(summary.compliance_rate, 100); 108 assert.ok(Array.isArray(summary.violations_detail)); 109 });