feat: add hourly portfolio sync history
This commit is contained in:
@@ -204,27 +204,28 @@ describe('durable shared instrument metadata (SQLite)', () => {
|
||||
await settled();
|
||||
expect((await service.read('other', identity, true))?.data).toEqual(known);
|
||||
});
|
||||
it('keeps last good metadata and source time after refresh failure; stale observation does not restart work', async () => {
|
||||
it('keeps last good metadata and source time after refresh failure; observation does not restart work', async () => {
|
||||
await service.read('owner', identity);
|
||||
await settled();
|
||||
const old = new Date(Date.now() - 86_400_000);
|
||||
const old = new Date(Date.now() - 10 * 86_400_000);
|
||||
await prisma.tbankInstrumentLookup.updateMany({ data: { fetchedAt: old } });
|
||||
await prisma.tbankInstrument.updateMany({ data: { fetchedAt: old } });
|
||||
const calls = upstream.getInstrumentByUid.mock.calls.length;
|
||||
expect((await service.read('owner', identity, true))?.fresh).toBe(false);
|
||||
expect((await service.read('owner', identity, true))?.fresh).toBe(true);
|
||||
expect(upstream.getInstrumentByUid).toHaveBeenCalledTimes(calls);
|
||||
const failedHandle = await service.request('owner', 'owner-revision', identity, true);
|
||||
upstream.getInstrumentByUid.mockRejectedValueOnce(
|
||||
new Error('upstream unavailable'),
|
||||
);
|
||||
upstream.getInstrumentByFigi.mockRejectedValueOnce(
|
||||
new Error('upstream unavailable'),
|
||||
);
|
||||
await service.read('owner', identity);
|
||||
await settled();
|
||||
const failed = await service.read('owner', identity, true);
|
||||
expect(failed?.data).toEqual(known);
|
||||
expect(failed?.fetchedAt).toEqual(old);
|
||||
expect(failed?.work?.state).toBe('failed');
|
||||
if (!failedHandle) throw new Error('Expected forced refresh work');
|
||||
expect((await prisma.tbankSyncWork.findUniqueOrThrow({ where: { id: failedHandle } })).state).toBe('failed');
|
||||
await delay(20);
|
||||
expect(upstream.getInstrumentByUid).toHaveBeenCalledTimes(calls + 1);
|
||||
});
|
||||
@@ -252,20 +253,18 @@ describe('durable shared instrument metadata (SQLite)', () => {
|
||||
expect(after?.work?.state).toBe('failed');
|
||||
expect(upstream.getInstrumentByUid).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
it('uses the exact daily TTL boundary and does not count another instrument as covered', async () => {
|
||||
it('keeps saved metadata fresh and does not count another instrument as covered', async () => {
|
||||
await service.read('owner', identity);
|
||||
await settled();
|
||||
const timestamp = new Date('2026-09-01Z');
|
||||
await prisma.tbankInstrumentLookup.updateMany({
|
||||
data: { fetchedAt: timestamp },
|
||||
});
|
||||
const clock = jest
|
||||
.spyOn(Date, 'now')
|
||||
.mockReturnValue(timestamp.valueOf() + 86_400_000 - 1);
|
||||
const clock = jest.spyOn(Date, 'now').mockReturnValue(timestamp.valueOf());
|
||||
try {
|
||||
expect((await service.read('owner', identity, true))?.fresh).toBe(true);
|
||||
clock.mockReturnValue(timestamp.valueOf() + 86_400_000);
|
||||
expect((await service.read('owner', identity, true))?.fresh).toBe(false);
|
||||
clock.mockReturnValue(timestamp.valueOf() + 10 * 86_400_000);
|
||||
expect((await service.read('owner', identity, true))?.fresh).toBe(true);
|
||||
expect(
|
||||
(await service.read('owner', { instrumentUid: 'other-uid' }, true))
|
||||
?.complete,
|
||||
|
||||
Reference in New Issue
Block a user