/** * Prueft die Bewertung der SIP-Erreichbarkeit gegen konstruierte Antworten. * * Der Kernsatz, der hier nachgerechnet wird: JEDE Statuszeile beweist eine * antwortende Instanz. Eine 401 ("bitte anmelden") oder eine 405 ("Methode * nicht erlaubt") darf deshalb NIE als Ausfall im Kundendokument landen - * genau das waere die Falschaussage, wegen der ein Techniker am falschen Ende * sucht. Ebenso wichtig: der Fall "nur ueber TCP kam etwas" muss auffallen, * weil er auf einen UDP-Filter zeigt, waehrend die Anlage selbst laeuft. * * Start: node tools/pruefe-sip.mjs */ const { bewerteSip, fehlerText } = await import('../src/lib/tools/telefonie/sip-bewertung.ts'); const antwort = (transport, code, text, extra = {}) => ({ transport, statusCode: code, statusText: text, latenzMs: 12, server: extra.server ?? null, allow: extra.allow ?? null, fehler: null, }); const stumm = (transport, grund = 'timeout') => ({ transport, statusCode: null, statusText: null, latenzMs: null, server: null, allow: null, fehler: grund, }); const m = (versuche, host = 'fritz.box', port = 5060) => ({ host, ip: '192.168.1.1', port, versuche }); const faelle = [ { name: '200 OK ueber UDP -> GRUEN', m: m([antwort('udp', 200, 'OK', { server: 'FRITZ!OS' })]), soll: 0, }, { name: '401 Unauthorized -> GRUEN + Anmeldung verlangt (Normalfall beim Provider)', m: m([antwort('udp', 401, 'Unauthorized')], 'sip.stadtwerke-nms.de'), soll: 0, pruefe: (r) => r.anmeldungNoetig === true, }, { name: '407 Proxy Authentication Required -> GRUEN + Anmeldung verlangt', m: m([antwort('udp', 407, 'Proxy Authentication Required')]), soll: 0, pruefe: (r) => r.anmeldungNoetig === true, }, { name: '405 Method Not Allowed -> GELB, aber ERREICHBAR (kein Ausfall!)', m: m([antwort('udp', 405, 'Method Not Allowed')]), soll: 1, pruefe: (r) => r.statuszeile === '405 Method Not Allowed', }, { name: '404 Not Found -> GELB (Instanz da, Ziel unbekannt)', m: m([antwort('udp', 404, 'Not Found')]), soll: 1, }, { name: '403 Forbidden -> GELB (erreichbar, weist ab)', m: m([antwort('udp', 403, 'Forbidden')]), soll: 1, }, { name: '503 Service Unavailable -> GELB (Weg in Ordnung, Gegenseite gestoert)', m: m([antwort('udp', 503, 'Service Unavailable')]), soll: 1, }, { name: 'UDP stumm, TCP antwortet 200 -> GELB + Hinweis auf UDP-Filter', m: m([stumm('udp'), antwort('tcp', 200, 'OK')]), soll: 1, pruefe: (r) => r.antwortWeg === 'tcp' && /UDP/.test(r.befund), }, { name: 'UDP stumm, TCP antwortet 401 -> GELB (nicht gruen: der Filter bleibt ein Befund)', m: m([stumm('udp'), antwort('tcp', 401, 'Unauthorized')]), soll: 1, pruefe: (r) => r.anmeldungNoetig === true, }, { name: 'Beide Wege stumm -> ROT', m: m([stumm('udp'), stumm('tcp')]), soll: 2, pruefe: (r) => r.statuszeile === null, }, { name: 'Verbindung abgewiesen (Port zu) -> ROT, aber NICHT als "keine Antwort" betitelt', m: m([stumm('udp'), stumm('tcp', 'abgewiesen')]), soll: 2, pruefe: (r) => /Port geschlossen/.test(r.kurz) && /erreichbar/.test(r.befund), }, { name: 'Name nicht aufloesbar -> NICHT MESSBAR (DNS-Befund, keine Aussage ueber die Anlage)', m: m([stumm('dns', 'name')], 'pbx.kunde.local'), soll: 3, }, { name: 'Antwort ist kein SIP -> ROT mit eigenem Befund (nicht "keine Antwort")', m: m([stumm('udp', 'kein-sip')]), soll: 2, pruefe: (r) => /kein SIP/.test(r.kurz), }, { name: 'Nicht-Standardport erscheint im Kurztext', m: m([antwort('udp', 200, 'OK')], 'pbx.kunde.de', 5080), soll: 0, pruefe: (r) => r.kurz.includes('pbx.kunde.de:5080'), }, ]; let fehler = 0; for (const f of faelle) { const r = bewerteSip(f.m); const statusOk = r.status === f.soll; const extraOk = f.pruefe ? f.pruefe(r) : true; if (!statusOk || !extraOk) fehler++; console.log(`${statusOk && extraOk ? 'OK ' : 'FEHL'} ${f.name}`); console.log(` status=${r.status} (soll ${f.soll}) ${r.kurz}`); if (!extraOk) console.log(` Zusatzpruefung fehlgeschlagen: ${r.befund}`); } // Die Fehlertexte muessen den Port nennen - "keine Antwort" allein schickt den // Techniker sonst auf die Suche ohne Anhaltspunkt. const textFaelle = [ ['timeout', 5060, /Port 5060/], ['abgewiesen', 5080, /Port 5080/], ['kein-sip', 5060, /kein SIP/], ['name', 5060, /aufl/], ]; for (const [grund, port, muster] of textFaelle) { const t = fehlerText(grund, port); const okk = muster.test(t); if (!okk) fehler++; console.log(`${okk ? 'OK ' : 'FEHL'} fehlerText("${grund}", ${port}) = "${t}"`); } console.log(fehler === 0 ? 'ALLE FAELLE KORREKT' : `${fehler} FEHLER`); process.exit(fehler === 0 ? 0 : 1);