61 lines
2.9 KiB
JavaScript
61 lines
2.9 KiB
JavaScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { createRequestLogger, ensureSchema, insertRequest, removeNonChatCompletionRequests } from '../src/db.js';
|
|
|
|
describe('request database', () => {
|
|
it('creates the requests table, compatible columns, and recent-request index', async () => {
|
|
const pool = { query: vi.fn().mockResolvedValue({}) };
|
|
|
|
await ensureSchema(pool);
|
|
|
|
expect(pool.query).toHaveBeenCalledTimes(3);
|
|
expect(pool.query.mock.calls[0][0]).toContain('CREATE TABLE IF NOT EXISTS requests');
|
|
expect(pool.query.mock.calls[1][0]).toContain('ADD COLUMN IF NOT EXISTS request_headers');
|
|
expect(pool.query.mock.calls[1][0]).toContain('ADD COLUMN IF NOT EXISTS duration_ms');
|
|
expect(pool.query.mock.calls[1][0]).toContain('ADD COLUMN IF NOT EXISTS training_data');
|
|
expect(pool.query.mock.calls[2][0]).toContain('created_at DESC, id DESC');
|
|
});
|
|
|
|
it('stores request and response data as one row', async () => {
|
|
const pool = { query: vi.fn().mockResolvedValue({}) };
|
|
const entry = {
|
|
method: 'POST', endpoint: '/oai/v1/responses',
|
|
requestHeaders: { host: 'proxy.test' }, requestBody: { model: 'm', input: 'Hi' },
|
|
responseHeaders: { 'content-type': 'application/json' }, responseBody: '{"id":"r1"}',
|
|
responseStatus: 200, durationMs: 123.5, model: 'm', clientIp: '198.51.100.2', stream: false,
|
|
trainingData: { messages: [{ role: 'user', content: 'Hi' }, { role: 'assistant', content: 'Hello' }] },
|
|
};
|
|
|
|
await insertRequest(pool, entry);
|
|
|
|
expect(pool.query).toHaveBeenCalledOnce();
|
|
expect(pool.query.mock.calls[0][0]).toContain('INSERT INTO requests');
|
|
expect(pool.query.mock.calls[0][1]).toEqual([
|
|
'POST', '/oai/v1/responses', '{"host":"proxy.test"}',
|
|
'{"model":"m","input":"Hi"}', '{"content-type":"application/json"}',
|
|
'{"id":"r1"}', 200, 123.5, 'm', '198.51.100.2', false,
|
|
'{"messages":[{"role":"user","content":"Hi"},{"role":"assistant","content":"Hello"}]}',
|
|
]);
|
|
});
|
|
|
|
it('removes requests that are not for the chat completions endpoint', async () => {
|
|
const pool = { query: vi.fn().mockResolvedValue({ rowCount: 4 }) };
|
|
|
|
await expect(removeNonChatCompletionRequests(pool)).resolves.toBe(4);
|
|
|
|
expect(pool.query).toHaveBeenCalledOnce();
|
|
expect(pool.query.mock.calls[0][0]).toContain("split_part(endpoint, '?', 1) <> ALL($1::text[])");
|
|
expect(pool.query.mock.calls[0][1]).toEqual([[
|
|
'/oai/v1/chat/completions', '/oai/v1/responses',
|
|
'/ant/v1/messages', '/ant/v1/v1/messages',
|
|
]]);
|
|
});
|
|
|
|
it('reports storage failures without rejecting request handling', async () => {
|
|
const onError = vi.fn();
|
|
const logger = createRequestLogger({ query: vi.fn().mockRejectedValue(new Error('database offline')) }, { onError });
|
|
|
|
await expect(logger.log({ method: 'GET', endpoint: '/', responseStatus: 200 })).resolves.toBeUndefined();
|
|
expect(onError).toHaveBeenCalledWith('Failed to store request: database offline');
|
|
});
|
|
});
|