Session 20: Provider intelligence — quota tracker, gateway with fallback cascade, admin quota dashboard (1476 tests)
This commit is contained in:
@@ -14,6 +14,11 @@ jest.mock('../../scripts/tank01-prefetch', () => ({
|
||||
}));
|
||||
const tank01Prefetch = require('../../scripts/tank01-prefetch');
|
||||
|
||||
jest.mock('../../src/services/quotaTracker', () => ({
|
||||
getAllQuotaStatuses: jest.fn(),
|
||||
}));
|
||||
const quotaTracker = require('../../src/services/quotaTracker');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
process.env.VYNDR_INTERNAL_KEY = 'test-internal-key-9999';
|
||||
@@ -98,3 +103,37 @@ describe('POST /api/internal/prefetch/tank01', () => {
|
||||
expect(argv).toContain('--sports=mlb');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/internal/quota (Session 20)', () => {
|
||||
test('rejects without the internal key', async () => {
|
||||
const app = mountApp();
|
||||
const res = await request(app).get('/api/internal/quota');
|
||||
expect(res.status).toBe(401);
|
||||
expect(quotaTracker.getAllQuotaStatuses).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('returns the per-provider snapshot when keyed', async () => {
|
||||
const fakeSnapshot = [
|
||||
{ provider: 'odds-api', name: 'The Odds API', used: 487, limit: 500, remaining: 13, pct: 0.974, allowed: false, period: '2026-06', quotaType: 'monthly' },
|
||||
{ provider: 'tank01', name: 'Tank01', used: 30, limit: 1000, remaining: 970, pct: 0.03, allowed: true, period: '2026-06', quotaType: 'monthly' },
|
||||
];
|
||||
quotaTracker.getAllQuotaStatuses.mockResolvedValueOnce(fakeSnapshot);
|
||||
|
||||
const app = mountApp();
|
||||
const res = await request(app)
|
||||
.get('/api/internal/quota')
|
||||
.set('x-internal-key', 'test-internal-key-9999');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toEqual({ ok: true, providers: fakeSnapshot });
|
||||
});
|
||||
|
||||
test('returns 500 with the underlying error when the tracker throws', async () => {
|
||||
quotaTracker.getAllQuotaStatuses.mockRejectedValueOnce(new Error('redis down'));
|
||||
const app = mountApp();
|
||||
const res = await request(app)
|
||||
.get('/api/internal/quota')
|
||||
.set('x-internal-key', 'test-internal-key-9999');
|
||||
expect(res.status).toBe(500);
|
||||
expect(res.body).toEqual({ ok: false, error: 'redis down' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,13 @@ const mockRedis = {
|
||||
};
|
||||
jest.mock('../../src/utils/redis', () => ({
|
||||
getRedisClient: () => mockRedis,
|
||||
// Session 20 — provider gateway pulls cacheGet/cacheSet/isDegraded.
|
||||
// Degraded mode lets every call through and skips Redis writes, so
|
||||
// the existing axios-mock assertions stay accurate.
|
||||
cacheGet: jest.fn(async () => null),
|
||||
cacheSet: jest.fn(async () => true),
|
||||
cacheDel: jest.fn(async () => true),
|
||||
isDegraded: jest.fn(() => true),
|
||||
}));
|
||||
|
||||
// Mock axios
|
||||
|
||||
Reference in New Issue
Block a user