Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[config] transform plugin deprecations before checking for unused settings #21294

Merged
merged 8 commits into from
Nov 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/deprecation/get_transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { noop } from 'lodash';

import { createTransform } from './create_transform';
import { rename, unused } from './deprecations';

export async function getTransform(spec) {
const deprecationsProvider = spec.getDeprecationsProvider() || noop;
if (!deprecationsProvider) return;
const transforms = await deprecationsProvider({ rename, unused }) || [];
return createTransform(transforms);
}
1 change: 1 addition & 0 deletions src/deprecation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
import { rename, unused } from './deprecations';

export { createTransform } from './create_transform';
export { getTransform } from './get_transform';
export const Deprecations = { rename, unused };
13 changes: 4 additions & 9 deletions src/plugin_discovery/plugin_config/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@
* under the License.
*/

import { get, noop } from 'lodash';
import { get } from 'lodash';

import * as serverConfig from '../../server/config';
import { createTransform, Deprecations } from '../../deprecation';

async function getDeprecationTransformer(spec) {
const provider = spec.getDeprecationsProvider() || noop;
return createTransform(await provider(Deprecations) || []);
}
import { getTransform } from '../../deprecation';

/**
* Get the settings for a pluginSpec from the raw root settings while
Expand All @@ -38,7 +33,7 @@ async function getDeprecationTransformer(spec) {
*/
export async function getSettings(spec, rootSettings, logDeprecation) {
const prefix = spec.getConfigPrefix();
const transformer = await getDeprecationTransformer(spec);
const rawSettings = get(serverConfig.transformDeprecations(rootSettings), prefix);
return transformer(rawSettings, logDeprecation);
const transform = await getTransform(spec);
return transform(rawSettings, logDeprecation);
}
28 changes: 20 additions & 8 deletions src/server/config/complete.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@
import { difference } from 'lodash';
import { transformDeprecations } from './transform_deprecations';
import { unset, formatListAsProse, getFlattenedObject } from '../../utils';
import { getTransform } from '../../deprecation';


const getFlattenedKeys = object => (
Object.keys(getFlattenedObject(object))
);

const getUnusedConfigKeys = (disabledPluginSpecs, rawSettings, configValues) => {
const settings = transformDeprecations(rawSettings);
async function getUnusedConfigKeys(plugins, disabledPluginSpecs, rawSettings, configValues) {
// transform deprecated settings
const transforms = [
transformDeprecations,
...await Promise.all(plugins.map(({ spec }) => getTransform(spec)))
];
const settings = transforms.reduce((a, c) => c(a), rawSettings);

// remove config values from disabled plugins
for (const spec of disabledPluginSpecs) {
Expand All @@ -44,27 +51,32 @@ const getUnusedConfigKeys = (disabledPluginSpecs, rawSettings, configValues) =>
}

return difference(inputKeys, appliedKeys);
};
}

