/ tests / agents / slo-tracker-simple.test.js
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  });