Files
waggle-os/packages/server/tests/cockpit-health.test.ts
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

112 lines
4.2 KiB
TypeScript

/**
* Cockpit health endpoint enhancements — memoryStats, serviceHealth, defaultModel.
*/
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { MindDB, FrameStore, SessionStore } from '@waggle/core';
import { buildLocalServer } from '../src/local/index.js';
import type { FastifyInstance } from 'fastify';
describe('Cockpit health endpoint enhancements', () => {
let server: FastifyInstance;
let tmpDir: string;
beforeAll(async () => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-cockpit-test-'));
// Create personal.mind with test data
const personalPath = path.join(tmpDir, 'personal.mind');
const mind = new MindDB(personalPath);
const sessions = new SessionStore(mind);
const frames = new FrameStore(mind);
const s1 = sessions.create('cockpit-test');
frames.createIFrame(s1.gop_id, 'Test frame 1', 'normal');
frames.createIFrame(s1.gop_id, 'Test frame 2', 'important');
frames.createPFrame(s1.gop_id, 'Test P-frame', 1, 'normal');
mind.close();
server = await buildLocalServer({ dataDir: tmpDir });
});
afterAll(async () => {
await server.close();
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns memoryStats in health response', async () => {
const res = await server.inject({ method: 'GET', url: '/health' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.memoryStats).toBeDefined();
expect(typeof body.memoryStats.frameCount).toBe('number');
expect(body.memoryStats.frameCount).toBeGreaterThanOrEqual(3); // We created 3 frames
expect(typeof body.memoryStats.mindSizeBytes).toBe('number');
expect(body.memoryStats.mindSizeBytes).toBeGreaterThan(0);
expect(typeof body.memoryStats.embeddingCoverage).toBe('number');
expect(body.memoryStats.embeddingCoverage).toBeGreaterThanOrEqual(0);
expect(body.memoryStats.embeddingCoverage).toBeLessThanOrEqual(100);
});
it('returns serviceHealth in health response', async () => {
const res = await server.inject({ method: 'GET', url: '/health' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.serviceHealth).toBeDefined();
expect(typeof body.serviceHealth.watchdogRunning).toBe('boolean');
expect(body.serviceHealth.watchdogRunning).toBe(true); // scheduler starts on server build
expect(typeof body.serviceHealth.notificationSSEActive).toBe('boolean');
});
it('returns defaultModel in health response', async () => {
const res = await server.inject({ method: 'GET', url: '/health' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.defaultModel).toBeDefined();
expect(typeof body.defaultModel).toBe('string');
expect(body.defaultModel.length).toBeGreaterThan(0);
});
it('preserves existing health fields', async () => {
const res = await server.inject({ method: 'GET', url: '/health' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
// All original fields still present
expect(['ok', 'degraded', 'unavailable']).toContain(body.status);
expect(body.mode).toBe('local');
expect(body.timestamp).toBeDefined();
expect(body.llm).toBeDefined();
expect(body.llm.provider).toBeDefined();
expect(body.llm.health).toBeDefined();
expect(body.database).toBeDefined();
expect(body.database.healthy).toBe(true);
});
it('does not block first health response on slow live provider validation', async () => {
server.agentState.llmProvider = {
provider: 'anthropic-proxy',
health: 'healthy',
detail: 'test provider',
checkedAt: new Date().toISOString(),
};
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(async () => {
await new Promise((resolve) => setTimeout(resolve, 250));
return { status: 200 } as Response;
});
const started = Date.now();
try {
const res = await server.inject({ method: 'GET', url: '/health' });
const elapsed = Date.now() - started;
expect(res.statusCode).toBe(200);
expect(elapsed).toBeLessThan(100);
} finally {
fetchSpy.mockRestore();
}
});
});