blob: 04099cdf7895a8f9f0ba64076d7ec0b97ad4b2fe [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import chai from 'chai'; // not esm
import * as constant from '../src/constants';
import {ffxEventForTest, malformedLogForTest, symbolizedDataForTest} from './util';
import { FfxLogData, LogPayload } from '../src/log_data';
import { LogRow } from '../components/log_row';
import { messageForEvent } from '../src/format_log_text';
import {ffxLogToLogRowData} from '../src/ffxLogToLogRow';
import {State} from '../src/state';
import {LogColumnFormatter} from '../src/fields';
const columnFormatter: LogColumnFormatter = (_fieldName, text) => text;
before(() => {
chai.should();
});
/**
* Creates a fake log data to be used in tests.
*
* @param payload payload to use for the fake log data.
* @returns a log data to use for testing.
*/
function logDataForTest(payload: LogPayload): FfxLogData {
return {
data: {
// eslint-disable-next-line @typescript-eslint/naming-convention
TargetLog: {
moniker: 'core/foo',
metadata: {
errors: [],
// eslint-disable-next-line @typescript-eslint/naming-convention
component_url: 'fuchsia-pkg://fuchsia.com/foo#metafoo.cm',
timestamp: 12345678900,
severity: 'Info',
tags: ['bar', 'baz'],
pid: 123,
tid: 456,
file: 'foo/main.rs',
line: 25,
},
payload,
},
},
timestamp: 12345,
version: 1
};
};
describe('LogRow', () => {
let state: State;
beforeEach(() => {
state = new State();
});
describe('#constructor', () => {
it('adds title to to non-message cells', async () => {
const logRow = new LogRow(ffxLogToLogRowData(
logDataForTest({
root: {
message: {
value: 'hello vscode',
},
keys: null,
printf: null,
}
}), false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const testFields = [
'000012.35',
'123',
'456',
'core/foo',
'bar,baz',
'Info',
'hello vscode'];
let field: keyof typeof testFields;
for (field in testFields) {
if (testFields[field] === 'hello vscode') {
return;
}
const logField = logRow.children[0].children[field] as HTMLElement;
logField.title.should.equal(testFields[field]);
}
logRow.remove();
});
it('formats target logs', async () => {
const logRow = new LogRow(ffxLogToLogRowData(
logDataForTest({
root: {
message: {
value: 'hello vscode',
},
keys: null,
printf: null,
}
}), false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const testFields = [
'000012.35',
'123',
'456',
'core/foo',
'bar,baz',
'Info',
'hello vscode'];
let field: keyof typeof testFields;
for (field in testFields) {
const logField = logRow.children[0].children[field] as HTMLElement;
logField.innerText.should.equal(testFields[field]);
}
logRow.remove();
});
it('formats html logs', async () => {
const logRow = new LogRow(
{fields: [{key: 'message', text: 'hello vscode'}]}
, {
'timestamp': {displayName: 'timestamp', width: ''},
'pid': {displayName: 'pid', width: ''},
'tid': {displayName: 'tid', width: ''},
'tags': {displayName: 'tags', width: ''},
'moniker': {displayName: 'moniker', width: ''},
'severity': {displayName: 'severity', width: ''},
'message': {displayName: 'messagepw', width: ''},
}, (fieldName, text) => {
const el = document.createElement('span');
if (fieldName === 'message') {
el.innerHTML = text.replace('vscode', '<b>vscode</b>');
}
return el;
});
document.body.appendChild(logRow);
await logRow.updateComplete;
const msgField = logRow.children[0].children[6] as HTMLElement;
msgField.querySelector('b')!.innerText.should.equal('vscode');
logRow.remove();
});
it('formats structured logs', async () => {
const logRow = new LogRow(ffxLogToLogRowData(
logDataForTest({
root: {
message: {
value: 'hello vscode',
},
keys: {
os: 'fuchsia',
number: 1,
},
printf: null,
}
}), false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const testFields =
['000012.35', '123', '456', 'core/foo', 'bar,baz',
'Info', 'hello vscodeos=fuchsia number=1'];
let field: keyof typeof testFields;
for (field in testFields) {
const logField = logRow.children[0].children[field] as HTMLElement;
logField.innerText.should.equal(testFields[field]);
}
logRow.remove();
});
it('formats printf logs', async () => {
const logRow = new LogRow(ffxLogToLogRowData(
logDataForTest({
root: {
message: null,
keys: null,
printf: {
format: '%s is #%d',
args: ['Fuchsia', 1]
},
}
}), false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const testFields =
['000012.35',
'123',
'456',
'core/foo',
'bar,baz',
'Info',
'%s is #%d args=[Fuchsia, 1]'];
let field: keyof typeof testFields;
for (field in testFields) {
const logField = logRow.children[0].children[field] as HTMLElement;
logField.innerText.should.equal(testFields[field]);
}
logRow.remove();
});
it('formats symbolized log', async () => {
const logRow = new LogRow(ffxLogToLogRowData(
symbolizedDataForTest({
root: {
message: {
value: 'this is ignored',
},
keys: null,
printf: null,
}
}), false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const testFields =
['000000.12', '123', '456', 'core/foo', 'my_tag', 'Info', 'symbolized'];
let field: keyof typeof testFields;
for (field in testFields) {
const logField = logRow.children[0].children[field] as HTMLElement;
logField.innerText.should.equal(testFields[field]);
}
logRow.remove();
});
it('formats logging started events', async () => {
let logRow = new LogRow(
ffxLogToLogRowData(
ffxEventForTest('LoggingStarted'), false)!,
state.currentFields,
columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
let moniker = constant.FFX_MONIKER;
let msg = messageForEvent('LoggingStarted', false);
let monikerEl = logRow.children[0].children[3] as HTMLElement;
let msgEl = logRow.children[0].children[6] as HTMLElement;
monikerEl.innerText.should.equal(moniker);
msgEl.innerText.should.equal(msg);
logRow.remove();
logRow = new LogRow(
ffxLogToLogRowData(
ffxEventForTest('LoggingStarted'), true)!,
state.currentFields,
columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
msg = messageForEvent('LoggingStarted', true);
monikerEl = logRow.children[0].children[3] as HTMLElement;
msgEl = logRow.children[0].children[6] as HTMLElement;
monikerEl.innerText.should.equal(moniker);
msgEl.innerText.should.equal(msg);
logRow.remove();
});
it('formats target disconnected events', async () => {
const logRow = new LogRow(
ffxLogToLogRowData(
ffxEventForTest('TargetDisconnected'), false)!,
state.currentFields,
columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
let moniker = constant.FFX_MONIKER;
let msg = messageForEvent('TargetDisconnected', true);
let monikerEl = logRow.children[0].children[3] as HTMLElement;
let msgEl = logRow.children[0].children[6] as HTMLElement;
monikerEl.innerText.should.equal(moniker);
msgEl.innerText.should.equal(msg);
logRow.remove();
});
it('formats malformed log', async () => {
const logRow = new LogRow(
ffxLogToLogRowData(
malformedLogForTest('hello world'), false)!,
state.currentFields,
columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
let msg = 'Malformed target log: hello world';
let msgEl = logRow.children[0].children[6] as HTMLElement;
msgEl.innerText.should.equal(msg);
logRow.remove();
});
it('formats viewer synthesized messages', async () => {
const msg = 'Logs are cool';
const data = {
data: {
// eslint-disable-next-line @typescript-eslint/naming-convention
ViewerEvent: msg,
},
timestamp: 0,
version: 0
};
const logRow = new LogRow(
ffxLogToLogRowData(data, false)!, state.currentFields, columnFormatter);
document.body.appendChild(logRow);
await logRow.updateComplete;
const monikerEl = logRow.children[0].children[3] as HTMLElement;
const msgEl = logRow.children[0].children[6] as HTMLElement;
monikerEl.innerText.should.equal(constant.VSCODE_SYNTHETIC_MONIKER);
msgEl.innerText.should.equal(msg);
logRow.remove();
});
});
});