Files
MikrotikManager/lib/ospf-state.test.ts

49 lines
4.3 KiB
TypeScript

import assert from "node:assert/strict"
import { test } from "node:test"
import { normalizeOspfState, normalizeBfdState, ospfNodeState, ospfBfdConflicts } from "./ospf-state"
test("RouterOS states keep transitional adjacency separate from failure", () => {
assert.deepEqual(["full", "2-way", "ExStart", "exchange", "loading", "attempt", "init", "down"].map(normalizeOspfState), ["Full", "2-Way", "ExStart", "Exchange", "Loading", "Attempt", "Init", "Down"])
assert.equal(normalizeOspfState("future-state"), "Unknown")
assert.equal(normalizeBfdState(""), "Unknown")
assert.equal(normalizeBfdState(" UP "), "Up")
})
test("Full/BFD conflict requires fresh exact device, interface, peer, explicit active BFD and unique direct session", () => {
const neighbor = { localRouter: "1", localIface: "gre-own", neighborAddress: "198.18.153.2", state: "Full" as const }
const iface = { serverId: "1", interfaceName: "gre-own", active: true, useBfd: true }
const session = { serverId: "1", iface: "gre-own", remoteAddr: "198.18.153.2", state: "Down" as const, multihop: false }
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session]), [neighbor])
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [{ ...session, state: "AdminDown" }]), [neighbor])
for (const s of [{ ...session, serverId: "2" }, { ...session, iface: "ether1" }, { ...session, remoteAddr: "198.18.153.3" }, { ...session, multihop: true }, { ...session, multihop: null }, { ...session, state: "Unknown" as const }, { ...session, state: "Up" as const }, { ...session, dataUnknown: true }]) assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [s]), [])
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session, { ...session, state: "Up" }]), [])
for (const i of [{ ...iface, useBfd: null }, { ...iface, useBfd: false }, { ...iface, active: false }, { ...iface, active: null }, { ...iface, dataUnknown: true }]) assert.deepEqual(ospfBfdConflicts([neighbor], [i], [session]), [])
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, dataUnknown: true }], [iface], [session]), [])
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, state: "Down" }], [iface], [session]), [])
assert.deepEqual(ospfBfdConflicts([{ ...neighbor, neighborAddress: undefined }], [iface], [session]), [])
})
test("topology does not infer Down from missing or transitional evidence", () => {
assert.equal(ospfNodeState([]), "none")
assert.equal(ospfNodeState(["Down"]), "Down")
assert.equal(ospfNodeState(["Down", "Unknown"]), "Unknown")
assert.equal(ospfNodeState(["Exchange", "Loading"]), "Pending")
assert.equal(ospfNodeState(["2-Way", "Down"]), "2-Way")
assert.equal(ospfNodeState(["Full", "Unknown"]), "Full")
})
test("BFD correlation compares IPv6 addresses canonically within their interface scope", () => {
const neighbor = { localRouter: "1", localIface: "gre-own", neighborAddress: "FE80:0000:0000:0000:0000:0000:0000:0002%gre-own", state: "Full" as const }
const iface = { serverId: "1", interfaceName: "gre-own", active: true, useBfd: true }
const session = { serverId: "1", iface: "gre-own", remoteAddr: "fe80::2", state: "Down" as const, multihop: false }
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session]), [neighbor])
for (const remoteAddr of ["fe80::3", "fe80::2%other", "fe80::2%", "fe80::2%gre-own%extra"]) assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [{ ...session, remoteAddr }]), [])
for (const neighborAddress of ["fe80::2%other", "fe80::2%", "fe80::2%gre-own%extra"]) assert.deepEqual(ospfBfdConflicts([{ ...neighbor, neighborAddress }], [iface], [session]), [])
})
test("invalid peer strings and stale duplicate sessions cannot prove an OSPF/BFD conflict", () => {
const neighbor = { localRouter: "1", localIface: "gre-own", neighborAddress: "198.18.153.2", state: "Full" as const }
const iface = { serverId: "1", interfaceName: "gre-own", active: true, useBfd: true }
const session = { serverId: "1", iface: "gre-own", remoteAddr: neighbor.neighborAddress, state: "Down" as const, multihop: false }
assert.deepEqual(ospfBfdConflicts([neighbor], [iface], [session, { ...session, dataUnknown: true }]), [])
for (const address of ["peer.example", "999.18.153.2", "0198.18.153.2", "fe80::invalid", ":::", "fe80::2/64", ""]) assert.deepEqual(ospfBfdConflicts([{ ...neighbor, neighborAddress: address }], [iface], [{ ...session, remoteAddr: address }]), [])
})