computer: fixes

This commit is contained in:
nym21
2026-03-23 00:39:15 +01:00
parent 514b0513de
commit fef7a24951
4 changed files with 189 additions and 36 deletions

View File

@@ -0,0 +1,132 @@
/**
* Consistency test: verifies that all series sharing the same index have the same length.
* Useful for catching stale/inconsistent state after a reorg rollback.
*/
import { BrkClient } from "../index.js";
/**
* @typedef {import('../index.js').AnySeriesPattern} AnyMetricPattern
*/
/**
* @param {any} obj
* @returns {obj is AnyMetricPattern}
*/
function isMetricPattern(obj) {
return (
obj &&
typeof obj === "object" &&
typeof obj.indexes === "function" &&
obj.by &&
typeof obj.by === "object"
);
}
/**
* Recursively collect all metric patterns from the tree.
* @param {Record<string, any>} obj
* @param {string} path
* @returns {Array<{path: string, metric: AnyMetricPattern}>}
*/
function getAllMetrics(obj, path = "") {
/** @type {Array<{path: string, metric: AnyMetricPattern}>} */
const metrics = [];
for (const key of Object.keys(obj)) {
const attr = obj[key];
if (!attr || typeof attr !== "object") continue;
const currentPath = path ? `${path}.${key}` : key;
if (isMetricPattern(attr)) {
metrics.push({ path: currentPath, metric: attr });
}
if (typeof attr === "object" && !Array.isArray(attr)) {
metrics.push(...getAllMetrics(attr, currentPath));
}
}
return metrics;
}
async function testConsistency() {
const client = new BrkClient({
baseUrl: "http://localhost:3110",
timeout: 15000,
});
const metrics = getAllMetrics(client.series);
console.log(`\nFound ${metrics.length} metrics`);
/** @type {Map<string, Array<{path: string, total: number}>>} */
const byIndex = new Map();
for (const { path, metric } of metrics) {
const indexes = metric.indexes();
for (const idxName of indexes) {
const fullPath = `${path}.by.${idxName}`;
const endpoint = metric.by[idxName];
if (!endpoint) {
console.log(`SKIP: ${fullPath} (undefined endpoint)`);
continue;
}
try {
const result = await endpoint.last(0);
const total = result.total;
if (!byIndex.has(idxName)) {
byIndex.set(idxName, []);
}
byIndex.get(idxName).push({ path: fullPath, total });
} catch (e) {
console.log(
`FAIL: ${fullPath} -> ${e instanceof Error ? e.message : e}`,
);
return;
}
}
}
let failed = false;
for (const [index, entries] of byIndex) {
const totals = new Set(entries.map((e) => e.total));
if (totals.size === 1) {
const [total] = totals;
console.log(`OK: ${index}${entries.length} series, all length ${total}`);
continue;
}
failed = true;
console.log(`\nMISMATCH: ${index}${entries.length} series with ${totals.size} different lengths:`);
/** @type {Map<number, string[]>} */
const grouped = new Map();
for (const { path, total } of entries) {
if (!grouped.has(total)) grouped.set(total, []);
grouped.get(total).push(path);
}
for (const [total, paths] of [...grouped].sort((a, b) => b[0] - a[0])) {
console.log(` length ${total}: (${paths.length} series)`);
for (const p of paths) {
console.log(` ${p}`);
}
}
}
if (failed) {
console.log("\nFAILED: length mismatches detected");
process.exit(1);
} else {
console.log("\nPASSED: all indexes consistent");
}
}
testConsistency();