Sessions 5-7a: 955 tests, deployment ready

This commit is contained in:
Kev
2026-06-08 18:35:13 -04:00
parent 06b82624a2
commit 1fa04dc776
371 changed files with 49366 additions and 955 deletions
+120
View File
@@ -0,0 +1,120 @@
process.env.VYNDR_INTERNAL_KEY = 'health-test-key';
const mockPing = jest.fn();
jest.mock('../../src/utils/redis', () => ({
getRedisClient: () => ({ ping: mockPing }),
isDegraded: () => false,
cacheGet: async () => null,
cacheSet: async () => true,
cacheDel: async () => true,
}));
const mockSupabaseLimit = jest.fn();
jest.mock('../../src/utils/supabase', () => ({
getSupabaseServiceClient: () => ({
from() {
const proxy = {
select() { return proxy; },
limit() { return mockSupabaseLimit(); },
};
return proxy;
},
}),
}));
const mockAxiosGet = jest.fn();
jest.mock('axios', () => ({ get: (...args) => mockAxiosGet(...args), post: jest.fn() }));
// Adapter configured() helpers — fixed boolean returns are enough for the
// detailed branch assertions.
jest.mock('../../src/services/adapters/sharpApiAdapter', () => ({ configured: () => true }));
jest.mock('../../src/services/adapters/propOddsAdapter', () => ({ configured: () => false }));
jest.mock('../../src/services/adapters/parlayApiAdapter', () => ({ configured: () => true }));
jest.mock('../../src/services/adapters/oddsPapiAdapter', () => ({ configured: () => false }));
jest.mock('../../src/services/adapters/cfbdAdapter', () => ({ configured: () => false }));
jest.mock('../../src/services/adapters/openRouterAdapter', () => ({ configured: () => true }));
const app = require('../../src/app');
const http = require('http');
function call(path, headers = {}) {
return new Promise((resolve) => {
const server = app.listen(0, '127.0.0.1', () => {
const port = server.address().port;
const req = http.request({ host: '127.0.0.1', port, path, method: 'GET', headers }, (res) => {
const chunks = [];
res.on('data', (c) => chunks.push(c));
res.on('end', () => {
server.close();
const raw = Buffer.concat(chunks).toString('utf8');
let parsed; try { parsed = JSON.parse(raw); } catch { parsed = raw; }
resolve({ status: res.statusCode, body: parsed });
});
});
req.end();
});
});
}
beforeEach(() => {
mockPing.mockReset();
mockSupabaseLimit.mockReset();
mockAxiosGet.mockReset();
});
describe('GET /api/health', () => {
test('public response is minimal when no internal key', async () => {
mockPing.mockResolvedValue('PONG');
mockSupabaseLimit.mockResolvedValue({ error: null });
const res = await call('/api/health');
expect(res.status).toBe(200);
expect(res.body).toEqual({ status: 'healthy' });
});
test('reports 503 when Redis is down', async () => {
mockPing.mockRejectedValue(new Error('econnrefused'));
mockSupabaseLimit.mockResolvedValue({ error: null });
const res = await call('/api/health');
expect(res.status).toBe(503);
expect(res.body.status).toBe('degraded');
});
test('reports 503 when Supabase errors', async () => {
mockPing.mockResolvedValue('PONG');
mockSupabaseLimit.mockResolvedValue({ error: { message: 'bad' } });
const res = await call('/api/health');
expect(res.status).toBe(503);
});
test('detailed branch with valid internal key includes adapters + python', async () => {
mockPing.mockResolvedValue('PONG');
mockSupabaseLimit.mockResolvedValue({ error: null });
mockAxiosGet.mockResolvedValue({ status: 200, data: { status: 'ok' } });
const res = await call('/api/health', { 'x-vyndr-internal-key': 'health-test-key' });
expect(res.status).toBe(200);
expect(res.body.checks.python).toBe('ok');
expect(res.body.checks.adapters).toMatchObject({
sharpapi: true,
propodds: false,
openrouter: true,
});
expect(typeof res.body.uptime).toBe('number');
});
test('wrong internal key falls through to public response', async () => {
mockPing.mockResolvedValue('PONG');
mockSupabaseLimit.mockResolvedValue({ error: null });
const res = await call('/api/health', { 'x-vyndr-internal-key': 'wrong' });
expect(res.body).toEqual({ status: 'healthy' });
expect(res.body.checks).toBeUndefined();
});
test('python down does not flip overall status (Python is optional)', async () => {
mockPing.mockResolvedValue('PONG');
mockSupabaseLimit.mockResolvedValue({ error: null });
mockAxiosGet.mockRejectedValue(new Error('refused'));
const res = await call('/api/health', { 'x-vyndr-internal-key': 'health-test-key' });
expect(res.status).toBe(200);
expect(res.body.checks.python).toBe('down');
});
});