Killed pluginStateRecorder

Summary: The state recorder was never updated for Sandy, nor is that really needed since Sandy offers better testing abstractions, and this was a stop gap with potential privacy concerns (due to recording real data). The feature didn't result in any actual test cases, so it seems we won't be missing out with this :)

Reviewed By: passy

Differential Revision: D26813798

fbshipit-source-id: 48ec11516fbc1a47a349a5799713ad05a7e1c73a
This commit is contained in:
Michel Weststrate
2021-03-04 05:59:40 -08:00
committed by Facebook GitHub Bot
parent 7b8054f31c
commit 05a7451173
3 changed files with 2 additions and 231 deletions

View File

@@ -25,7 +25,6 @@ import {setPersistor} from './utils/persistor';
import React from 'react'; import React from 'react';
import path from 'path'; import path from 'path';
import {store} from './store'; import {store} from './store';
import {registerRecordingHooks} from './utils/pluginStateRecorder';
import {cache} from '@emotion/css'; import {cache} from '@emotion/css';
import {CacheProvider} from '@emotion/react'; import {CacheProvider} from '@emotion/react';
import {enableMapSet} from 'immer'; import {enableMapSet} from 'immer';
@@ -196,7 +195,6 @@ function init() {
document.getElementById('root'), document.getElementById('root'),
); );
initLauncherHooks(config(), store); initLauncherHooks(config(), store);
registerRecordingHooks(store);
enableConsoleHook(); enableConsoleHook();
window.flipperGlobalStoreDispatch = store.dispatch; window.flipperGlobalStoreDispatch = store.dispatch;

View File

