Files

106 lines
4.8 KiB
JavaScript
Raw Permalink Normal View History

2026-10-29 11:57:29 +01:00
// Generated, do not edit. sha256:9871fb04293a9538a99372a76f6c50a51c7cfcd7eb2971b99eaf20efe539553d
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert/strict';
import { createDbHarness } from '../helpers/db-node.mjs';
const harness = createDbHarness();
mock.module('../../server/db.js', { namedExports: harness.exports });
for (const mod of ['providers', 'price-source', 'price-history', 'api-metrics']) {
mock.module(`../../client/data/${mod}.js`, { namedExports: await import(`../../server/data/${mod}.js`) });
}
const facade = await import('../../client/price/providers.js');
let fetchCalls = [];
globalThis.fetch = async (url, opties) => {
const body = JSON.parse(opties.body);
fetchCalls.push(body.provider.key);
const antwoord = body.date ? { time: Math.floor(Date.parse(`${body.date}T00:00:00Z`) / 1000), price: 60 } : { price: 60 };
return { ok: true, status: 200, json: async () => antwoord };
};
const { run, lastId, one } = harness.exports;
let goud;
const maand = new Date().toISOString().slice(0, 7);
function provider(key, { limiet = null, gebruikt = 0, rang = 1, caps = ['spot', 'history_point'] } = {}) {
run(`INSERT INTO Provider (key, name, searchName, baseUrl, authenticationKind, authenticationRequired,
isActive, isSeed, isSystem, createdAt)
VALUES (?,?,?, 'https://voorbeeld.test','none',0,1,1,0,'2026-09-01T10:00:00.000Z')`, [key, key, key]);
const id = lastId();
run(`INSERT INTO ProviderCoverage (providerId, symbol) VALUES (?, 'XAU')`, [id]);
for (const c of caps) {
run(`INSERT INTO ProviderEndpoint (providerId, capability, method, pathTemplate) VALUES (?, ?, 'GET', '/p')`, [id, c]);
run(`INSERT OR IGNORE INTO PriceSource (assetId, capability, providerId, rank, status)
VALUES (?, ?, ?, ?, 'confirmed')`, [goud, c === 'spot' ? 'spot' : 'history', id, rang]);
}
if (limiet) run(`INSERT INTO ProviderCallLimit (providerId, callsPerMonth, createdAt) VALUES (?, ?, '2026-09-01T00:00:00Z')`, [id, limiet]);
if (gebruikt) {
run(`INSERT INTO ApiCallMetric (providerId, capability, bucketMinute, okCount, failCount, sumLatencyMs, maxLatencyMs)
VALUES (?, 'spot', ?, ?, 0, 0, 0)`, [id, `${maand}-01T00:01`, gebruikt]);
}
return id;
}
const asset = () => one(`SELECT * FROM Asset WHERE id = ?`, [goud]);
beforeEach(() => {
harness.recreate();
facade.clearSpotCache();
facade.forgetSeriesFetches();
facade.forgetUsage();
fetchCalls = [];
run(`INSERT INTO Asset (symbol, name, searchName, kind, unit, subunit, decimals, displayUnit)
VALUES ('XAU','Goud','goud','metal','g','mg',3,'unit')`);
goud = lastId();
});
describe('de maandlimiet', () => {
it('stuurt geen verzoek meer naar een bron op zijn limiet', async () => {
provider('goldapi', { limiet: 100, gebruikt: 100 });
assert.equal(await facade.liveSpotFor(asset()), null);
assert.deepEqual(fetchCalls, [], 'niets naar buiten');
});
it('telt de verzoeken van deze sessie mee, en weigert het eerste boven de limiet', async () => {
provider('goldapi', { limiet: 3, gebruikt: 1 });
for (let i = 0; i < 3; i++) { facade.clearSpotCache(); await facade.liveSpotFor(asset()); }
assert.equal(fetchCalls.length, 2, 'één stond er al, dus nog twee mogen');
});
it('schakelt voor de spot over op de volgende rang', async () => {
provider('goldapi', { limiet: 100, gebruikt: 100, rang: 1 });
provider('reserve', { rang: 2 });
assert.deepEqual(await facade.liveSpotFor(asset()), { price: 60 });
assert.deepEqual(fetchCalls, ['reserve']);
});
});
describe('fillClosesFor met een limiet', () => {
it('gaat na de limiet van rang 1 verder bij rang 2', async () => {
provider('goldapi', { limiet: 1, rang: 1 });
provider('reserve', { rang: 2 });
const uit = await facade.fillClosesFor(asset(), '2026-09-01', '2026-09-03', { today: '2026-09-24' });
assert.deepEqual(fetchCalls, ['goldapi', 'reserve', 'reserve']);
assert.equal(uit.written, 3);
assert.equal(uit.limitReached, false);
});
it('stopt de ronde als geen enkele bron nog tegoed heeft, in plaats van alle dagen af te lopen', async () => {
provider('goldapi', { limiet: 1 });
const uit = await facade.fillClosesFor(asset(), '2026-01-01', '2026-09-01', { today: '2026-09-24' });
assert.deepEqual(fetchCalls, ['goldapi']);
assert.equal(uit.limitReached, true);
assert.ok(uit.requested <= 2, `hij liep ${uit.requested} dagen af`);
});
it('stopt tussen twee dagen als het signaal is afgebroken', async () => {
provider('goldapi');
const stop = new AbortController();
stop.abort();
const uit = await facade.fillClosesFor(asset(), '2026-09-01', '2026-09-10', { today: '2026-09-24', signal: stop.signal });
assert.deepEqual(fetchCalls, []);
assert.equal(uit.stopped, true);
});
});