import assert from "node:assert/strict" import { readRecursiveEffectiveProperties, parseRecursiveCatalog } from "./recursive-route-catalog.js" const row = { ".id": "*1", static: "true", "dst-address": "10.9.9.2/32", gateway: "192.0.2.1%gre-test", distance: "1", scope: "30", "target-scope": "10", "routing-table": "main", comment: "MikrotikManager:recursive Тест" } const calls: string[] = [] const result = await readRecursiveEffectiveProperties([row], async (id, property) => { calls.push(id + ":" + property) return property === "disabled" ? { ret: "false" } : [] }) assert.equal(parseRecursiveCatalog(result)[0].disabled, false) assert.equal(parseRecursiveCatalog(result)[0].checkGateway, "none") assert.deepEqual(calls.sort(), ["*1:check-gateway", "*1:disabled"]) assert.equal("disabled" in row, false) let reads = 0 const complete = { ...row, disabled: "true", "check-gateway": "ping" } assert.deepEqual(await readRecursiveEffectiveProperties([complete, { ".id": "*other", comment: "user-owned" }], async () => { reads++; return null }), [complete, { ".id": "*other", comment: "user-owned" }]) assert.equal(reads, 0) for (const payload of [null, {}, [null], [{ ...row, ".id": "" }], [row, row]]) { await assert.rejects(readRecursiveEffectiveProperties(payload, async () => { reads++; return null })) assert.equal(reads, 0) } for (const property of ["disabled", "check-gateway"] as const) { for (const response of [null, {}, { ret: false }, { ret: "" }, { ret: "unknown" }, [{}], ...(property === "disabled" ? [[]] : [])]) { const input = { ...complete }; delete (input as Record)[property] await assert.rejects(readRecursiveEffectiveProperties([input], async () => response), /Не подтверждён/) } } await assert.rejects(readRecursiveEffectiveProperties([row], async () => { throw Error("RouterOS недоступен") }), /недоступен/) const explicit = await readRecursiveEffectiveProperties([row], async (_id, property) => ({ ret: property === "disabled" ? "true" : "bfd" })) assert.equal(parseRecursiveCatalog(explicit)[0].disabled, true) assert.equal(parseRecursiveCatalog(explicit)[0].checkGateway, "bfd") // Explicit invalid values are not replaced with defaults or re-read. const invalid = { ...complete, disabled: "unknown" } const untouched = await readRecursiveEffectiveProperties([invalid], async () => { throw Error("unexpected read") }) assert.throws(() => parseRecursiveCatalog(untouched)) let active = 0, maximum = 0 await readRecursiveEffectiveProperties(Array.from({ length: 12 }, (_, i) => ({ ...row, ".id": "*" + i })), async (_id, property) => { maximum = Math.max(maximum, ++active) await new Promise(resolve => setTimeout(resolve, 1)); active-- return { ret: property === "disabled" ? "false" : "arp" } }) assert.equal(maximum, 2) console.log("Recursive effective properties: omitted flags/unset check, strict envelopes, ownership, no mutation, errors and bounded reads passed")