Adding test converage for plugin loading

Summary: Adds test for the plugin reducer and dispatcher

Reviewed By: jknoxville, passy

Differential Revision: D13082652

fbshipit-source-id: 4af2c7721c4d88abbd332d610ff71d5db78e721c
This commit is contained in:
Daniel Büchele
2018-11-15 07:25:58 -08:00
committed by Facebook Github Bot
parent 1edc91512d
commit 0b43d219c3
4 changed files with 222 additions and 16 deletions

View File

@@ -0,0 +1,10 @@
/**
* 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 {FlipperPlugin} from '../../plugin.js';
export default class extends FlipperPlugin {}

View File

@@ -0,0 +1,121 @@
/**
* 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 dispatcher, {
getDynamicPlugins,
checkDisabled,
checkGK,
requirePlugin,
} from '../plugins';
import path from 'path';
import {remote} from 'electron';
import {FlipperPlugin} from '../../plugin';
import reducers from '../../reducers/index.js';
import Logger from '../../fb-stubs/Logger.js';
import configureStore from 'redux-mock-store';
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
const mockStore = configureStore([])(reducers(undefined, {type: 'INIT'}));
const logger = new Logger();
test('dispatcher dispatches REGISTER_PLUGINS', () => {
dispatcher(mockStore, logger);
const actions = mockStore.getActions();
expect(actions[0].type).toBe('REGISTER_PLUGINS');
});
test('getDynamicPlugins returns empty array', () => {
// $FlowFixMe process.env not defined in electron API spec
remote.process.env.PLUGINS = null;
const res = getDynamicPlugins();
expect(res).toEqual([]);
});
test('getDynamicPlugins returns empty array for invalid JSON', () => {
// $FlowFixMe process.env not defined in electron API spec
remote.process.env.PLUGINS = 'invalid JOSN }}[]';
const res = getDynamicPlugins();
expect(res).toEqual([]);
});
test('getDynamicPlugins from env', () => {
const plugins = [{name: 'test'}];
// $FlowFixMe process.env not defined in electron API spec
remote.process.env.PLUGINS = JSON.stringify(plugins);
const res = getDynamicPlugins();
expect(res).toEqual(plugins);
});
test('checkDisabled', () => {
const disabledPlugin = 'pluginName';
const config = {disabledPlugins: [disabledPlugin]};
// $FlowFixMe process.env not defined in electron API spec
remote.process.env.CONFIG = JSON.stringify(config);
const disabled = checkDisabled();
expect(
disabled({
name: 'other Name',
out: './test/index.js',
}),
).toBeTruthy();
expect(
disabled({
name: disabledPlugin,
out: './test/index.js',
}),
).toBeFalsy();
});
test('checkGK for plugin without GK', () => {
expect(
checkGK({
name: 'pluginID',
out: './test/index.js',
}),
).toBeTruthy();
});
test('checkGK for passing plugin', () => {
expect(
checkGK({
name: 'pluginID',
gatekeeper: TEST_PASSING_GK,
out: './test/index.js',
}),
).toBeTruthy();
});
test('checkGK for failing plugin', () => {
expect(
checkGK({
name: 'pluginID',
gatekeeper: TEST_FAILING_GK,
out: './test/index.js',
}),
).toBeFalsy();
});
test('requirePlugin returns null for invalid requires', () => {
const plugin = requirePlugin(require)({
name: 'pluginID',
out: 'this/path/does not/exist',
});
expect(plugin).toBeNull();
});
test('requirePlugin loads plugin', () => {
const plugin = requirePlugin(require)({
name: 'pluginID',
out: path.join(__dirname, 'TestPlugin.js'),
// $FlowFixMe Electron require returns default exports wrapped in an object
}).default;
expect(plugin.prototype).toBeInstanceOf(FlipperPlugin);
});

View File

@@ -37,7 +37,7 @@ export default (store: Store, logger: Logger) => {
> = [...getBundledPlugins(), ...getDynamicPlugins()]
.filter(disabled)
.filter(checkGK)
.map(requirePlugin)
.map(requirePlugin())
.filter(Boolean);
store.dispatch(registerPlugins(initialPlugins));
@@ -69,7 +69,7 @@ function getBundledPlugins(): Array<PluginDefinition> {
}));
}
function getDynamicPlugins() {
export function getDynamicPlugins() {
let dynamicPlugins: Array<PluginDefinition> = [];
try {
// $FlowFixMe process.env not defined in electron API spec
@@ -80,7 +80,7 @@ function getDynamicPlugins() {
return dynamicPlugins;
}
function checkGK(plugin: PluginDefinition): boolean {
export function checkGK(plugin: PluginDefinition): boolean {
const result = plugin.gatekeeper && !GK.get(plugin.gatekeeper);
if (!result) {
console.warn(
@@ -92,7 +92,7 @@ function checkGK(plugin: PluginDefinition): boolean {
return !result;
}
function checkDisabled(): (plugin: PluginDefinition) => boolean {
export function checkDisabled(): (plugin: PluginDefinition) => boolean {
let disabledPlugins: Set<string> = new Set();
try {
disabledPlugins = new Set(
@@ -106,17 +106,21 @@ function checkDisabled(): (plugin: PluginDefinition) => boolean {
return (plugin: PluginDefinition) => !disabledPlugins.has(plugin.name);
}
function requirePlugin(
pluginDefinition: PluginDefinition,
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> {
try {
const plugin = window.electronRequire(pluginDefinition.out);
if (!plugin.prototype instanceof FlipperBasePlugin) {
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
export function requirePlugin(
requireFunction: Function = window.electronRequire,
) {
return (
pluginDefinition: PluginDefinition,
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> => {
try {
const plugin = requireFunction(pluginDefinition.out);
if (!plugin.prototype instanceof FlipperBasePlugin) {
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
}
return plugin;
} catch (e) {
console.error(pluginDefinition, e);
return null;
}
return plugin;
} catch (e) {
console.error(pluginDefinition, e);
return null;
}
};
}

View File

@@ -0,0 +1,71 @@
/**
* 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 {default as reducer, registerPlugins} from '../plugins';
import {
FlipperBasePlugin,
FlipperPlugin,
FlipperDevicePlugin,
} from '../../plugin.js';
const testBasePlugin = class extends FlipperBasePlugin {
static id = 'TestPlugin';
};
const testPlugin = class extends FlipperPlugin {
static id = 'TestPlugin';
};
const testDevicePlugin = class extends FlipperDevicePlugin {
static id = 'TestDevicePlugin';
};
test('add clientPlugin', () => {
const res = reducer(
{
devicePlugins: new Map(),
clientPlugins: new Map(),
},
registerPlugins([testPlugin]),
);
expect(res.clientPlugins.get(testPlugin.id)).toBe(testPlugin);
});
test('add devicePlugin', () => {
const res = reducer(
{
devicePlugins: new Map(),
clientPlugins: new Map(),
},
registerPlugins([testDevicePlugin]),
);
expect(res.devicePlugins.get(testDevicePlugin.id)).toBe(testDevicePlugin);
});
test('do not add plugin twice', () => {
const res = reducer(
{
devicePlugins: new Map(),
clientPlugins: new Map(),
},
registerPlugins([testPlugin, testPlugin]),
);
expect(res.clientPlugins.size).toEqual(1);
});
test('do not add other classes', () => {
const res = reducer(
{
devicePlugins: new Map(),
clientPlugins: new Map(),
},
// $FlowFixMe testing wrong classes on purpose here
registerPlugins([testBasePlugin]),
);
expect(res.devicePlugins.size).toEqual(0);
expect(res.devicePlugins.size).toEqual(0);
});