This commit is contained in:
126
packages/server/tests/routes/health.test.ts
Normal file
126
packages/server/tests/routes/health.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { MindDB } from '@waggle/core';
|
||||
import { buildLocalServer } from '../../src/local/index.js';
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
|
||||
describe('Health Endpoint', () => {
|
||||
let server: FastifyInstance;
|
||||
let tmpDir: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-health-test-'));
|
||||
const personalPath = path.join(tmpDir, 'personal.mind');
|
||||
const mind = new MindDB(personalPath);
|
||||
mind.close();
|
||||
|
||||
server = await buildLocalServer({ dataDir: tmpDir });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await server.close();
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns structured health with llm and database status', async () => {
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
const body = JSON.parse(res.payload);
|
||||
expect(body.mode).toBe('local');
|
||||
expect(body.timestamp).toBeTruthy();
|
||||
|
||||
// LLM section
|
||||
expect(body.llm).toBeDefined();
|
||||
expect(body.llm.provider).toMatch(/^(litellm|anthropic-proxy|ollama)$/);
|
||||
expect(body.llm.health).toMatch(/^(healthy|degraded|unavailable)$/);
|
||||
expect(body.llm.detail).toBeTruthy();
|
||||
expect(body.llm.checkedAt).toBeTruthy();
|
||||
|
||||
// Database section
|
||||
expect(body.database).toBeDefined();
|
||||
expect(body.database.healthy).toBe(true);
|
||||
});
|
||||
|
||||
it('overall status reflects LLM health', async () => {
|
||||
// Default: llmProvider was set to unavailable (no init via startService)
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
const body = JSON.parse(res.payload);
|
||||
|
||||
// Since we didn't go through startService, llmProvider defaults to unavailable
|
||||
// Overall status should be 'unavailable' or 'degraded', not 'ok'
|
||||
expect(body.status).not.toBe('ok');
|
||||
});
|
||||
|
||||
it('reports healthy when LLM provider is marked healthy', async () => {
|
||||
// Simulate a healthy provider
|
||||
server.agentState.llmProvider = {
|
||||
provider: 'litellm',
|
||||
health: 'healthy',
|
||||
detail: 'LiteLLM on port 4000',
|
||||
checkedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
const body = JSON.parse(res.payload);
|
||||
|
||||
expect(body.status).toBe('ok');
|
||||
expect(body.llm.provider).toBe('litellm');
|
||||
expect(body.llm.health).toBe('healthy');
|
||||
expect(body.llm.reachable).toBe(true);
|
||||
});
|
||||
|
||||
it('reports a healthy resolved provider as reachable even when the offline probe is stale', async () => {
|
||||
const offlineProbe = server.offlineManager as unknown as { _offline: boolean };
|
||||
const previousOffline = offlineProbe._offline;
|
||||
offlineProbe._offline = true;
|
||||
server.agentState.llmProvider = {
|
||||
provider: 'ollama',
|
||||
health: 'healthy',
|
||||
detail: 'Local Ollama model',
|
||||
checkedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
const body = JSON.parse(res.payload);
|
||||
|
||||
expect(body.status).toBe('ok');
|
||||
expect(body.llm.health).toBe('healthy');
|
||||
expect(body.llm.reachable).toBe(true);
|
||||
} finally {
|
||||
offlineProbe._offline = previousOffline;
|
||||
}
|
||||
});
|
||||
|
||||
it('reports degraded when LLM provider is configured but not verified', async () => {
|
||||
server.agentState.llmProvider = {
|
||||
provider: 'anthropic-proxy',
|
||||
health: 'degraded',
|
||||
detail: 'Built-in Anthropic proxy (no API key)',
|
||||
checkedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
const body = JSON.parse(res.payload);
|
||||
|
||||
expect(body.status).toBe('degraded');
|
||||
expect(body.llm.health).toBe('degraded');
|
||||
});
|
||||
|
||||
it('reports unavailable when no LLM path works', async () => {
|
||||
server.agentState.llmProvider = {
|
||||
provider: 'anthropic-proxy',
|
||||
health: 'unavailable',
|
||||
detail: 'No working LLM path',
|
||||
checkedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const res = await server.inject({ method: 'GET', url: '/health' });
|
||||
const body = JSON.parse(res.payload);
|
||||
|
||||
expect(body.status).toBe('unavailable');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user