Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6126a7f85c |
@@ -105,9 +105,9 @@ code lives in `src/main.js` with a class-based architecture:
|
|||||||
- **UI functions**: `buildUI()` constructs the DOM, `updateHostRow()` /
|
- **UI functions**: `buildUI()` constructs the DOM, `updateHostRow()` /
|
||||||
`updateSummary()` / `updateHealthBox()` handle incremental updates
|
`updateSummary()` / `updateHealthBox()` handle incremental updates
|
||||||
- **`tick()`**: Main loop — measures all hosts in parallel, pushing each host's
|
- **`tick()`**: Main loop — measures all hosts in parallel, pushing each host's
|
||||||
sample and redrawing its row as soon as its check ends, then sorts and redraws
|
sample and redrawing its row as soon as its check ends, then redraws every
|
||||||
the summary and health box once the last check ends. When paused, pushes blank
|
row, sorts, and redraws the summary and health box once the last check ends.
|
||||||
markers (no probes, no false outage)
|
When paused, pushes blank markers (no probes, no false outage)
|
||||||
- **`Reporter`**: Posts collected samples to the backend
|
- **`Reporter`**: Posts collected samples to the backend
|
||||||
|
|
||||||
### Reporting
|
### Reporting
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ latest run passes.
|
|||||||
|
|
||||||
- 2026-10-03: each target's row shows its result as soon as its check ends
|
- 2026-10-03: each target's row shows its result as soon as its check ends
|
||||||
(issue #91), where every row waited for the round's slowest check, up to 24
|
(issue #91), where every row waited for the round's slowest check, up to 24
|
||||||
seconds at a 30-second interval. Sorting, the summary, the health box and
|
seconds at a 30-second interval. Every row is still redrawn, and sorting, the
|
||||||
offline detection still run once, when the round's last check ends. A check
|
summary, the health box and offline detection still run, once, when the
|
||||||
that ends after the user pauses or after its round is given up shows nothing,
|
round's last check ends, so no row reads "paused" after a pause and resume
|
||||||
and the first round is still discarded as a whole
|
during the round. A check that ends after the user pauses or after its round
|
||||||
|
is given up shows nothing, and the first round is still discarded as a whole
|
||||||
- 2026-10-03: the Go tests run with the race detector and coverage (issue #88):
|
- 2026-10-03: the Go tests run with the race detector and coverage (issue #88):
|
||||||
`backend/script/test` runs `go test -timeout 30s -race -cover ./...` and, if
|
`backend/script/test` runs `go test -timeout 30s -race -cover ./...` and, if
|
||||||
that fails, runs it again with `-v` and fails. Go's `-timeout` bounds the
|
that fails, runs it again with `-v` and fails. Go's `-timeout` bounds the
|
||||||
|
|||||||
@@ -1156,6 +1156,10 @@ export async function tick(state, signal, onOffline) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redraw every row: if the user paused and resumed during this round,
|
||||||
|
// rows whose check ended before the resume still read "paused"
|
||||||
|
state.allHosts.forEach((host, i) => updateHostRow(host, i));
|
||||||
|
|
||||||
// Sort after the first real check, then every 10 ticks thereafter
|
// Sort after the first real check, then every 10 ticks thereafter
|
||||||
if (state.tickCount === 2 || state.tickCount % 10 === 1) {
|
if (state.tickCount === 2 || state.tickCount % 10 === 1) {
|
||||||
sortAndRebuildWAN(state);
|
sortAndRebuildWAN(state);
|
||||||
|
|||||||
+61
-5
@@ -1,16 +1,20 @@
|
|||||||
// Unit tests for src/main.js, run by script/frontend-test with Node's
|
// Unit tests for src/main.js, run by script/frontend-test with Node's
|
||||||
// built-in test runner. Importing the module does not start the page.
|
// built-in test runner. Importing the module does not start the page.
|
||||||
|
|
||||||
import { test } from "node:test";
|
import { beforeEach, test } from "node:test";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { AppState, CONFIG, measureLatency, tick } from "../../src/main.js";
|
import { AppState, CONFIG, measureLatency, tick } from "../../src/main.js";
|
||||||
|
|
||||||
// There is no page here, so the tests stand in for it. The debug log looks
|
// There is no page here, so the tests stand in for it. The debug log looks
|
||||||
// for its panel by id and finds none. Each element of a host's row that
|
// for its panel by id and finds none. Each element of a host's row that
|
||||||
// tick draws into is a plain object, made the first time it is looked up
|
// tick draws into is a plain object, made the first time a test looks it
|
||||||
// and kept in elements under its selector. Drawing a sparkline does
|
// up and kept in elements under its selector until the next test starts.
|
||||||
// nothing; it looks for the pixel ratio on window and finds none.
|
// Drawing a sparkline does nothing; it looks for the pixel ratio on window
|
||||||
const elements = {};
|
// and finds none.
|
||||||
|
let elements;
|
||||||
|
beforeEach(() => {
|
||||||
|
elements = {};
|
||||||
|
});
|
||||||
const doNothing = () => {};
|
const doNothing = () => {};
|
||||||
const canvasContext = {
|
const canvasContext = {
|
||||||
clearRect: doNothing,
|
clearRect: doNothing,
|
||||||
@@ -120,3 +124,55 @@ test("at a 30000ms interval, a target answering after 1000ms shows in its row wh
|
|||||||
assert.notEqual(await settled(round), "still waiting");
|
assert.notEqual(await settled(round), "still waiting");
|
||||||
assert.equal(state.tickCount, 3);
|
assert.equal(state.tickCount, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// In the next three tests, the answering target's check is still waiting
|
||||||
|
// when something happens after which its result must not show.
|
||||||
|
|
||||||
|
test("at a 30000ms interval, a check still waiting when its round is given up does not show in its row", async (t) => {
|
||||||
|
CONFIG.updateInterval = 30000;
|
||||||
|
const state = new AppState([
|
||||||
|
{ name: "Answering", url: "https://answering.test" },
|
||||||
|
]);
|
||||||
|
const answering = state.local[0];
|
||||||
|
mockTargets(t, (url) => (url.startsWith(answering.url) ? 1000 : Infinity));
|
||||||
|
state.tickCount = 2;
|
||||||
|
|
||||||
|
const roundChecks = new AbortController();
|
||||||
|
const round = tick(state, roundChecks.signal);
|
||||||
|
t.mock.timers.tick(500);
|
||||||
|
// As a round started early does to the last round's checks.
|
||||||
|
roundChecks.abort();
|
||||||
|
assert.notEqual(await settled(round), "still waiting");
|
||||||
|
assert.equal(latencyFigure(state, answering), undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("at a 30000ms interval, a check still waiting when the user pauses does not show in its row", async (t) => {
|
||||||
|
CONFIG.updateInterval = 30000;
|
||||||
|
const state = new AppState([
|
||||||
|
{ name: "Answering", url: "https://answering.test" },
|
||||||
|
]);
|
||||||
|
const answering = state.local[0];
|
||||||
|
mockTargets(t, (url) => (url.startsWith(answering.url) ? 1000 : Infinity));
|
||||||
|
state.tickCount = 2;
|
||||||
|
|
||||||
|
const round = tick(state, new AbortController().signal);
|
||||||
|
t.mock.timers.tick(500);
|
||||||
|
state.paused = true;
|
||||||
|
t.mock.timers.tick(500);
|
||||||
|
assert.equal(await settled(round), "still waiting");
|
||||||
|
assert.equal(latencyFigure(state, answering), undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("at a 30000ms interval, a check in the first round does not show in its row", async (t) => {
|
||||||
|
CONFIG.updateInterval = 30000;
|
||||||
|
const state = new AppState([
|
||||||
|
{ name: "Answering", url: "https://answering.test" },
|
||||||
|
]);
|
||||||
|
const answering = state.local[0];
|
||||||
|
mockTargets(t, (url) => (url.startsWith(answering.url) ? 1000 : Infinity));
|
||||||
|
|
||||||
|
const round = tick(state, new AbortController().signal);
|
||||||
|
t.mock.timers.tick(1000);
|
||||||
|
assert.equal(await settled(round), "still waiting");
|
||||||
|
assert.equal(latencyFigure(state, answering), undefined);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user