You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

71 lines
3.3 KiB

const test = require('node:test');
const assert = require('node:assert/strict');
const logs = require('../frontend/web/static/js/log-view.js');
test('state event view includes transitions only, never periodic snapshots or unknown types', () => {
const events=[{event_type:'snapshot'},{event_type:'transition',state:'up'},{event_type:'other'},{}];
assert.deepEqual(logs.transitionsOnly(events),[events[1]]);
assert.equal(events.length,4);
});
test('newest logs first without mutating source; invalid timestamps last', () => {
const items = [
{ id: 1, timestamp: '2026-09-07T01:00:00Z' },
{ id: 2, timestamp: 'invalid' },
{ id: 3, timestamp: '2026-09-07T02:00:00Z' },
{ id: 4, timestamp: '2026-09-07T02:00:00Z' },
{ id: 5 },
];
assert.deepEqual(logs.orderedEvents(items).map(e => e.id), [3, 4, 1, 2, 5]);
assert.deepEqual(items.map(e => e.id), [1, 2, 3, 4, 5]);
});
test('system summary counts only returned raw severity values', () => {
const summary = logs.summaryFor('system', [
{ severity: 'info' }, { severity: 'INFO' }, { severity: 'warning' },
{ severity: 'critical' }, {}, { severity: 'other' },
]);
assert.deepEqual(summary.map(e => [e.key, e.count]), [['info', 2], ['warning', 1], ['critical', 1]]);
assert.equal(logs.summaryFor('system', []).every(e => e.count === 0), true);
});
test('port and link summaries use directions and actual state, not translated labels', () => {
assert.deepEqual(logs.summaryFor('port', [
{ direction: 'RX', event_type: 'traffic' }, { direction: 'tx' },
{ direction: 'CONNECTED', event_type: 'session' }, { event_type: 'session' },
]).map(e => e.count), [1, 1, 2]);
assert.deepEqual(logs.summaryFor('link', [
{ state: 'UP', previous_state: 'down' }, { state: 'down' }, { state: 'unknown' }, {},
]).map(e => e.count), [1, 1, 2]);
});
test('timestamps respect device time zone across midnight', () => {
assert.deepEqual(logs.timestampParts('2026-09-06T16:02:03Z', 'Asia/Seoul'), {
date: '2026-09-07', time: '01:02:03', unset: false,
});
assert.deepEqual(logs.timestampParts('2026-09-07T00:00:00Z', 'UTC'), {
date: '2026-09-07', time: '00:00:00', unset: false,
});
});
test('unconfigured clocks stay in the past; missing dates do not become today', () => {
assert.deepEqual(logs.timestampParts('1970-01-01T00:00:00Z', 'UTC'), {
date: '1970-01-01', time: '00:00:00', unset: true,
});
for (const value of [null, undefined, '']) {
assert.deepEqual(logs.timestampParts(value, 'UTC'), { date: '—', time: '—', unset: false });
}
assert.equal(logs.timestampParts('invalid', 'UTC').time, 'invalid');
assert.equal(logs.timestampParts('2026-09-07T00:00:00Z', 'invalid-zone').time, '2026-09-07T00:00:00Z');
});
test('highlighting is literal, case-insensitive and preserves the full original text', () => {
const original = '<img onerror="alert(1)"> a.b A.B [x]';
const parts = logs.highlightParts(original, 'a.b');
assert.equal(parts.map(p => p.text).join(''), original);
assert.deepEqual(parts.filter(p => p.match).map(p => p.text), ['a.b', 'A.B']);
assert.equal(logs.highlightParts(original, '[x]').filter(p => p.match)[0].text, '[x]');
assert.deepEqual(logs.highlightParts(original, ' '), [{ text: original, match: false }]);
assert.deepEqual(logs.highlightParts('오류: 연결 오류', '오류').filter(p => p.match).map(p => p.text), ['오류', '오류']);
});