fix: scope income and ledger sync to requested intervals (WealthLedger/backend#57)
This commit is contained in:
@@ -297,6 +297,58 @@ describe('local income completeness and exact money (SQLite)', () => {
|
||||
expect(result.data?.calculatedAt).toBe('2025-02-01T00:00:00.000Z');
|
||||
expect(upstream.getOperationsByCursor).not.toHaveBeenCalled();
|
||||
});
|
||||
it('ordinary covered income reads local data without membership or operations RPC', async () => {
|
||||
await prisma.tbankConnection.update({
|
||||
where: { userId: 'income-owner' },
|
||||
data: { membershipAt: new Date('2020-01-01Z') },
|
||||
});
|
||||
const response = await get('a', undefined, false).expect(200);
|
||||
const result = response.body as IncomeAnalyticsResourceDto;
|
||||
expect(result.data).not.toBeNull();
|
||||
expect(result.meta.completeness).toBe('complete');
|
||||
expect(upstream.getOpenAccounts).not.toHaveBeenCalled();
|
||||
expect(upstream.getOperationsByCursor).not.toHaveBeenCalled();
|
||||
});
|
||||
it('cold income imports only the missing requested interval', async () => {
|
||||
await prisma.tbankConnection.update({
|
||||
where: { userId: 'income-owner' },
|
||||
data: { membershipAt: new Date('2020-01-01Z') },
|
||||
});
|
||||
let release: () => void = () => {
|
||||
throw new Error('Upstream not initialized');
|
||||
};
|
||||
const blocked = new Promise<{ hasNext: boolean; items: never[] }>((resolve) => {
|
||||
release = () => resolve({ hasNext: false, items: [] });
|
||||
});
|
||||
upstream.getOperationsByCursor.mockReturnValue(blocked);
|
||||
const first = await get('a', 'from=2025-02-01&to=2025-02-28', false).expect(200);
|
||||
const cold = first.body as IncomeAnalyticsResourceDto;
|
||||
release();
|
||||
expect(cold.data).toBeNull();
|
||||
expect(cold.meta.completeness).toBe('incomplete');
|
||||
let result: IncomeAnalyticsResourceDto = cold;
|
||||
for (let attempt = 0; attempt < 100; attempt++) {
|
||||
const response = await get('a', 'from=2025-02-01&to=2025-02-28').expect(200);
|
||||
result = response.body as IncomeAnalyticsResourceDto;
|
||||
if (result.meta.completeness === 'complete') break;
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
}
|
||||
expect(result.data).not.toBeNull();
|
||||
expect(result.meta.completeness).toBe('complete');
|
||||
expect(upstream.getOpenAccounts).not.toHaveBeenCalled();
|
||||
expect(upstream.getOperationsByCursor.mock.calls).toEqual([
|
||||
['synthetic', expect.objectContaining({
|
||||
accountId: 'a',
|
||||
from: { seconds: '1738357199' },
|
||||
to: { seconds: '1738368001' },
|
||||
})],
|
||||
['synthetic', expect.objectContaining({
|
||||
accountId: 'a',
|
||||
from: { seconds: '1738367999' },
|
||||
to: { seconds: '1740776401' },
|
||||
})],
|
||||
]);
|
||||
});
|
||||
it('returns while a cold upstream is blocked and validates access/period before scheduling', async () => {
|
||||
await get('absent', undefined, false).expect(404);
|
||||
await get('a', 'from=2025-02-31&to=2025-03-01', false).expect(400);
|
||||
|
||||
Reference in New Issue
Block a user