a lot
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { createKeyRotator, parseKeys } from '../src/key-store.js';
|
||||
import { createKeyRotator, loadConfiguredKeys, parseKeys, parseKeysJson } from '../src/key-store.js';
|
||||
|
||||
describe('key store', () => {
|
||||
it('parses JSON keys and prefers the environment variable', async () => {
|
||||
expect(parseKeysJson('[" a ","b"]')).toEqual(['a', 'b']);
|
||||
expect(() => parseKeysJson('{"key":"a"}')).toThrow();
|
||||
await expect(loadConfiguredKeys({ env: { OPENCODE_API_KEYS: '["env-key"]' }, path: '/does-not-exist' })).resolves.toEqual(['env-key']);
|
||||
});
|
||||
|
||||
it('parses keys, blank lines, and comments', () => {
|
||||
expect(parseKeys(' first \n\nsecond # note\n# ignored\n')).toEqual(['first', 'second']);
|
||||
});
|
||||
|
||||
@@ -58,6 +58,24 @@ describe('proxy', () => {
|
||||
expect(JSON.parse(fetchImpl.mock.calls[0][1].body)).toEqual(body);
|
||||
});
|
||||
|
||||
it('enforces the configured context and IP limits and records cost', async () => {
|
||||
const fetchImpl = vi.fn()
|
||||
.mockResolvedValueOnce(response(JSON.stringify({ id: 'c', cost: 0 })))
|
||||
.mockResolvedValue(response(JSON.stringify({ id: 'c', cost: 10 })));
|
||||
const app = createProxyApp({ keys: ['key'], fetchImpl, maxContextTokens: 100 });
|
||||
await request(app).post('/oai/v1/chat/completions').set('X-Real-IP', '198.51.100.1').send({ model: 'm', max_tokens: 101 }).expect(400);
|
||||
await request(app).post('/oai/v1/chat/completions').set('X-Real-IP', '198.51.100.1').send({ model: 'm', max_tokens: 1 }).expect(200);
|
||||
await request(app).post('/oai/v1/chat/completions').set('X-Real-IP', '198.51.100.1').send({ model: 'm', max_tokens: 1 }).expect(200);
|
||||
await request(app).post('/oai/v1/chat/completions').set('X-Real-IP', '198.51.100.1').send({ model: 'm', max_tokens: 1 }).expect(429);
|
||||
});
|
||||
|
||||
it('adds the global context limit to model listings', async () => {
|
||||
const fetchImpl = vi.fn().mockResolvedValue(response('{"data":[{"id":"m"}]}'));
|
||||
const app = createProxyApp({ keys: ['key'], fetchImpl, maxContextTokens: 123 });
|
||||
const result = await request(app).get('/oai/v1/models').expect(200);
|
||||
expect(result.body.data[0]).toMatchObject({ context_length: 123, context_window: 123, max_context_tokens: 123 });
|
||||
});
|
||||
|
||||
it('passes through streaming responses', async () => {
|
||||
const fetchImpl = vi.fn().mockResolvedValue(response('data: {"delta":"Hi"}\n\ndata: [DONE]\n\n', {
|
||||
headers: { 'content-type': 'text/event-stream' },
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { createRateLimiter } from '../src/rate-limit.js';
|
||||
|
||||
describe('rate limiter', () => {
|
||||
it('enforces request and spend windows', () => {
|
||||
let time = 0;
|
||||
const limiter = createRateLimiter({ now: () => time });
|
||||
expect(limiter.check('ip').allowed).toBe(true);
|
||||
expect(limiter.check('ip').allowed).toBe(true);
|
||||
expect(limiter.check('ip').allowed).toBe(false);
|
||||
time = 1_001;
|
||||
expect(limiter.check('ip').allowed).toBe(true);
|
||||
limiter.recordCost('ip', 10);
|
||||
expect(limiter.check('ip').allowed).toBe(false);
|
||||
time = 5 * 60 * 60 * 1_000 + 1_002;
|
||||
expect(limiter.check('ip').allowed).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps clients independent', () => {
|
||||
const limiter = createRateLimiter();
|
||||
expect(limiter.check('a').allowed).toBe(true);
|
||||
expect(limiter.check('a').allowed).toBe(true);
|
||||
expect(limiter.check('a').allowed).toBe(false);
|
||||
expect(limiter.check('b').allowed).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user