unrip/test/postgres-quote-lifecycle-statistics.test.mjs
philipp 8361defa53
All checks were successful
deploy / deploy (push) Successful in 50s
Fix quote statistics refresh collapse
Proof: reproduced live quote lifecycle statistics refresh stalling while persisted subject and window counts remained nonzero; fixed refresh to incrementally scan recent durable source evidence from the retained subject table, canonicalized statistic window ids, de-duped duplicate persisted grain/window rows on load, and validated with targeted stats/dashboard tests, full npm test, and dashboard bundle build.

Assumptions: quote lifecycle statistics are durable retained unique quote subjects, and a 5 minute source overlap is enough to catch ordinary insert/refresh races without re-reading the whole retained history on every dashboard refresh.

Still fake: this does not create venue-native fill truth where no durable settlement evidence exists, does not repair WebSocket client backpressure from high live quote volume, and does not reconstruct pruned raw quote detail.
2026-06-14 20:56:32 +02:00

194 lines
6.6 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
buildQuoteLifecycleStatistics,
} from '../src/core/quote-lifecycle-statistics.mjs';
import {
loadQuoteLifecycleStatistics,
refreshQuoteLifecycleStatistics,
} from '../src/lib/postgres.mjs';
test('postgres quote lifecycle statistics refresh idempotently upserts state buckets by original quote window', async () => {
const upserts = [];
const subjects = new Map();
const issuedSql = [];
let includeFailure = false;
const pool = {
async query(sql, params = []) {
issuedSql.push(sql);
if (sql.includes('MAX(updated_at) AS latest_subject_updated_at')) {
return {
rows: [{
has_statistic_subjects: subjects.size > 0,
latest_subject_updated_at: subjects.size ? '2026-06-12T17:32:00.000Z' : null,
}],
};
}
if (sql.includes('INSERT INTO quote_lifecycle_stat_subjects')) {
subjects.set('quote-stat', {
quote_id: 'quote-stat',
quote_activity_at: '2026-06-12T17:31:01.000Z',
latest_stage_at: includeFailure
? '2026-06-12T17:36:10.000Z'
: '2026-06-12T17:31:03.000Z',
statistics_bucket: includeFailure ? 'submission_failed' : 'awaiting_executor',
lifecycle_state: includeFailure ? 'failed' : 'command_emitted',
reason_code: includeFailure ? 'quote_not_found_or_finished' : 'awaiting_executor',
});
if (subjects.size > 0 && includeFailure) {
assert.equal(params[1], '2026-06-12T17:27:00.000Z');
}
return { rows: [], rowCount: 1 };
}
if (sql.includes('SELECT COUNT(*)::INT AS subject_count')) {
return { rows: [{ subject_count: subjects.size }] };
}
if (sql.includes('WITH subjects AS')) {
return {
rows: buildQuoteLifecycleStatistics({
lifecycleRows: [...subjects.values()],
grains: params[0],
computedAt: params[1],
}),
};
}
if (sql.includes('INSERT INTO quote_lifecycle_statistics')) {
upserts.push({ sql, params });
return { rows: [], rowCount: 1 };
}
throw new Error(`unexpected query: ${sql}`);
},
};
await refreshQuoteLifecycleStatistics(pool, {
now: '2026-06-12T17:32:00.000Z',
});
includeFailure = true;
await refreshQuoteLifecycleStatistics(pool, {
now: '2026-06-12T17:37:00.000Z',
});
const fiveMinuteUpserts = upserts.filter((query) => (
query.params[1] === 'five_minute'
&& query.params[2] === '2026-06-12T17:30:00.000Z'
));
assert.equal(fiveMinuteUpserts.length, 2);
assert.equal(fiveMinuteUpserts.at(-1).params[4], 1);
const latestBuckets = JSON.parse(fiveMinuteUpserts.at(-1).params[7]);
assert.equal(latestBuckets.submission_failed, 1);
assert.equal(latestBuckets.awaiting_executor, 0);
assert.equal(
upserts.some((query) => (
query.params[1] === 'five_minute'
&& query.params[2] === '2026-06-12T17:35:00.000Z'
)),
false,
);
assert.equal(
issuedSql.some((sql) => sql.includes('ORDER BY COALESCE') && sql.includes('FROM swap_demand_events')),
false,
);
assert.equal(
issuedSql.some((sql) => sql.includes('COALESCE(ingested_at, observed_at) >= $2::timestamptz')),
true,
);
});
test('postgres quote lifecycle statistics retain per-quote buckets after detail pruning', async () => {
const subjects = new Map();
const allTimeUpserts = [];
let sourceAvailable = true;
const pool = {
async query(sql, params = []) {
if (sql.includes('MAX(updated_at) AS latest_subject_updated_at')) {
return {
rows: [{
has_statistic_subjects: subjects.size > 0,
latest_subject_updated_at: subjects.size ? '2026-06-12T14:12:00.000Z' : null,
}],
};
}
if (sql.includes('INSERT INTO quote_lifecycle_stat_subjects')) {
if (sourceAvailable) {
subjects.set('quote-completed', {
quote_id: 'quote-completed',
quote_activity_at: '2026-06-12T14:11:01.000Z',
latest_stage_at: '2026-06-12T14:11:10.000Z',
statistics_bucket: 'success',
lifecycle_state: 'completed',
reason_code: 'completed',
});
}
return { rows: [], rowCount: sourceAvailable ? 1 : 0 };
}
if (sql.includes('SELECT COUNT(*)::INT AS subject_count')) {
return { rows: [{ subject_count: subjects.size }] };
}
if (sql.includes('WITH subjects AS')) {
return {
rows: buildQuoteLifecycleStatistics({
lifecycleRows: [...subjects.values()],
grains: params[0],
computedAt: params[1],
}),
};
}
if (sql.includes('INSERT INTO quote_lifecycle_statistics')) {
if (params[1] === 'all_time') allTimeUpserts.push({ params });
return { rows: [], rowCount: 1 };
}
throw new Error(`unexpected query: ${sql}`);
},
};
await refreshQuoteLifecycleStatistics(pool, {
now: '2026-06-12T14:12:00.000Z',
});
sourceAvailable = false;
await refreshQuoteLifecycleStatistics(pool, {
now: '2026-06-12T15:12:00.000Z',
});
assert.equal(allTimeUpserts.length, 2);
assert.equal(allTimeUpserts[0].params[4], 1);
assert.equal(JSON.parse(allTimeUpserts[0].params[7]).success, 1);
assert.equal(allTimeUpserts[1].params[4], 1);
assert.equal(JSON.parse(allTimeUpserts[1].params[7]).success, 1);
});
test('postgres quote lifecycle statistics loader returns all-time and clamped grain rows', async () => {
let issuedSql = '';
const pool = {
async query(sql, params = []) {
issuedSql = sql;
assert.match(sql, /FROM quote_lifecycle_statistics/);
assert.deepEqual(params, [['all_time', 'five_minute'], 2]);
return {
rows: [{
stat_id: 'quote-lifecycle-stat:all_time:all',
grain: 'all_time',
window_start: null,
window_end: null,
quote_count: 3,
missing_identifier_count: 1,
missing_timestamp_count: 0,
bucket_counts: { success: 1, submission_failed: 2 },
computed_at: '2026-06-12T17:40:00.000Z',
}],
};
},
};
const rows = await loadQuoteLifecycleStatistics(pool, {
grains: ['all_time', 'five_minute'],
limit: 2,
});
assert.equal(rows.length, 1);
assert.equal(rows[0].quote_count, 3);
assert.equal(rows[0].bucket_counts.success, 1);
assert.equal(rows[0].bucket_counts.submitted_no_reply, 0);
assert.match(issuedSql, /PARTITION BY grain, window_start, window_end/);
assert.match(issuedSql, /duplicate_rank = 1/);
});