test: prove reads finish before source synchronization
Conventional commits / commits (pull_request) Successful in 31s
Backend security / security (pull_request) Successful in 9s
Backend verify / verify (pull_request) Successful in 10m47s
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Failing after 12m14s
Conventional commits / commits (pull_request) Successful in 31s
Backend security / security (pull_request) Successful in 9s
Backend verify / verify (pull_request) Successful in 10m47s
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Failing after 12m14s
Block synthetic upstream with an explicit barrier instead of comparing total HTTP batch time with a two-second timer. Keep the 500 ms server p95 gate and RPC assertions unchanged.
This commit was merged in pull request #34.
This commit is contained in:
@@ -70,10 +70,12 @@ describe('T-Bank persisted read budget', () => {
|
||||
}).sort((a, b) => Number(b.date.seconds) - Number(a.date.seconds));
|
||||
const rpc: Record<string, number> = {};
|
||||
let upstreamMode: 'ready' | 'delayed' | 'failed' = 'ready';
|
||||
let sourceGate: Promise<void> | undefined;
|
||||
let releaseSource = () => {};
|
||||
const serverTimes: number[] = [];
|
||||
async function counted<T>(name: string, value: T): Promise<T> {
|
||||
rpc[name] = (rpc[name] ?? 0) + 1;
|
||||
if (upstreamMode === 'delayed') await delay(2000);
|
||||
if (upstreamMode === 'delayed') await sourceGate;
|
||||
if (upstreamMode === 'failed')
|
||||
return Promise.reject(new Error('Synthetic outage'));
|
||||
return Promise.resolve(value);
|
||||
@@ -516,7 +518,8 @@ describe('T-Bank persisted read budget', () => {
|
||||
JSON.stringify(output, null, 2),
|
||||
);
|
||||
console.log(JSON.stringify(output));
|
||||
// Delayed dependency cannot hold a data response or multiply one stale pass.
|
||||
// Hold the source until HTTP reads finish: proves independence without a
|
||||
// wall-clock race against the runner's throughput. The p95 gate stays below.
|
||||
await fresh();
|
||||
await app.get(PrismaService).tbankPortfolio.updateMany({
|
||||
where: { accountId: 'baseline-0' },
|
||||
@@ -524,31 +527,45 @@ describe('T-Bank persisted read budget', () => {
|
||||
});
|
||||
const beforeStale = { ...rpc };
|
||||
upstreamMode = 'delayed';
|
||||
sourceGate = new Promise<void>((resolve) => {
|
||||
releaseSource = resolve;
|
||||
});
|
||||
const startStale = performance.now();
|
||||
await Promise.all(
|
||||
Array.from({ length: 20 }, () =>
|
||||
request(app.getHttpServer())
|
||||
.get('/api/v1/brokerage-accounts/baseline-0/portfolio')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.expect(200),
|
||||
),
|
||||
);
|
||||
try {
|
||||
await Promise.all(
|
||||
Array.from({ length: 20 }, () =>
|
||||
request(app.getHttpServer())
|
||||
.get('/api/v1/brokerage-accounts/baseline-0/portfolio')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.timeout(10_000)
|
||||
.expect(200),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
releaseSource();
|
||||
}
|
||||
const staleResponsesMs = performance.now() - startStale;
|
||||
expect(staleResponsesMs).toBeLessThan(2000);
|
||||
await settled();
|
||||
expect(rpc.portfolio - beforeStale.portfolio).toBe(1);
|
||||
expect(rpc.positions - beforeStale.positions).toBe(1);
|
||||
await app
|
||||
.get(PrismaService)
|
||||
.tbankPortfolio.deleteMany({ where: { accountId: 'baseline-0' } });
|
||||
sourceGate = new Promise<void>((resolve) => {
|
||||
releaseSource = resolve;
|
||||
});
|
||||
const coldStart = performance.now();
|
||||
const missing = await request(app.getHttpServer())
|
||||
.get('/api/v1/brokerage-accounts/baseline-0/portfolio')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.expect(200);
|
||||
expect((missing.body as { data: unknown }).data).toBeNull();
|
||||
try {
|
||||
const missing = await request(app.getHttpServer())
|
||||
.get('/api/v1/brokerage-accounts/baseline-0/portfolio')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.timeout(10_000)
|
||||
.expect(200);
|
||||
expect((missing.body as { data: unknown }).data).toBeNull();
|
||||
} finally {
|
||||
releaseSource();
|
||||
}
|
||||
const coldImportMs = performance.now() - coldStart;
|
||||
expect(coldImportMs).toBeLessThan(2000);
|
||||
await settled();
|
||||
Object.assign(output, {
|
||||
staleResponsesMs,
|
||||
|
||||
Reference in New Issue
Block a user