修复跨分钟导致的测试误报

This commit is contained in:
imengying committed 2026-09-07 22:04:25 +08:00
1 parent d7ccdca8d7
commit 58dea92e5f
2 files changed
+80 -2

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
import { describe, expect, test } from "bun:test";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
const script = readFileSync(new URL("../../scripts/smoke-test.sh", import.meta.url), "utf8");
const assertion = script.match(/^assert_latency_history\(\) \{[\s\S]*?^\}/m)?.[0];
if (!assertion) throw new Error("Missing latency history smoke assertion");
const taskId = "smoke-latency";
const point = (timestamp: number, latency_ms: number, packet_loss: number, task_id = taskId) => ({
task_id, timestamp, latency_ms, packet_loss,
});
function check(points: ReturnType<typeof point>[], tasks = [{ id: taskId }]) {
return spawnSync("sh", ["-c", `${assertion}\nassert_latency_history "$1"`, "smoke-test", taskId], {
input: JSON.stringify({ tasks, points }), encoding: "utf8",
});
}
describe("latency history smoke assertion", () => {
test("accepts a single averaged bucket with floating point rounding", () => {
const result = check([point(120, 38.400000000000006, 50)]);
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
});
test("accepts samples split across a minute boundary in either response order", () => {
const points = [point(120, 28.4, 25), point(180, 48.4, 75)];
expect(check(points).status).toBe(0);
expect(check([...points].reverse()).status).toBe(0);
});
test("rejects missing, corrupt, duplicate and unrelated samples", () => {
for (const points of [
[], [point(120, 28.4, 25)], [point(120, 38.4, 51)],
[point(120, 38.4, 50, "other-task")],
[point(120, 28.4, 25), point(240, 48.4, 75)],
[point(120, 28.4, 25), point(180, 47, 75)],
[point(120, 28.4, 25), point(180, 48.4, 76)],
[point(120, 38.4, 50), point(120, 38.4, 50)],
]) {
const result = check(points);
expect(result.status).toBe(1);
expect(result.stderr).toContain("latency history assertion failed");
expect(result.stderr).toContain(JSON.stringify({ tasks: [{ id: taskId }], points }));
}
});
test("requires the task to remain assigned", () => {
expect(check([point(120, 38.4, 50)], []).status).toBe(1);
});
});
+28 -2
View File
@@ -32,6 +32,28 @@ step() {
printf 'smoke: %s\n' "$1" >&2
}
assert_latency_history() {
latency_history_json=$(cat)
# Samples one second apart can land in adjacent minute buckets.
if printf '%s' "$latency_history_json" | jq -e --arg task_id "$1" '
def near($expected): type == "number" and . > ($expected - 0.001) and . < ($expected + 0.001);
(.tasks | any(.id == $task_id)) and
(.points | map(select(.task_id == $task_id)) | sort_by(.timestamp) |
if length == 1 then
(.[0].latency_ms | near(38.4)) and (.[0].packet_loss | near(50))
elif length == 2 then
(.[1].timestamp - .[0].timestamp == 60) and
(.[0].latency_ms | near(28.4)) and (.[0].packet_loss | near(25)) and
(.[1].latency_ms | near(48.4)) and (.[1].packet_loss | near(75))
else false end)
' >/dev/null; then
return 0
fi
printf '%s\n' 'smoke: latency history assertion failed; expected one averaged bucket or two adjacent sample buckets' >&2
printf '%s\n' "$latency_history_json" >&2
return 1
}
admin_token=
server_id=
latency_task_id=
@@ -231,18 +253,22 @@ rotated_agent_token=$(MONITOR_BASE_URL="$MONITOR_BASE_URL" MONITOR_ADMIN_TOKEN="
[ "$rotated_agent_token" != "$agent_token" ]
agent_token=$rotated_agent_token
step "persisted metrics"
step "persisted metrics: admin IP metadata"
request -H "Authorization: Bearer $admin_token" "$MONITOR_BASE_URL/api/admin/servers" | \
jq -e --arg id "$server_id" '.servers | any(.id == $id and .last_ip == "8.8.8.8")' >/dev/null
step "persisted metrics: public snapshot"
post_report_bootstrap=$(request -H "Authorization: Bearer $admin_token" "$MONITOR_BASE_URL/api/bootstrap")
if ! printf '%s' "$post_report_bootstrap" | jq -e --arg id "$server_id" --arg task_id "$latency_task_id" '.servers | any(.id == $id and .cpu == 18.5 and .gpu_usage == 32.5 and .disk_await_ms == 1.4 and (.gpus | length) == 1 and (.disks | length) == 1 and .disk_used == 21474836480 and .traffic_limit == 107374182400 and .net_rx_total == 2684354560 and .net_tx_total == 1342177280 and .price == 9.9 and (has("last_ip") | not) and (.latency | any(.task_id == $task_id and .latency_ms == 48.4 and .packet_loss == 75)))' >/dev/null; then
printf '%s' "$post_report_bootstrap" | jq --arg id "$server_id" '.servers[] | select(.id == $id)' >&2
exit 1
fi
step "persisted metrics: GPU history"
request -H "Authorization: Bearer $admin_token" "$MONITOR_BASE_URL/api/history/$server_id?hours=1" | jq -e '.points | length >= 1 and any(.gpu_usage == 32.5)' >/dev/null
request -H "Authorization: Bearer $admin_token" "$MONITOR_BASE_URL/api/latency/$server_id?hours=1" | jq -e --arg task_id "$latency_task_id" '(.tasks | any(.id == $task_id)) and (.points | any(.task_id == $task_id and .latency_ms > 38.399 and .latency_ms < 38.401 and .packet_loss > 49.999 and .packet_loss < 50.001))' >/dev/null
step "persisted metrics: latency history"
request -H "Authorization: Bearer $admin_token" "$MONITOR_BASE_URL/api/latency/$server_id?hours=1" | assert_latency_history "$latency_task_id"
step "persisted metrics: latency task unassignment"
request -H "Authorization: Bearer $admin_token" -H 'Content-Type: application/json' -X PATCH \
--data '{"name":"Smoke TCP","task_type":"tcp","target":"example.com","port":443,"interval_seconds":60,"default_enabled":true,"server_ids":[]}' \
"$MONITOR_BASE_URL/api/admin/latency-tasks/$latency_task_id" >/dev/null