add test coverage for log processing
Summary: as per title Reviewed By: passy Differential Revision: D13376522 fbshipit-source-id: 4746d3234a13abdf81a23387e57d877714c94b44
This commit is contained in:
committed by
Facebook Github Bot
parent
4546e64509
commit
cbfbd0dd98
58
src/plugins/logs/__tests__/index.node.js
Normal file
58
src/plugins/logs/__tests__/index.node.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {addEntriesToState, processEntry} from '../index';
|
||||
|
||||
const entry = {
|
||||
tag: 'OpenGLRenderer',
|
||||
pid: 18384,
|
||||
|
||||
tid: 18409,
|
||||
message: 'Swap behavior 1',
|
||||
date: new Date('Feb 28 2013 19:00:00 EST'),
|
||||
type: 'debug',
|
||||
};
|
||||
|
||||
test('processEntry', () => {
|
||||
const key = 'key';
|
||||
const processedEntry = processEntry(entry, key);
|
||||
expect(processedEntry.entry).toEqual(entry);
|
||||
expect(processedEntry.row.key).toBe(key);
|
||||
expect(typeof processedEntry.row.height).toBe('number');
|
||||
});
|
||||
|
||||
test('addEntriesToState without current state', () => {
|
||||
const processedEntry = processEntry(entry, 'key');
|
||||
const newState = addEntriesToState([processedEntry]);
|
||||
|
||||
expect(newState.rows.length).toBe(1);
|
||||
expect(newState.entries.length).toBe(1);
|
||||
expect(newState.entries[0]).toEqual(processedEntry);
|
||||
});
|
||||
|
||||
test('addEntriesToState with current state', () => {
|
||||
const currentState = addEntriesToState([processEntry(entry, 'key1')]);
|
||||
const processedEntry = processEntry(
|
||||
{
|
||||
...entry,
|
||||
message: 'new message',
|
||||
},
|
||||
'key2',
|
||||
);
|
||||
const newState = addEntriesToState([processedEntry], currentState);
|
||||
expect(newState.rows.length).toBe(2);
|
||||
expect(newState.entries.length).toBe(2);
|
||||
});
|
||||
|
||||
test('addEntriesToState increase counter on duplicate message', () => {
|
||||
const currentState = addEntriesToState([processEntry(entry, 'key1')]);
|
||||
const processedEntry = processEntry(entry, 'key2');
|
||||
const newState = addEntriesToState([processedEntry], currentState);
|
||||
expect(newState.rows.length).toBe(1);
|
||||
expect(newState.entries.length).toBe(2);
|
||||
expect(newState.rows[0].columns.type.value.props.children).toBe(2);
|
||||
});
|
||||
@@ -243,6 +243,136 @@ function pad(chunk: mixed, len: number): string {
|
||||
return str;
|
||||
}
|
||||
|
||||
export function addEntriesToState(
|
||||
items: Entries,
|
||||
state: $Shape<State> = {
|
||||
rows: [],
|
||||
entries: [],
|
||||
key2entry: {},
|
||||
},
|
||||
): $Shape<State> {
|
||||
const rows = [...state.rows];
|
||||
const entries = [...state.entries];
|
||||
const key2entry = {...state.key2entry};
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const {entry, row} = items[i];
|
||||
entries.push({row, entry});
|
||||
key2entry[row.key] = entry;
|
||||
|
||||
let previousEntry: ?DeviceLogEntry = null;
|
||||
|
||||
if (i > 0) {
|
||||
previousEntry = items[i - 1].entry;
|
||||
} else if (state.rows.length > 0 && state.entries.length > 0) {
|
||||
previousEntry = state.entries[state.entries.length - 1].entry;
|
||||
}
|
||||
|
||||
addRowIfNeeded(rows, row, entry, previousEntry);
|
||||
}
|
||||
|
||||
return {
|
||||
entries,
|
||||
rows,
|
||||
key2entry,
|
||||
};
|
||||
}
|
||||
|
||||
export function addRowIfNeeded(
|
||||
rows: Array<TableBodyRow>,
|
||||
row: TableBodyRow,
|
||||
entry: DeviceLogEntry,
|
||||
previousEntry: ?DeviceLogEntry,
|
||||
) {
|
||||
const previousRow = rows.length > 0 ? rows[rows.length - 1] : null;
|
||||
if (
|
||||
previousRow &&
|
||||
previousEntry &&
|
||||
entry.message === previousEntry.message &&
|
||||
entry.tag === previousEntry.tag &&
|
||||
previousRow.type != null
|
||||
) {
|
||||
// duplicate log, increase counter
|
||||
const count =
|
||||
previousRow.columns.type.value &&
|
||||
previousRow.columns.type.value.props &&
|
||||
typeof previousRow.columns.type.value.props.children === 'number'
|
||||
? previousRow.columns.type.value.props.children + 1
|
||||
: 2;
|
||||
const type = LOG_TYPES[previousRow.type] || LOG_TYPES.debug;
|
||||
previousRow.columns.type.value = (
|
||||
<LogCount backgroundColor={type.color}>{count}</LogCount>
|
||||
);
|
||||
} else {
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
export function processEntry(
|
||||
entry: DeviceLogEntry,
|
||||
key: string,
|
||||
): {
|
||||
row: TableBodyRow,
|
||||
entry: DeviceLogEntry,
|
||||
} {
|
||||
console.log(JSON.stringify(entry));
|
||||
const {icon, style} = LOG_TYPES[(entry.type: string)] || LOG_TYPES.debug;
|
||||
|
||||
// clean message
|
||||
const message = entry.message.trim();
|
||||
entry.type === 'error';
|
||||
|
||||
// build the item, it will either be batched or added straight away
|
||||
return {
|
||||
entry,
|
||||
row: {
|
||||
columns: {
|
||||
type: {
|
||||
value: icon,
|
||||
align: 'center',
|
||||
},
|
||||
time: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>
|
||||
{entry.date.toTimeString().split(' ')[0] +
|
||||
'.' +
|
||||
pad(entry.date.getMilliseconds(), 3)}
|
||||
</HiddenScrollText>
|
||||
),
|
||||
},
|
||||
message: {
|
||||
value: <HiddenScrollText code={true}>{message}</HiddenScrollText>,
|
||||
},
|
||||
tag: {
|
||||
value: <HiddenScrollText code={true}>{entry.tag}</HiddenScrollText>,
|
||||
isFilterable: true,
|
||||
},
|
||||
pid: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>{String(entry.pid)}</HiddenScrollText>
|
||||
),
|
||||
isFilterable: true,
|
||||
},
|
||||
tid: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>{String(entry.tid)}</HiddenScrollText>
|
||||
),
|
||||
isFilterable: true,
|
||||
},
|
||||
app: {
|
||||
value: <HiddenScrollText code={true}>{entry.app}</HiddenScrollText>,
|
||||
isFilterable: true,
|
||||
},
|
||||
},
|
||||
height: getLineCount(message) * 15 + 10, // 15px per line height + 8px padding
|
||||
style,
|
||||
type: entry.type,
|
||||
filterValue: entry.message,
|
||||
key,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default class LogTable extends FlipperDevicePlugin<
|
||||
State,
|
||||
Actions,
|
||||
@@ -322,8 +452,10 @@ export default class LogTable extends FlipperDevicePlugin<
|
||||
supportedColumns.includes(obj.key),
|
||||
);
|
||||
|
||||
const initialState = this.addEntriesToState(
|
||||
this.device.getLogs().map(this.processEntry),
|
||||
const initialState = addEntriesToState(
|
||||
this.device
|
||||
.getLogs()
|
||||
.map(log => processEntry(log, String(this.counter++))),
|
||||
);
|
||||
this.state = {
|
||||
...initialState,
|
||||
@@ -335,7 +467,7 @@ export default class LogTable extends FlipperDevicePlugin<
|
||||
};
|
||||
|
||||
this.logListener = this.device.addLogListener((entry: DeviceLogEntry) => {
|
||||
const processedEntry = this.processEntry(entry);
|
||||
const processedEntry = processEntry(entry, String(this.counter++));
|
||||
this.incrementCounterIfNeeded(processedEntry.entry);
|
||||
this.scheudleEntryForBatch(processedEntry);
|
||||
});
|
||||
@@ -365,73 +497,6 @@ export default class LogTable extends FlipperDevicePlugin<
|
||||
}
|
||||
};
|
||||
|
||||
processEntry = (
|
||||
entry: DeviceLogEntry,
|
||||
): {
|
||||
row: TableBodyRow,
|
||||
entry: DeviceLogEntry,
|
||||
} => {
|
||||
const {icon, style} = LOG_TYPES[(entry.type: string)] || LOG_TYPES.debug;
|
||||
|
||||
// clean message
|
||||
const message = entry.message.trim();
|
||||
entry.type === 'error';
|
||||
|
||||
// build the item, it will either be batched or added straight away
|
||||
return {
|
||||
entry,
|
||||
row: {
|
||||
columns: {
|
||||
type: {
|
||||
value: icon,
|
||||
align: 'center',
|
||||
},
|
||||
time: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>
|
||||
{entry.date.toTimeString().split(' ')[0] +
|
||||
'.' +
|
||||
pad(entry.date.getMilliseconds(), 3)}
|
||||
</HiddenScrollText>
|
||||
),
|
||||
},
|
||||
message: {
|
||||
value: <HiddenScrollText code={true}>{message}</HiddenScrollText>,
|
||||
},
|
||||
tag: {
|
||||
value: <HiddenScrollText code={true}>{entry.tag}</HiddenScrollText>,
|
||||
isFilterable: true,
|
||||
},
|
||||
pid: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>
|
||||
{String(entry.pid)}
|
||||
</HiddenScrollText>
|
||||
),
|
||||
isFilterable: true,
|
||||
},
|
||||
tid: {
|
||||
value: (
|
||||
<HiddenScrollText code={true}>
|
||||
{String(entry.tid)}
|
||||
</HiddenScrollText>
|
||||
),
|
||||
isFilterable: true,
|
||||
},
|
||||
app: {
|
||||
value: <HiddenScrollText code={true}>{entry.app}</HiddenScrollText>,
|
||||
isFilterable: true,
|
||||
},
|
||||
},
|
||||
height: getLineCount(message) * 15 + 10, // 15px per line height + 8px padding
|
||||
style,
|
||||
type: entry.type,
|
||||
filterValue: entry.message,
|
||||
key: String(this.counter++),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
scheudleEntryForBatch = (item: {
|
||||
row: TableBodyRow,
|
||||
entry: DeviceLogEntry,
|
||||
@@ -448,46 +513,11 @@ export default class LogTable extends FlipperDevicePlugin<
|
||||
const thisBatch = this.batch;
|
||||
this.batch = [];
|
||||
this.queued = false;
|
||||
this.setState(state => this.addEntriesToState(thisBatch, state));
|
||||
this.setState(state => addEntriesToState(thisBatch, state));
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
addEntriesToState = (
|
||||
items: Entries,
|
||||
state: $Shape<State> = {
|
||||
rows: [],
|
||||
entries: [],
|
||||
key2entry: {},
|
||||
},
|
||||
): $Shape<State> => {
|
||||
const rows = [...state.rows];
|
||||
const entries = [...state.entries];
|
||||
const key2entry = {...state.key2entry};
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const {entry, row} = items[i];
|
||||
entries.push({row, entry});
|
||||
key2entry[row.key] = entry;
|
||||
|
||||
let previousEntry: ?DeviceLogEntry = null;
|
||||
|
||||
if (i > 0) {
|
||||
previousEntry = items[i - 1].entry;
|
||||
} else if (state.rows.length > 0 && state.entries.length > 0) {
|
||||
previousEntry = state.entries[state.entries.length - 1].entry;
|
||||
}
|
||||
|
||||
this.addRowIfNeeded(rows, row, entry, previousEntry);
|
||||
}
|
||||
|
||||
return {
|
||||
entries,
|
||||
rows,
|
||||
key2entry,
|
||||
};
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.batchTimer) {
|
||||
clearTimeout(this.batchTimer);
|
||||
@@ -498,36 +528,6 @@ export default class LogTable extends FlipperDevicePlugin<
|
||||
}
|
||||
}
|
||||
|
||||
addRowIfNeeded(
|
||||
rows: Array<TableBodyRow>,
|
||||
row: TableBodyRow,
|
||||
entry: DeviceLogEntry,
|
||||
previousEntry: ?DeviceLogEntry,
|
||||
) {
|
||||
const previousRow = rows.length > 0 ? rows[rows.length - 1] : null;
|
||||
if (
|
||||
previousRow &&
|
||||
previousEntry &&
|
||||
entry.message === previousEntry.message &&
|
||||
entry.tag === previousEntry.tag &&
|
||||
previousRow.type != null
|
||||
) {
|
||||
// duplicate log, increase counter
|
||||
const count =
|
||||
previousRow.columns.type.value &&
|
||||
previousRow.columns.type.value.props &&
|
||||
typeof previousRow.columns.type.value.props.children === 'number'
|
||||
? previousRow.columns.type.value.props.children + 1
|
||||
: 2;
|
||||
const type = LOG_TYPES[previousRow.type] || LOG_TYPES.debug;
|
||||
previousRow.columns.type.value = (
|
||||
<LogCount backgroundColor={type.color}>{count}</LogCount>
|
||||
);
|
||||
} else {
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
clearLogs = () => {
|
||||
this.setState({
|
||||
entries: [],
|
||||
|
||||
Reference in New Issue
Block a user