v0.32.6_fix2
This commit is contained in:
1 parent
e1ac899ec0
commit
fc8711d4d8
39 files changed
+695
-232
No files matched your search
@@ -0,0 +1,126 @@
|
||||
// Counter-derived chart regression: pauses must not become fake 0/s samples.
|
||||
// Real Cache / Transform chart functions run against simulated DOM and clock.
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import vm from 'node:vm';
|
||||
|
||||
const samplingSource = fs.readFileSync('src/admin/web/app/rate-sampling.js', 'utf8');
|
||||
const panels = {
|
||||
cache: {
|
||||
path: 'src/admin/web/cache-panel.js', stop: ' function configure()',
|
||||
counters: (hit, miss) => ({ hits: hit, misses: miss, bypasses: 0 }),
|
||||
graph: 'cache-live-hit-line', rate: 'cache-live-hit-rate',
|
||||
keys: ['hits', 'misses', 'bypasses'], seconds: 5,
|
||||
},
|
||||
transform: {
|
||||
path: 'src/admin/web/transform-panel.js', stop: ' function countersFor(data)',
|
||||
counters: (hit, miss) => ({ applied: hit, cache_hits: miss, skipped: 0, errors: 0 }),
|
||||
graph: 'transform-live-applied-line', rate: 'transform-live-applied-rate',
|
||||
keys: ['applied', 'cache_hits', 'skipped', 'errors'], seconds: 3,
|
||||
},
|
||||
};
|
||||
|
||||
function fixture(name, config) {
|
||||
const source = fs.readFileSync(config.path, 'utf8');
|
||||
const end = source.indexOf(config.stop);
|
||||
assert(end > 0, `unable to isolate ${name} live chart`);
|
||||
const documentListeners = new Map(), windowListeners = new Map(), nodes = new Map();
|
||||
let now = 1000;
|
||||
const node = id => {
|
||||
if (!nodes.has(id)) nodes.set(id, {
|
||||
value: id.endsWith('-scope') ? '*' : '', textContent: '',
|
||||
attrs: {}, setAttribute(key, value) { this.attrs[key] = value; },
|
||||
});
|
||||
return nodes.get(id);
|
||||
};
|
||||
const document = {
|
||||
hidden: false,
|
||||
addEventListener(name, listener) { documentListeners.set(name, listener); },
|
||||
};
|
||||
const window = {
|
||||
addEventListener(name, listener) { windowListeners.set(name, listener); },
|
||||
rustProxyRefresh: { current: () => ({ overview_seconds: 2, cache_seconds: config.seconds }) },
|
||||
};
|
||||
const ctx = {
|
||||
document, window, $: node, performance: { now: () => now },
|
||||
sparklinePoints: samples => samples.join(','),
|
||||
};
|
||||
vm.createContext(ctx);
|
||||
vm.runInContext(samplingSource, ctx);
|
||||
vm.runInContext(source.slice(0, end) + '\nwindow.liveChartTest = { renderLiveChart, resetLiveChart, liveChartSamples };\n})();', ctx);
|
||||
const chart = window.liveChartTest;
|
||||
const line = () => node(config.graph).attrs.points;
|
||||
const rate = () => node(config.rate).textContent;
|
||||
const length = () => chart.liveChartSamples[config.keys[0]].length;
|
||||
const sample = (stamp, hits, misses) => {
|
||||
now = stamp;
|
||||
chart.renderLiveChart(config.counters(hits, misses));
|
||||
};
|
||||
return { ctx, chart, line, rate, length, sample, document, documentListeners, windowListeners };
|
||||
}
|
||||
|
||||
for (const [name, config] of Object.entries(panels)) {
|
||||
const f = fixture(name, config);
|
||||
f.sample(1000, 100, 50); // no deltas exist before the first observation
|
||||
assert.equal(f.length(), 0, `${name}: first reading is a baseline, not 0/s`);
|
||||
assert.equal(f.rate(), '-');
|
||||
f.sample(1000 + config.seconds * 1000, 130, 65);
|
||||
assert.equal(f.rate(), `${(30 / config.seconds).toFixed(1)}/s`);
|
||||
assert.equal(f.length(), 1);
|
||||
f.sample(1000 + config.seconds * 2000, 130, 65);
|
||||
assert.equal(f.rate(), '0.0/s', `${name}: real idle interval is still zero`);
|
||||
assert.equal(f.length(), 2);
|
||||
|
||||
const graphBefore = f.line();
|
||||
const delayed = 1000 + config.seconds * 2000 + 120000;
|
||||
f.sample(delayed, 500, 200);
|
||||
assert.equal(f.rate(), '-', `${name}: long pause cannot be averaged into a misleading rate`);
|
||||
assert.equal(f.length(), 2, `${name}: do not append fake drop`);
|
||||
assert.equal(f.line(), graphBefore, `${name}: keep old chart path`);
|
||||
f.sample(delayed + config.seconds * 1000, 530, 215);
|
||||
assert.equal(f.rate(), `${(30 / config.seconds).toFixed(1)}/s`, `${name}: next fresh interval resumes`);
|
||||
assert.equal(f.length(), 3);
|
||||
|
||||
f.document.hidden = true;
|
||||
f.documentListeners.get('visibilitychange')?.();
|
||||
f.document.hidden = false;
|
||||
f.documentListeners.get('visibilitychange')?.();
|
||||
const afterBackground = delayed + config.seconds * 1000 + 200;
|
||||
f.sample(afterBackground, 533, 219);
|
||||
assert.equal(f.length(), 3, `${name}: even a short background hide must not append a rate`);
|
||||
assert.equal(f.rate(), '-');
|
||||
f.sample(afterBackground + config.seconds * 1000, 533, 219);
|
||||
assert.equal(f.rate(), '0.0/s', `${name}: genuine zero after resume`);
|
||||
assert.equal(f.length(), 4);
|
||||
|
||||
f.windowListeners.get('pagehide')?.();
|
||||
f.sample(afterBackground + config.seconds * 2000, 540, 220);
|
||||
assert.equal(f.length(), 4, `${name}: pagehide / BFCache must rebase`);
|
||||
f.sample(afterBackground + config.seconds * 3000, 550, 230);
|
||||
assert.equal(f.length(), 5);
|
||||
f.sample(afterBackground + config.seconds * 4000, 1, 1);
|
||||
assert.equal(f.length(), 5, `${name}: counters reset must not be interpreted as 0/s`);
|
||||
f.sample(afterBackground + config.seconds * 5000, 3, 3);
|
||||
assert.equal(f.length(), 6, `${name}: counter reset recovery`);
|
||||
}
|
||||
|
||||
// All remaining rate charts share this exact continuity check, including
|
||||
// configured 30-second Cache refresh (not falsely treated as a pause).
|
||||
{
|
||||
const listeners = new Map(), document = { hidden: false, addEventListener(key, fn) { listeners.set(key, fn); } };
|
||||
const context = { window: {}, document };
|
||||
vm.createContext(context);
|
||||
vm.runInContext(samplingSource, context);
|
||||
const sample = vm.runInContext('rustProxyRateSampling', context);
|
||||
let baseline = sample.difference(null, [100], 1000, 30).next;
|
||||
let value = sample.difference(baseline, [130], 31000, 30);
|
||||
assert.equal(value.deltas[0], 30, '30-second chart interval is valid');
|
||||
baseline = value.next;
|
||||
value = sample.difference(baseline, [200], 124000, 30);
|
||||
assert.equal(value.deltas, null, 'large delay is a gap');
|
||||
document.hidden = true;
|
||||
listeners.get('visibilitychange')?.();
|
||||
document.hidden = false;
|
||||
assert.equal(sample.continuous(value.next, 124001, 30), false, 'hide invalidates even a short elapsed period');
|
||||
}
|
||||
console.log('PASS: Cache/Transform history survives hidden tabs, long pauses, BFCache and counter resets; real 0/s and configured cadence remain intact.');
|
||||
Reference in new issue
Block a user