fix(uptime): объяснить неизвестный результат теста скорости
This commit is contained in:
1 parent
dbe1e7c917
commit
5944e5e751
13 files changed
+190
-24
No files matched your search
@@ -28,12 +28,22 @@ missing = true; assert.equal((await send(base)).statusCode, 404); assert.equal(c
|
||||
for (const [error, code] of [[new SpeedProbeEndpointsChanged(), 409], [new SpeedProbeContextChanged(), 409], [Error("На интерфейсе назначения нет активного IP"), 400], [Error("Server not found"), 400], [Error("authentication failed"), 502], [Error("socket hang up"), 502]] as const) {
|
||||
problem = error; const response = await send({ ...base, runId: "failed", direction: "transmit", durationSec: 20 }); assert.equal(response.statusCode, code); assert.equal(failures.at(-1)?.runId, "failed"); assert.equal(failures.at(-1)?.durationSec, 20); assert.equal(failures.at(-1)?.direction, "transmit")
|
||||
}
|
||||
const beforeUnknown = { runs: commands.length, failures: failures.length }
|
||||
for (const transport of ["Connection timed out after 30s", "socket hang up", "read ECONNRESET"]) {
|
||||
problem = Error(transport)
|
||||
const response = await send({ ...base, runId: "transport-failed" })
|
||||
assert.equal(response.statusCode, 502)
|
||||
assert.match(response.json().error, /Результат теста скорости неизвестен/)
|
||||
assert.doesNotMatch(response.json().error, /socket|ECONNRESET|timed out/)
|
||||
assert.equal(failures.at(-1)?.message, transport)
|
||||
}
|
||||
problem = Error("RouterOS отклонил авторизацию bandwidth-test")
|
||||
assert.equal((await send(base)).json().error, problem.message)
|
||||
const beforePersistenceUnknown = { runs: commands.length, failures: failures.length }
|
||||
problem = new SpeedRunPersistenceUnknown("actual-run-id")
|
||||
const unknown = await send(base)
|
||||
assert.equal(unknown.statusCode, 502); assert.equal(unknown.json().outcome, "unknown")
|
||||
assert.equal(unknown.json().runId, "actual-run-id"); assert.match(unknown.json().error, /сохранение результата не подтверждено/)
|
||||
assert.equal(failures.length, beforeUnknown.failures); assert.equal(commands.length, beforeUnknown.runs + 1)
|
||||
assert.equal(failures.length, beforePersistenceUnknown.failures); assert.equal(commands.length, beforePersistenceUnknown.runs + 1)
|
||||
await app.close(); console.log("Speed-test HTTP:26 invalid inputs; explicit persistence unknown/runId skips failure write and command retry")
|
||||
process.env.AUTH_REQUIRED = "true"; process.env.AUTH_JWT_SECRET = "speed-command-test-secret"; process.env.AUTH_ISSUER = "https://auth.test.local"; process.env.NODE_ENV = "test"
|
||||
const { default: authPlugin, requireAuth } = await import("../plugins/auth.js")
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
|
||||
import { speedTestCommandSchema, type SpeedTestCommand } from "@mmapp/contracts"
|
||||
import type { SpeedTestRunResult } from "../services/uptime-speed-service.js"
|
||||
import { SpeedProbeContextChanged, SpeedRunPersistenceUnknown } from "../services/speed-run-persistence.js"
|
||||
import { speedRunErrorMessage } from "../services/speed-run-error-message.js"
|
||||
|
||||
export function createSpeedTestRoute(deps: {
|
||||
serverExists: (id: number) => Promise<boolean>
|
||||
@@ -23,9 +24,7 @@ export function createSpeedTestRoute(deps: {
|
||||
}
|
||||
const raw = error instanceof Error ? error.message : "Bandwidth test failed"
|
||||
await deps.failure({ ...command, message: raw })
|
||||
const message = /timed out|socket hang up|ECONNRESET/i.test(raw)
|
||||
? "BTTest timeout/socket hang up: проверь доступность destination, /tool bandwidth-server, firewall и корректность интерфейсов"
|
||||
: raw
|
||||
const message = speedRunErrorMessage(raw)
|
||||
if (error instanceof SpeedProbeContextChanged) return reply.code(409).send({ error: message })
|
||||
if (/активного IP|Server not found/i.test(raw)) return reply.code(400).send({ error: message })
|
||||
return reply.code(502).send({ error: message })
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/** A lost transport receipt cannot establish whether RouterOS completed the test. */
|
||||
export function speedRunErrorMessage(raw: string): string {
|
||||
return /timed out|socket hang up|ECONNRESET/i.test(raw)
|
||||
? "Результат теста скорости неизвестен: ответ устройства не получен. Проверьте его состояние перед повторным запуском."
|
||||
: raw
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { parsePing } from "./uptime-collector.js"
|
||||
import { assertBandwidthTestCompleted } from "./bandwidth-test-status.js"
|
||||
import { assertSpeedProbeContext, persistSpeedRun, SpeedRunPersistenceUnknown, type SpeedProbeContext } from "./speed-run-persistence.js"
|
||||
import { readBandwidthTestRates } from "./bandwidth-test-rates.js"
|
||||
import { speedRunErrorMessage } from "./speed-run-error-message.js"
|
||||
|
||||
type SpeedWriteTransaction = Parameters<Parameters<typeof db.transaction>[0]>[0]
|
||||
function speedProbeContextWhere(target: SpeedProbeContext) {
|
||||
@@ -73,12 +74,6 @@ export interface SpeedTestRunResult {
|
||||
}
|
||||
}
|
||||
|
||||
function humanizeSpeedError(raw: string): string {
|
||||
return /timed out|socket hang up|ECONNRESET/i.test(raw)
|
||||
? "BTTest timeout/socket hang up: проверь доступность destination, /tool bandwidth-server, firewall и корректность интерфейсов"
|
||||
: raw
|
||||
}
|
||||
|
||||
/** Полный цикл bandwidth-test + after-ping + запись в БД. Вызывать внутри withBtestNodeLocks при необходимости — здесь lock уже снаружи. */
|
||||
export async function executeBandwidthSpeedTestInner(params: SpeedTestRunParams): Promise<SpeedTestRunResult> {
|
||||
const probeId = String(params.probeId ?? "").trim()
|
||||
@@ -232,7 +227,7 @@ export async function recordSpeedTestFailure(params: {
|
||||
message: string
|
||||
}) {
|
||||
const probeId = String(params.probeId ?? "").trim()
|
||||
const message = humanizeSpeedError(params.message)
|
||||
const message = speedRunErrorMessage(params.message)
|
||||
await persistSpeedRun<SpeedWriteTransaction, SpeedProbeContext>(probeId ? {
|
||||
id: probeId, srcServerId: params.srcServerId, dstServerId: params.dstServerId,
|
||||
srcInterface: String(params.srcInterface ?? "").trim(), dstInterface: String(params.dstInterface ?? "").trim(),
|
||||
|
||||
Reference in new issue
Block a user