@@ -10,10 +10,6 @@
import {PersistedStateReducer, FlipperDevicePlugin} from '../plugin'; import {PersistedStateReducer, FlipperDevicePlugin} from '../plugin';
import {State, MiddlewareAPI} from '../reducers/index'; import {State, MiddlewareAPI} from '../reducers/index';
import {setPluginState} from '../reducers/pluginStates'; import {setPluginState} from '../reducers/pluginStates';
import {
flipperRecorderAddEvent,
isRecordingEvents,
} from './pluginStateRecorder';
import { import {
clearMessageQueue, clearMessageQueue,
queueMessages, queueMessages,
@@ -37,7 +33,6 @@ function processMessageClassic(
message: Message, message: Message,
): State { ): State {
const reducerStartTime = Date.now(); const reducerStartTime = Date.now();
flipperRecorderAddEvent(pluginKey, message.method, message.params);
try { try {
const newPluginState = plugin.persistedStateReducer!( const newPluginState = plugin.persistedStateReducer!(
state, state,
@@ -53,16 +48,10 @@ function processMessageClassic(
} }
function processMessagesSandy( function processMessagesSandy(
pluginKey: string,
plugin: _SandyPluginInstance, plugin: _SandyPluginInstance,
messages: Message[], messages: Message[],
) { ) {
const reducerStartTime = Date.now(); const reducerStartTime = Date.now();
if (isRecordingEvents(pluginKey)) {
messages.forEach((message) => {
flipperRecorderAddEvent(pluginKey, message.method, message.params);
});
}
try { try {
plugin.receiveMessages(messages); plugin.receiveMessages(messages);
addBackgroundStat(plugin.definition.id, Date.now() - reducerStartTime); addBackgroundStat(plugin.definition.id, Date.now() - reducerStartTime);
@@ -87,7 +76,7 @@ export function processMessagesImmediately(
messages: Message[], messages: Message[],
) { ) {
if (plugin instanceof _SandyPluginInstance) { if (plugin instanceof _SandyPluginInstance) {
processMessagesSandy(pluginKey, plugin, messages); processMessagesSandy(plugin, messages);
} else { } else {
const persistedState = getCurrentPluginState(store, plugin, pluginKey); const persistedState = getCurrentPluginState(store, plugin, pluginKey);
const newPluginState = messages.reduce( const newPluginState = messages.reduce(
@@ -192,7 +181,7 @@ export async function processMessageQueue(
do { do {
if (_SandyPluginInstance.is(plugin)) { if (_SandyPluginInstance.is(plugin)) {
// Optimization: we could send a batch of messages here // Optimization: we could send a batch of messages here
processMessagesSandy(pluginKey, plugin, [messages[offset]]); processMessagesSandy(plugin, [messages[offset]]);
} else { } else {
newPluginState = processMessageClassic( newPluginState = processMessageClassic(
newPluginState, newPluginState,

View File

@@ -1,216 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import path from 'path';
import fs from 'fs';
import {Store, State} from '../reducers';
import {getPluginKey} from './pluginUtils';
import {serialize} from './serialization';
import {isSandyPlugin} from '../plugin';
let pluginRecordingState: {
recording: string;
pluginName: string;
startState: any;
events: [string, any][];
endState: any;
} = initialRecordingState();
function initialRecordingState(): typeof pluginRecordingState {
return {
recording: '',
startState: undefined,
events: [],
endState: undefined,
pluginName: '',
};
}
export function isRecordingEvents(pluginKey: string) {
return pluginRecordingState.recording === pluginKey;
}
export function flipperRecorderAddEvent(
pluginKey: string,
method: string,
params: any,
) {
if (pluginRecordingState.recording === pluginKey) {
pluginRecordingState.events.push([method, params]);
}
}
async function flipperStartPluginRecording(state: State) {
if (pluginRecordingState.recording) {
throw new Error('A plugin recording is already running');
}
const app = state.connections.selectedApp;
const client = state.connections.clients.find((client) => client.id === app);
if (!app || !client) {
throw new Error('Can only record plugin states if a device is selected');
}
const selectedPlugin = state.connections.selectedPlugin;
const pluginKey = getPluginKey(client.id, null, selectedPlugin!);
const plugin = state.plugins.clientPlugins.get(selectedPlugin!);
if (!selectedPlugin || !plugin) {
throw new Error('Can only record plugin states if a plugin is selected');
}
pluginRecordingState = {
recording: pluginKey,
startState: undefined,
events: [],
endState: undefined,
pluginName: selectedPlugin,
};
// Note that we don't use the plugin's own serializeState, as that might interact with the
// device state, and is used for creating Flipper Exports.
pluginRecordingState.startState = await serialize(
state.pluginStates[pluginKey] ||
(isSandyPlugin(plugin) ? {} : plugin.defaultPersistedState),
);
console.log(
`Started recordig the states of plugin ${selectedPlugin}..... Use window.flipperStopPluginRecording() to finish this process`,
);
}
async function flipperStopPluginRecording(state: State) {
if (!pluginRecordingState.recording) {
throw new Error('No plugin recording is running. ');
}
if (!pluginRecordingState.events.length) {
console.warn('No events were captured, cancelling recording');
pluginRecordingState = initialRecordingState();
return;
}
pluginRecordingState.endState = await serialize(
state.pluginStates[pluginRecordingState.recording],
);
const pluginName = pluginRecordingState.pluginName;
const snapShotFileContents = JSON.stringify(pluginRecordingState);
const snapShotFileName = `${pluginName}.pluginSnapshot.json`;
const testFileName = `${pluginName}EventsRunner.tsx`;
const outDir = getOutputDir(pluginName);
const testFileContents = generateTestSuite(pluginName, snapShotFileName);
await fs.promises.writeFile(
path.join(outDir, snapShotFileName),
snapShotFileContents,
'utf8',
);
await fs.promises.writeFile(
path.join(outDir, testFileName),
testFileContents,
'utf8',
);
console.log(
`Finished recording ${pluginRecordingState.events.length} for plugin ${
pluginRecordingState.recording
}. Generated files ${path.join(outDir, testFileName)} and ${path.join(
outDir,
snapShotFileName,
)}. Move them to the '__tests__ folder of your plugin to incorporate them`,
);
pluginRecordingState = initialRecordingState();
}
export function registerRecordingHooks(store: Store) {
Object.assign(window, {
flipperStartPluginRecording() {
flipperStartPluginRecording(store.getState());
},
flipperStopPluginRecording() {
flipperStopPluginRecording(store.getState());
},
});
}
function getOutputDir(pluginName: string) {
const outDir = path.join(process.cwd(), '..');
const fbPluginDir = path.join(
outDir,
'plugins',
'fb',
pluginName.toLowerCase(),
'__tests__',
);
const defaultPluginDir = path.join(
outDir,
'plugins',
pluginName.toLowerCase(),
'__tests__',
);
if (fs.existsSync(fbPluginDir)) {
return fbPluginDir;
} else if (fs.existsSync(defaultPluginDir)) {
return defaultPluginDir;
}
return outDir;
}
function generateTestSuite(pluginName: string, snapShotFileName: string) {
return `\
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
// This file was initially generated by using \`flipperStartPluginRecording()\` in Flipper console
import fs from 'fs';
import path from 'path';
import {deserialize} from '../ui';
import Plugin from '../';
test('Verify events produce a consistent end state for plugin ${pluginName}', async () => {
const snapshotData: {
startState: string;
endState: string;
events: [string, any][];
} = JSON.parse(
await fs.promises.readFile(
path.join(__dirname, '${snapShotFileName}'),
'utf8',
),
);
const startState: typeof Plugin.defaultPersistedState = deserialize(
snapshotData.startState,
);
const endState: typeof Plugin.defaultPersistedState = deserialize(
snapshotData.endState,
);
const startTime = Date.now();
const generatedEndState = snapshotData.events.reduce(
(store, [method, params]) =>
Plugin.persistedStateReducer(store, method, params),
startState,
);
const totalTime = Date.now() - startTime;
expect(generatedEndState).toEqual(endState);
console.log(
\`Reducer took $\{totalTime\}ms. to process $\{snapshotData.events.length\} events\`,
);
});
`;
}