Fix issue where messages where not queued for non-selected apps

Summary: When determing whether to queue a message, the logic checked if the plugin is enabled on the currently selected app, rather than checking if it is enabled for the receiving app. This diff fixes that.

Reviewed By: passy

Differential Revision: D20000055

fbshipit-source-id: 665f0a650dcee8f7f46aa56f399a4f7d0d0aa1e0
This commit is contained in:
Michel Weststrate
2020-02-21 04:44:57 -08:00
committed by Facebook Github Bot
parent adce24d343
commit 4aec81b059
7 changed files with 167 additions and 70 deletions

View File

@@ -417,7 +417,8 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
if (activePlugin && target) {
pluginKey = getPluginKey(target.id, activePlugin.id);
pluginIsEnabled = pluginIsStarred(
{selectedApp, userStarredPlugins},
userStarredPlugins,
selectedApp,
activePlugin.id,
);
}

View File

@@ -5,10 +5,10 @@ Object {
"androidEmulators": Array [],
"clients": Array [
Object {
"id": "TestApp#Android#unit_test#serial",
"id": "TestApp#Android#MockAndroidDevice#serial",
"query": Object {
"app": "TestApp",
"device": "unit_test",
"device": "MockAndroidDevice",
"device_id": "serial",
"os": "Android",
},
@@ -25,7 +25,7 @@ Object {
},
],
"errors": Array [],
"selectedApp": "TestApp#Android#unit_test#serial",
"selectedApp": "TestApp#Android#MockAndroidDevice#serial",
"selectedDevice": Object {
"deviceType": "physical",
"logs": Array [],
@@ -36,7 +36,7 @@ Object {
"selectedPlugin": "TestPlugin",
"staticView": null,
"uninitializedClients": Array [],
"userPreferredApp": "TestApp#Android#unit_test#serial",
"userPreferredApp": "TestApp#Android#MockAndroidDevice#serial",
"userPreferredDevice": "MockAndroidDevice",
"userPreferredPlugin": "TestPlugin",
"userStarredPlugins": Object {

View File

@@ -53,7 +53,7 @@ test('can create a Fake flipper', async () => {
sendMessage('inc', {});
expect(store.getState().pluginStates).toMatchInlineSnapshot(`
Object {
"TestApp#Android#unit_test#serial#TestPlugin": Object {
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object {
"count": 1,
},
}

View File

@@ -621,17 +621,14 @@ export function getSelectedPluginKey(state: State): string | undefined {
}
export function pluginIsStarred(
state: {
selectedApp: string | null;
userStarredPlugins: State['userStarredPlugins'];
},
userStarredPlugins: State['userStarredPlugins'],
app: string | null,
pluginId: string,
): boolean {
const {selectedApp} = state;
if (!selectedApp) {
if (!app) {
return false;
}
const appInfo = deconstructClientId(selectedApp);
const starred = state.userStarredPlugins[appInfo.app];
const appInfo = deconstructClientId(app);
const starred = userStarredPlugins[appInfo.app];
return starred && starred.indexOf(pluginId) > -1;
}

View File

@@ -40,63 +40,72 @@ export async function createMockFlipperWithPlugin(
device: BaseDevice;
store: Store;
sendMessage(method: string, params: any): void;
createDevice(serial: string): BaseDevice;
createClient(device: BaseDevice, name: string): Client;
}) => Promise<void>,
) {
const store = createStore(reducers);
const device = new BaseDevice(
'serial',
'physical',
'MockAndroidDevice',
'Android',
);
const logger = createStubLogger();
store.dispatch(registerPlugins([pluginClazz]));
store.dispatch({
type: 'REGISTER_DEVICE',
payload: device,
});
function createDevice(serial: string): BaseDevice {
const device = new BaseDevice(
serial,
'physical',
'MockAndroidDevice',
'Android',
);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: device,
});
return device;
}
const query: ClientQuery = {
app: 'TestApp',
os: 'Android',
device: 'unit_test',
device_id: device.serial,
};
const id = buildClientId({
app: query.app,
os: query.os,
device: query.device,
device_id: query.device_id,
});
function createClient(device: BaseDevice, name: string): Client {
const query: ClientQuery = {
app: name,
os: 'Android',
device: device.title,
device_id: device.serial,
};
const id = buildClientId({
app: query.app,
os: query.os,
device: query.device,
device_id: query.device_id,
});
const client = new Client(
id,
query,
null, // create a stub connection to avoid this plugin to be archived?
logger,
store,
[pluginClazz.id],
device,
);
const client = new Client(
id,
query,
null, // create a stub connection to avoid this plugin to be archived?
logger,
store,
[pluginClazz.id],
device,
);
// yikes
client._deviceSet = device;
client.device = {
then() {
return device;
},
} as any;
// yikes
client._deviceSet = device;
client.device = {
then() {
return device;
},
} as any;
// As convenience, by default we select the new client, star the plugin, and select it
store.dispatch({
type: 'NEW_CLIENT',
payload: client,
});
// As convenience, by default we select the new client, star the plugin, and select it
store.dispatch({
type: 'NEW_CLIENT',
payload: client,
});
return client;
}
const device = createDevice('serial');
const client = createClient(device, 'TestApp');
store.dispatch(selectDevice(device));
store.dispatch(selectClient(client.id));
store.dispatch(
@@ -131,5 +140,7 @@ export async function createMockFlipperWithPlugin(
}),
);
},
createDevice,
createClient,
});
}

View File

@@ -9,8 +9,13 @@
import {FlipperPlugin} from '../../plugin';
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
import {GK, Store, Client} from 'flipper';
import {selectPlugin, starPlugin} from '../../reducers/connections';
import {GK, Store, Client} from '../../';
import {
selectPlugin,
starPlugin,
selectClient,
selectDevice,
} from '../../reducers/connections';
import {processMessageQueue} from '../messageQueue';
import {getPluginKey} from '../pluginUtils';
import {TestIdler} from '../Idler';
@@ -87,7 +92,7 @@ test('will process event with GK disabled', async () => {
sendMessage('inc', {});
expect(store.getState().pluginStates).toMatchInlineSnapshot(`
Object {
"TestApp#Android#unit_test#serial#TestPlugin": Object {
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object {
"count": 1,
},
}
@@ -104,12 +109,12 @@ test('queue - events are processed immediately if plugin is selected', async ()
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
sendMessage('inc', {});
expect(store.getState().pluginStates).toMatchInlineSnapshot(`
Object {
"TestApp#Android#unit_test#serial#TestPlugin": Object {
"count": 1,
},
}
`);
Object {
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Object {
"count": 1,
},
}
`);
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
`Object {}`,
);
@@ -135,7 +140,7 @@ test('queue - events are NOT processed immediately if plugin is NOT selected (bu
);
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(`
Object {
"TestApp#Android#unit_test#serial#TestPlugin": Array [
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
Object {
"method": "inc",
"params": Object {},
@@ -193,6 +198,84 @@ test('queue - events are NOT processed immediately if plugin is NOT selected (bu
);
});
test('queue - events are queued for plugins that are favorite when app is not selected', async () => {
await createMockFlipperWithPlugin(
TestPlugin,
async ({device, store, sendMessage, createClient}) => {
await GK.withWhitelistedGK('flipper_event_queue', async () => {
selectDeviceLogs(store);
expect(store.getState().connections.selectedPlugin).not.toBe(
'TestPlugin',
);
const client2 = createClient(device, 'TestApp2');
store.dispatch(selectClient(client2.id));
// Now we send a message to the second client, it should arrive,
// as the plugin was enabled already on the first client as well
sendMessage('inc', {delta: 2});
expect(store.getState().pluginStates).toMatchInlineSnapshot(
`Object {}`,
);
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
`
Object {
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
Object {
"method": "inc",
"params": Object {
"delta": 2,
},
},
],
}
`,
);
});
},
);
});
test('queue - events are queued for plugins that are favorite when app is selected on different device', async () => {
await createMockFlipperWithPlugin(
TestPlugin,
async ({client, store, sendMessage, createDevice, createClient}) => {
await GK.withWhitelistedGK('flipper_event_queue', async () => {
selectDeviceLogs(store);
expect(store.getState().connections.selectedPlugin).not.toBe(
'TestPlugin',
);
const device2 = createDevice('serial2');
const client2 = createClient(device2, client.query.app); // same app id
store.dispatch(selectDevice(device2));
store.dispatch(selectClient(client2.id));
// Now we send a message to the second client, it should arrive,
// as the plugin was enabled already on the first client as well
sendMessage('inc', {delta: 2});
expect(store.getState().pluginStates).toMatchInlineSnapshot(
`Object {}`,
);
expect(store.getState().pluginMessageQueue).toMatchInlineSnapshot(
`
Object {
"TestApp#Android#MockAndroidDevice#serial#TestPlugin": Array [
Object {
"method": "inc",
"params": Object {
"delta": 2,
},
},
],
}
`,
);
});
},
);
});
test('queue - events processing will be paused', async () => {
await createMockFlipperWithPlugin(
TestPlugin,

View File

@@ -18,6 +18,7 @@ import {
} from '../reducers/pluginMessageQueue';
import {Idler, BaseIdler} from './Idler';
import {pluginIsStarred, getSelectedPluginKey} from '../reducers/connections';
import {deconstructPluginKey} from './clientUtils';
const MAX_BACKGROUND_TASK_TIME = 25;
@@ -180,7 +181,11 @@ export function processMessageLater(
break;
case isSelected:
case plugin instanceof FlipperDevicePlugin:
case pluginIsStarred(store.getState().connections, plugin.id):
case pluginIsStarred(
store.getState().connections.userStarredPlugins,
deconstructPluginKey(pluginKey).client,
plugin.id,
):
store.dispatch(
queueMessage(
pluginKey,