Unit tests for the metrics

Summary: Added unit tests for the "WASTED_BYTES" for the fresco plugin

Reviewed By: passy

Differential Revision: D15610871

fbshipit-source-id: dc9bd84363e1ba22fc96890b74e217372188a9d0
This commit is contained in:
Pritesh Nandgaonkar
2019-06-04 14:12:44 -07:00
committed by Facebook Github Bot
parent 72a39cb09d
commit ace19e5d36
2 changed files with 275 additions and 17 deletions

View File

@@ -0,0 +1,259 @@
/**
* 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 FrescoPlugin from '../index.js';
import type {PersistedState, ImageEventWithId} from '../index.js';
function mockPersistedState(
imageSizes: Array<{
width: number,
height: number,
}>,
viewport: {
width: number,
height: number,
},
): PersistedState {
const scanDisplayTime = {};
scanDisplayTime[1] = 3;
const events: Array<ImageEventWithId> = [
{
imageIds: [...Array(imageSizes.length).keys()].map(String),
eventId: 0,
attribution: [],
startTime: 1,
endTime: 2,
source: 'source',
coldStart: true,
viewport: {...viewport, scanDisplayTime},
},
];
const imagesMap = imageSizes.reduce((acc, val, index) => {
acc[index] = {
imageId: String(index),
width: val.width,
height: val.height,
sizeBytes: 10,
data: undefined,
};
return acc;
}, {});
return {
surfaceList: new Set(),
images: [],
events,
imagesMap,
closeableReferenceLeaks: [],
};
}
test('the metric reducer for the input having regression', () => {
const persistedState = mockPersistedState(
[
{
width: 150,
height: 150,
},
{
width: 150,
height: 150,
},
{
width: 150,
height: 150,
},
],
{
width: 100,
height: 100,
},
);
expect(FrescoPlugin.metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = FrescoPlugin.metricsReducer(persistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 37500,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});
test('the metric reducer for the input having no regression', () => {
const persistedState = mockPersistedState(
[
{
width: 50,
height: 10,
},
{
width: 50,
height: 50,
},
{
width: 50,
height: 50,
},
],
{
width: 100,
height: 100,
},
);
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = metricsReducer(persistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 0,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});
test('the metric reducer for the default persisted state', () => {
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = metricsReducer(FrescoPlugin.defaultPersistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 0,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});
test('the metric reducer with the events data but with no imageData in imagesMap ', () => {
const persistedState = mockPersistedState(
[
{
width: 50,
height: 10,
},
{
width: 50,
height: 50,
},
{
width: 50,
height: 50,
},
],
{
width: 100,
height: 100,
},
);
persistedState.imagesMap = {};
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = metricsReducer(persistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 0,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});
test('the metric reducer with the no viewPort data in events', () => {
const persistedState = mockPersistedState(
[
{
width: 50,
height: 10,
},
{
width: 50,
height: 50,
},
{
width: 50,
height: 50,
},
],
{
width: 100,
height: 100,
},
);
delete persistedState.events[0].viewport;
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = metricsReducer(persistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 0,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});
test('the metric reducer with the multiple events', () => {
const scanDisplayTime = {};
scanDisplayTime[1] = 3;
const events: Array<ImageEventWithId> = [
{
imageIds: ['0', '1'],
eventId: 0,
attribution: [],
startTime: 1,
endTime: 2,
source: 'source',
coldStart: true,
viewport: {width: 100, height: 100, scanDisplayTime},
},
{
imageIds: ['2', '3'],
eventId: 1,
attribution: [],
startTime: 1,
endTime: 2,
source: 'source',
coldStart: true,
viewport: {width: 50, height: 50, scanDisplayTime},
},
];
const imageSizes = [
{
width: 150,
height: 150,
},
{
width: 100,
height: 100,
},
{
width: 250,
height: 250,
},
{
width: 300,
height: 300,
},
];
const imagesMap = imageSizes.reduce((acc, val, index) => {
acc[index] = {
imageId: String(index),
width: val.width,
height: val.height,
sizeBytes: 10,
data: undefined,
};
return acc;
}, {});
const persistedState = {
surfaceList: new Set(),
images: [],
events,
imagesMap,
};
const metricsReducer = FrescoPlugin.metricsReducer;
expect(metricsReducer).toBeDefined();
//$FlowFixMe: Added a check if the metricsReducer exists in FrescoPlugin
const metrics = metricsReducer(persistedState);
expect(metrics).resolves.toMatchObject({
WASTED_BYTES: 160000,
CLOSEABLE_REFERENCE_LEAKS: 0,
});
});

View File

@@ -33,7 +33,7 @@ import ImagePool from './ImagePool.js';
export type ImageEventWithId = ImageEvent & {eventId: number}; export type ImageEventWithId = ImageEvent & {eventId: number};
type PersistedState = { export type PersistedState = {
surfaceList: Set<string>, surfaceList: Set<string>,
images: ImagesList, images: ImagesList,
events: Array<ImageEventWithId>, events: Array<ImageEventWithId>,
@@ -157,28 +157,27 @@ export default class extends FlipperPlugin<PluginState, *, PersistedState> {
persistedState: PersistedState, persistedState: PersistedState,
): Promise<MetricType> => { ): Promise<MetricType> => {
const {events, imagesMap, closeableReferenceLeaks} = persistedState; const {events, imagesMap, closeableReferenceLeaks} = persistedState;
const wastedBytes = (events || []).reduce((acc, event) => { const wastedBytes = (events || []).reduce((acc, event) => {
const {viewport, imageIds} = event; const {viewport, imageIds} = event;
if (!viewport) { if (!viewport) {
return acc; return acc;
} }
return ( return imageIds.reduce((innerAcc, imageID) => {
acc + const imageData: ImageData = imagesMap[imageID];
imageIds.reduce((innerAcc, imageID) => { if (!imageData) {
const imageData: ImageData = imagesMap[imageID]; return innerAcc;
if (!imageData) { }
return innerAcc; const imageWidth: number = imageData.width;
} const imageHeight: number = imageData.height;
const imageWidth: number = imageData.width; const viewPortWidth: number = viewport.width;
const imageHeight: number = imageData.height; const viewPortHeight: number = viewport.height;
const viewPortWidth: number = viewport.width; const viewPortArea = viewPortWidth * viewPortHeight;
const viewPortHeight: number = viewport.height; const imageArea = imageWidth * imageHeight;
const viewPortArea = viewPortWidth * viewPortHeight; return innerAcc + Math.max(0, imageArea - viewPortArea);
const imageArea = imageWidth * imageHeight; }, acc);
return innerAcc + Math.max(0, imageArea - viewPortArea);
}, acc)
);
}, 0); }, 0);
return Promise.resolve({ return Promise.resolve({
WASTED_BYTES: wastedBytes, WASTED_BYTES: wastedBytes,
CLOSEABLE_REFERENCE_LEAKS: (closeableReferenceLeaks || []).length, CLOSEABLE_REFERENCE_LEAKS: (closeableReferenceLeaks || []).length,