export default function (kbnServer, server, config) {
export default async function (kbnServer, server, config) {

server.decorate('server', 'config', function () {
return kbnServer.config;
});

const unusedKeys = getUnusedConfigKeys(kbnServer.disabledPluginSpecs, kbnServer.settings, config.get())
.map(key => `"${key}"`);
const unusedKeys = await getUnusedConfigKeys(
kbnServer.plugins,
kbnServer.disabledPluginSpecs,
kbnServer.settings,
config.get()
);

if (!unusedKeys.length) {
return;
}

const desc = unusedKeys.length === 1
const formattedUnusedKeys = unusedKeys.map(key => `"${key}"`);
const desc = formattedUnusedKeys.length === 1
? 'setting was'
: 'settings were';

const error = new Error(
`${formatListAsProse(unusedKeys)} ${desc} not applied. ` +
`${formatListAsProse(formattedUnusedKeys)} ${desc} not applied. ` +
'Check for spelling errors and ensure that expected ' +
'plugins are installed.'
);
Expand Down
76 changes: 51 additions & 25 deletions src/server/config/complete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('server/config completeMixin()', function () {
settings = {},
configValues = {},
disabledPluginSpecs = [],
plugins = [],
} = options;

const server = {
Expand All @@ -48,32 +49,31 @@ describe('server/config completeMixin()', function () {
settings,
server,
config,
disabledPluginSpecs
disabledPluginSpecs,
plugins
};

const callCompleteMixin = () => {
completeMixin(kbnServer, server, config);
};
const callCompleteMixin = () => completeMixin(kbnServer, server, config);

return { config, callCompleteMixin, server };
};

describe('server decoration', () => {
it('adds a config() function to the server', () => {
it('adds a config() function to the server', async () => {
const { config, callCompleteMixin, server } = setup({
settings: {},
configValues: {}
});

callCompleteMixin();
await callCompleteMixin();
sinon.assert.calledOnce(server.decorate);
sinon.assert.calledWith(server.decorate, 'server', 'config', sinon.match.func);
expect(server.decorate.firstCall.args[2]()).toBe(config);
});
});

describe('all settings used', () => {
it('should not throw', function () {
it('should not throw', async function () {
const { callCompleteMixin } = setup({
settings: {
used: true
Expand All @@ -83,11 +83,11 @@ describe('server/config completeMixin()', function () {
},
});

callCompleteMixin();
await expect(callCompleteMixin()).resolves.toBe(undefined);
});

describe('more config values than settings', () => {
it('should not throw', function () {
it('should not throw', async function () {
const { callCompleteMixin } = setup({
settings: {
used: true
Expand All @@ -98,13 +98,13 @@ describe('server/config completeMixin()', function () {
}
});

callCompleteMixin();
await expect(callCompleteMixin()).resolves.toBe(undefined);
});
});
});

describe('env setting specified', () => {
it('should not throw', () => {
it('should not throw', async () => {
const { callCompleteMixin } = setup({
settings: {
env: 'development'
Expand All @@ -116,12 +116,12 @@ describe('server/config completeMixin()', function () {
}
});

callCompleteMixin();
await expect(callCompleteMixin()).resolves.toBe(undefined);
});
});

describe('settings include non-default array settings', () => {
it('should not throw', () => {
it('should not throw', async () => {
const { callCompleteMixin } = setup({
settings: {
foo: [
Expand All @@ -134,12 +134,13 @@ describe('server/config completeMixin()', function () {
}
});

callCompleteMixin();
await expect(callCompleteMixin()).resolves.toBe(undefined);
});
});

describe('some settings unused', () => {
it('should throw an error', function () {
it('should throw an error', async function () {
expect.assertions(1);
const { callCompleteMixin } = setup({
settings: {
unused: true
Expand All @@ -148,12 +149,15 @@ describe('server/config completeMixin()', function () {
used: true
}
});

expect(callCompleteMixin).toThrowError('"unused" setting was not applied');
try {
await callCompleteMixin();
} catch(error) {
expect(error.message).toMatch('"unused" setting was not applied');
}
});

describe('error thrown', () => {
it('has correct code, processExitCode, and message', () => {
it('has correct code, processExitCode, and message', async () => {
expect.assertions(3);

const { callCompleteMixin } = setup({
Expand All @@ -171,7 +175,7 @@ describe('server/config completeMixin()', function () {
});

try {
callCompleteMixin();
await callCompleteMixin();
} catch (error) {
expect(error).toHaveProperty('code', 'InvalidConfig');
expect(error).toHaveProperty('processExitCode', 64);
Expand All @@ -182,7 +186,7 @@ describe('server/config completeMixin()', function () {
});

describe('deprecation support', () => {
it('should transform settings when determining what is unused', function () {
it('should transform settings when determining what is unused', async function () {
sandbox.spy(transformDeprecationsNS, 'transformDeprecations');

const settings = {
Expand All @@ -196,12 +200,12 @@ describe('server/config completeMixin()', function () {
}
});

callCompleteMixin();
await callCompleteMixin();
sinon.assert.calledOnce(transformDeprecations);
sinon.assert.calledWithExactly(transformDeprecations, settings);
});

it('should use transformed settings when considering what is used', function () {
it('should use transformed settings when considering what is used', async function () {
sandbox.stub(transformDeprecationsNS, 'transformDeprecations').callsFake((settings) => {
settings.bar = settings.foo;
delete settings.foo;
Expand All @@ -217,13 +221,35 @@ describe('server/config completeMixin()', function () {
}
});

callCompleteMixin();
await callCompleteMixin();
sinon.assert.calledOnce(transformDeprecations);
});

it('should transform deprecated plugin settings', async () => {
const { callCompleteMixin } = setup({
settings: {
foo1: 'bar'
},
configValues: {
foo2: 'bar'
},
plugins: [
{
spec: {
getDeprecationsProvider() {
return async ({ rename }) => [rename('foo1', 'foo2')];
}
}
}
],
});

await expect(callCompleteMixin()).resolves.toBe(undefined);
});
});

describe('disabled plugins', () => {
it('ignores config for plugins that are disabled', () => {
it('ignores config for plugins that are disabled', async () => {
const { callCompleteMixin } = setup({
settings: {
foo: {
Expand All @@ -241,7 +267,7 @@ describe('server/config completeMixin()', function () {
configValues: {}
});

expect(callCompleteMixin).not.toThrowError();
await expect(callCompleteMixin()).resolves.toBe(undefined);
});
});
});