'use strict';
const https = require('https');
const { parseOpenBmpMessage, parseBmpMessage, parseBgpUpdate, parseMrtRecords } = require('@bgpkit/parser');
let passed = 0;
let failed = 0;
function assert(condition, msg) {
if (condition) {
console.log(` ✓ ${msg}`);
passed++;
} else {
console.error(` ✗ ${msg}`);
failed++;
}
}
function testOpenBmpPeerDown() {
console.log('\n[1/5] parseOpenBmpMessage (PeerDownNotification)');
const hex =
'4f424d500107006400000033800c6184b9c2000c602cbf4f072f3ae149d23486024bc3dadfc4000a' +
'69732d63632d626d7031c677060bdd020a9e92be000200de2e3180df3369000000000000000000000' +
'000000c726f7574652d76696577733500000001030000003302000000000000000000000000000000' +
'000000000000003fda060e00000da30000000061523c36000c0e1c0200000a';
const data = Buffer.from(hex, 'hex');
const msg = parseOpenBmpMessage(data);
assert(msg !== null, 'returns non-null for valid message');
assert(msg.type === 'PeerDownNotification', `type is PeerDownNotification (got ${msg.type})`);
assert(msg.openBmpHeader !== null, 'openBmpHeader is present');
assert(typeof msg.openBmpHeader.routerIp === 'string', `routerIp: ${msg.openBmpHeader.routerIp}`);
assert(msg.peerHeader !== undefined, 'peerHeader is present');
assert(typeof msg.peerHeader.peerAsn === 'number', `peerAsn: ${msg.peerHeader.peerAsn}`);
assert(typeof msg.reason === 'string', `reason: ${msg.reason}`);
assert(typeof msg.timestamp === 'number', `timestamp: ${msg.timestamp}`);
}
function testOpenBmpNull() {
console.log('\n[2/5] parseOpenBmpMessage (non-router frame)');
const hex =
'4f424d500100005c000000b0800c618881530002f643fef880938d19e9d632c815d1e95a87e1000a' +
'69732d61682d626d7031eb4de4e596b282c6a995b067df4abc8cc342f192';
const data = Buffer.from(hex, 'hex');
let result;
try {
result = parseOpenBmpMessage(data);
} catch {
result = 'threw';
}
assert(result === null, 'returns null for non-router OpenBMP frame');
}
function testBmpMessage() {
console.log('\n[3/5] parseBmpMessage');
const fullHex =
'4f424d500107006400000033800c6184b9c2000c602cbf4f072f3ae149d23486024bc3dadfc4000a' +
'69732d63632d626d7031c677060bdd020a9e92be000200de2e3180df3369000000000000000000000' +
'000000c726f7574652d76696577733500000001030000003302000000000000000000000000000000' +
'000000000000003fda060e00000da30000000061523c36000c0e1c0200000a';
const fullData = Buffer.from(fullHex, 'hex');
const hdrLen = fullData.readUInt16BE(6);
const bmpData = fullData.subarray(hdrLen);
const now = Date.now() / 1000;
const msg = parseBmpMessage(bmpData, now);
assert(msg !== null, 'returns non-null');
assert(msg.type === 'PeerDownNotification', `type is PeerDownNotification (got ${msg.type})`);
assert(msg.openBmpHeader === null, 'openBmpHeader is null (no OpenBMP wrapper)');
assert(typeof msg.timestamp === 'number', 'timestamp is a number');
}
function testBgpUpdate() {
console.log('\n[4/5] parseBgpUpdate');
const hex =
'ffffffffffffffffffffffffffffffff' + '00380200' + '0000' + '001b' + '40010100' + '40020a0202000000fd00000065' + '400304c0000201' + '18c63364';
const data = Buffer.from(hex, 'hex');
const elems = parseBgpUpdate(data);
assert(Array.isArray(elems), 'returns an array');
assert(elems.length === 1, `has ${elems.length} element(s)`);
const elem = elems[0];
assert(elem.type === 'ANNOUNCE', `type is ANNOUNCE (got ${elem.type})`);
assert(elem.prefix === '198.51.100.0/24', `prefix is ${elem.prefix}`);
assert(elem.next_hop === '192.0.2.1', `next_hop is ${elem.next_hop}`);
}
function testMrtRecords() {
return new Promise((resolve) => {
console.log('\n[5/5] parseMrtRecords');
console.log(' ↓ downloading test MRT file...');
const url = 'https://spaces.bgpkit.org/parser/update-example';
https.get(url, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
https.get(res.headers.location, (res2) => handleResponse(res2, resolve));
return;
}
handleResponse(res, resolve);
}).on('error', (err) => {
console.log(` ⚠ skipped (download failed: ${err.message})`);
resolve();
});
});
}
function handleResponse(res, resolve) {
const chunks = [];
res.on('data', (chunk) => chunks.push(chunk));
res.on('end', () => {
const raw = Buffer.concat(chunks);
console.log(` ↓ downloaded ${(raw.length / 1024).toFixed(0)} KB`);
const allElems = [];
for (const { elems } of parseMrtRecords(raw)) {
allElems.push(...elems);
}
assert(allElems.length > 0, `parsed ${allElems.length} elements`);
const announce = allElems.find((e) => e.type === 'ANNOUNCE');
if (announce) {
assert(typeof announce.prefix === 'string', `sample prefix: ${announce.prefix}`);
assert(typeof announce.peer_ip === 'string', `sample peer_ip: ${announce.peer_ip}`);
assert(typeof announce.peer_asn === 'number', `sample peer_asn: ${announce.peer_asn}`);
}
resolve();
});
res.on('error', (err) => {
console.log(` ⚠ skipped (download failed: ${err.message})`);
resolve();
});
}
async function main() {
console.log('Testing @bgpkit/parser npm package\n');
testOpenBmpPeerDown();
testOpenBmpNull();
testBmpMessage();
testBgpUpdate();
await testMrtRecords();
console.log(`\n${passed + failed} assertions: ${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);
}
main();