From 7650ab620d616d2c94c4d9b02867586bde70a9bf Mon Sep 17 00:00:00 2001 From: Michel Weststrate Date: Tue, 9 Feb 2021 04:12:09 -0800 Subject: [PATCH] Fixed bug causing pending events of non-sandy plugins not to be part of the export Summary: During testing I noticed that even though plugin queues were flushed, the processed messages didn't end up in the export snapshots. This was caused by holding a ref of an older snapshot of the state Changelog: Fixed an issue where data that arrived in the background was not part of the generated Flipper export. Reviewed By: nikoant Differential Revision: D26250897 fbshipit-source-id: ddd3f5bb19e38a1b13498d03f235bf63858eb8f8 --- .../src/utils/__tests__/exportData.node.tsx | 83 ++++++++++++++++++- desktop/app/src/utils/exportData.tsx | 3 +- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/desktop/app/src/utils/__tests__/exportData.node.tsx b/desktop/app/src/utils/__tests__/exportData.node.tsx index 2a5203c57..9a475a960 100644 --- a/desktop/app/src/utils/__tests__/exportData.node.tsx +++ b/desktop/app/src/utils/__tests__/exportData.node.tsx @@ -1095,6 +1095,7 @@ const sandyTestPlugin = new _SandyPluginDefinition( }); }); return { + counter, enableCustomExport() { client.onExport(async (idler, onStatus) => { if (idler.shouldIdle()) { @@ -1116,15 +1117,19 @@ const sandyTestPlugin = new _SandyPluginDefinition( ); test('Sandy plugins are exported properly', async () => { - const {client, sendMessage, store} = await createMockFlipperWithPlugin( - sandyTestPlugin, - ); + const { + client, + sendMessage, + store, + device, + } = await createMockFlipperWithPlugin(sandyTestPlugin); // We do select another plugin, to verify that pending message queues are indeed processed before exporting store.dispatch( selectPlugin({ selectedPlugin: 'DeviceLogs', - selectedApp: client.id, + selectedApp: null, + selectedDevice: device, deepLinkPayload: null, }), ); @@ -1134,7 +1139,16 @@ test('Sandy plugins are exported properly', async () => { sendMessage('inc', {}); sendMessage('inc', {}); + // not flushed + expect( + client.sandyPluginStates.get(sandyTestPlugin.id)!.instanceApi.counter.get(), + ).toBe(0); + const storeExport = await exportStore(store); + expect( + client.sandyPluginStates.get(sandyTestPlugin.id)!.instanceApi.counter.get(), + ).toBe(3); + const serial = storeExport.exportStoreData.device!.serial; expect(serial).not.toBeFalsy(); expect(storeExport.exportStoreData.pluginStates2).toEqual({ @@ -1144,6 +1158,67 @@ test('Sandy plugins are exported properly', async () => { }); }); +test('Non sandy plugins are exported properly if they are still queued', async () => { + type State = { + counter: number; + }; + + const {sendMessage, store, device} = await createMockFlipperWithPlugin( + class TestPlugin extends FlipperPlugin { + static id = 'TestPlugin'; + + static defaultPersistedState: State = { + counter: 0, + }; + + static persistedStateReducer(p: State, method: string): State { + if (method === 'inc') { + return { + counter: p.counter + 1, + }; + } + return p; + } + } as any, + ); + + // We do select another plugin, to verify that pending message queues are indeed processed before exporting + store.dispatch( + selectPlugin({ + selectedPlugin: 'DeviceLogs', + selectedApp: null, + selectedDevice: device, + deepLinkPayload: null, + }), + ); + + // Deliberately not using 'act' here, to verify that exportStore itself makes sure buffers are flushed first + sendMessage('inc', {}); + sendMessage('inc', {}); + sendMessage('inc', {}); + + // not flushed + expect(store.getState().pluginStates).toMatchInlineSnapshot(`Object {}`); + + const storeExport = await exportStore(store); + // flushed + expect(store.getState().pluginStates).toMatchInlineSnapshot(` + Object { + "TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object { + "counter": 3, + }, + } + `); + + const serial = storeExport.exportStoreData.device!.serial; + expect(serial).not.toBeFalsy(); + expect(storeExport.exportStoreData.store.pluginStates).toMatchInlineSnapshot(` + Object { + "TestApp#Android#MockAndroidDevice#${serial}#TestPlugin": "{\\"counter\\":3}", + } + `); +}); + test('Sandy plugins with custom export are exported properly', async () => { const {client, sendMessage, store} = await createMockFlipperWithPlugin( sandyTestPlugin, diff --git a/desktop/app/src/utils/exportData.tsx b/desktop/app/src/utils/exportData.tsx index 24b3a02c3..61d013f31 100644 --- a/desktop/app/src/utils/exportData.tsx +++ b/desktop/app/src/utils/exportData.tsx @@ -652,7 +652,7 @@ async function getStoreExport( exportData: ExportType; fetchMetaDataErrors: {[plugin: string]: Error} | null; }> { - const state = store.getState(); + let state = store.getState(); const {clients, selectedApp, selectedDevice} = state.connections; const pluginsToProcess = determinePluginsToProcess( clients, @@ -662,6 +662,7 @@ async function getStoreExport( statusUpdate?.('Preparing to process data queues for plugins...'); await processQueues(store, pluginsToProcess, statusUpdate, idler); + state = store.getState(); statusUpdate && statusUpdate('Preparing to fetch metadata from client...'); const fetchMetaDataMarker = `${EXPORT_FLIPPER_TRACE_EVENT}:fetch-meta-data`;