NP licensing add functional tests (#53002) (#53569)

* fix comment

* introduce core provider plugin for integration tests

* platform functional tests use core_provider_plugin for testing

* add 3 scenario for licensing plugins: server, client, legacy

* remove unused code

* run all licensing_plugin tests on CI

* remove duplicated config

* address comments

* declare global type for core provider
This commit is contained in:
Mikhail Shustov 2019-12-19 12:25:07 +01:00 committed by GitHub
parent 7e541053f6
commit f464641a1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 579 additions and 235 deletions

View file

@ -57,11 +57,12 @@ export default async function({ readConfigFile }) {
...functionalConfig.get('kbnTestServer'),
serverArgs: [
...functionalConfig.get('kbnTestServer.serverArgs'),
// Required to load new platform plugins via `--plugin-path` flag.
'--env.name=development',
...plugins.map(
pluginDir => `--plugin-path=${path.resolve(__dirname, 'plugins', pluginDir)}`
),
// Required to load new platform plugins via `--plugin-path` flag.
'--env.name=development',
],
},
};

View file

@ -22,9 +22,6 @@ import { CorePluginAPluginSetup } from '../../core_plugin_a/public/plugin';
declare global {
interface Window {
corePluginB?: string;
hasAccessToInjectedMetadata?: boolean;
receivedStartServices?: boolean;
env?: PluginInitializerContext['env'];
}
}
@ -39,12 +36,6 @@ export class CorePluginBPlugin
window.env = pluginContext.env;
}
public setup(core: CoreSetup, deps: CorePluginBDeps) {
window.corePluginB = `Plugin A said: ${deps.core_plugin_a.getGreeting()}`;
window.hasAccessToInjectedMetadata = 'getInjectedVar' in core.injectedMetadata;
core.getStartServices().then(([coreStart, plugins]) => {
window.receivedStartServices = 'overlays' in coreStart;
});
core.application.register({
id: 'bar',
title: 'Bar',
@ -53,6 +44,12 @@ export class CorePluginBPlugin
return renderApp(context, params);
},
});
return {
sayHi() {
return `Plugin A said: ${deps.core_plugin_a.getGreeting()}`;
},
};
}
public start() {}

View file

@ -0,0 +1,36 @@
/*
* 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 { resolve } from 'path';
import { Legacy } from '../../../../kibana';
// eslint-disable-next-line import/no-default-export
export default function CoreProviderPlugin(kibana: any) {
const config: Legacy.PluginSpecOptions = {
id: 'core-provider',
require: [],
publicDir: resolve(__dirname, 'public'),
init: (server: Legacy.Server) => ({}),
uiExports: {
hacks: [resolve(__dirname, 'public/index')],
},
};
return new kibana.Plugin(config);
}

View file

@ -0,0 +1,17 @@
{
"name": "core_provider_plugin",
"version": "1.0.0",
"main": "target/test/plugin_functional/plugins/core_provider_plugin",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Apache-2.0",
"scripts": {
"kbn": "node ../../../../scripts/kbn.js",
"build": "rm -rf './target' && tsc"
},
"devDependencies": {
"typescript": "3.5.3"
}
}

View file

@ -16,6 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
import { UiSettingsPlugin } from './plugin';
import { npSetup, npStart } from 'ui/new_platform';
import '../types';
export const plugin = () => new UiSettingsPlugin();
window.__coreProvider = {
setup: npSetup,
start: npStart,
testUtils: {
delay: (ms: number) => new Promise(res => setTimeout(res, ms)),
},
};

View file

@ -0,0 +1,14 @@
{
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"outDir": "./target",
"skipLibCheck": true
},
"include": [
"index.ts",
"types.ts",
"public/**/*.ts",
"../../../../typings/**/*",
],
"exclude": []
}

View file

@ -16,22 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
import { CoreSetup, Plugin } from 'kibana/public';
import { LegacyCoreSetup, LegacyCoreStart } from 'kibana/public';
declare global {
interface Window {
uiSettingsPlugin?: Record<string, any>;
uiSettingsPluginValue?: string;
__coreProvider: {
setup: {
core: LegacyCoreSetup;
plugins: Record<string, any>;
};
start: {
core: LegacyCoreStart;
plugins: Record<string, any>;
};
testUtils: {
delay: (ms: number) => Promise<void>;
};
};
}
}
export class UiSettingsPlugin implements Plugin {
public setup(core: CoreSetup) {
window.uiSettingsPlugin = core.uiSettings.getAll().ui_settings_plugin;
window.uiSettingsPluginValue = core.uiSettings.get('ui_settings_plugin');
}
public start() {}
public stop() {}
}

View file

@ -4,5 +4,5 @@
"kibanaVersion": "kibana",
"configPath": ["ui_settings_plugin"],
"server": true,
"ui": true
"ui": false
}

View file

@ -5,9 +5,6 @@
"skipLibCheck": true
},
"include": [
"index.ts",
"public/**/*.ts",
"public/**/*.tsx",
"server/**/*.ts",
"../../../../typings/**/*",
],

View file

@ -19,6 +19,7 @@
import expect from '@kbn/expect';
import { PluginFunctionalProviderContext } from '../../services';
import '../../../../test/plugin_functional/plugins/core_provider_plugin/types';
// eslint-disable-next-line import/no-default-export
export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
@ -31,22 +32,35 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider
await PageObjects.common.navigateToApp('settings');
});
it('should attach string to window.corePluginB', async () => {
const corePluginB = await browser.execute('return window.corePluginB');
expect(corePluginB).to.equal(`Plugin A said: Hello from Plugin A!`);
it('should run the new platform plugins', async () => {
expect(
await browser.execute(() => {
return window.__coreProvider.setup.plugins.core_plugin_b.sayHi();
})
).to.be('Plugin A said: Hello from Plugin A!');
});
});
describe('have injectedMetadata service provided', function describeIndexTests() {
describe('should have access to the core services', function describeIndexTests() {
before(async () => {
await PageObjects.common.navigateToApp('bar');
await PageObjects.common.navigateToApp('settings');
});
it('should attach boolean to window.hasAccessToInjectedMetadata', async () => {
const hasAccessToInjectedMetadata = await browser.execute(
'return window.hasAccessToInjectedMetadata'
);
expect(hasAccessToInjectedMetadata).to.equal(true);
it('to injectedMetadata service', async () => {
expect(
await browser.execute(() => {
return window.__coreProvider.setup.core.injectedMetadata.getKibanaBuildNumber();
})
).to.be.a('number');
});
it('to start services via coreSetup.getStartServices', async () => {
expect(
await browser.executeAsync(async cb => {
const [coreStart] = await window.__coreProvider.setup.core.getStartServices();
cb(Boolean(coreStart.overlays));
})
).to.be(true);
});
});
@ -61,16 +75,5 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider
expect(envData.packageInfo.version).to.be.a('string');
});
});
describe('have access to start services via coreSetup.getStartServices', function describeIndexTests() {
before(async () => {
await PageObjects.common.navigateToApp('bar');
});
it('should attach boolean to window.receivedStartServices', async () => {
const receivedStartServices = await browser.execute('return window.receivedStartServices');
expect(receivedStartServices).to.equal(true);
});
});
});
}

View file

@ -18,6 +18,7 @@
*/
import expect from '@kbn/expect';
import { PluginFunctionalProviderContext } from '../../services';
import '../../plugins/core_provider_plugin/types';
// eslint-disable-next-line import/no-default-export
export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
@ -31,15 +32,30 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider
});
it('client plugins have access to registered settings', async () => {
const settings = await browser.execute('return window.uiSettingsPlugin');
const settings = await browser.execute(() => {
return window.__coreProvider.setup.core.uiSettings.getAll().ui_settings_plugin;
});
expect(settings).to.eql({
category: ['any'],
description: 'just for testing',
name: 'from_ui_settings_plugin',
value: '2',
});
const settingsValue = await browser.execute('return window.uiSettingsPluginValue');
const settingsValue = await browser.execute(() => {
return window.__coreProvider.setup.core.uiSettings.get('ui_settings_plugin');
});
expect(settingsValue).to.be('2');
const settingsValueViaObservables = await browser.executeAsync(async (callback: Function) => {
window.__coreProvider.setup.core.uiSettings
.get$('ui_settings_plugin')
.subscribe(v => callback(v));
});
expect(settingsValueViaObservables).to.be('2');
});
it('server plugins have access to registered settings', async () => {

View file

@ -35,4 +35,6 @@ require('@kbn/test').runTestsCli([
require.resolve('../test/ui_capabilities/spaces_only/config'),
require.resolve('../test/upgrade_assistant_integration/config'),
require.resolve('../test/licensing_plugin/config'),
require.resolve('../test/licensing_plugin/config.public'),
require.resolve('../test/licensing_plugin/config.legacy'),
]);

View file

@ -1,177 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
import { PublicLicenseJSON } from '../../../plugins/licensing/server';
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
export default function({ getService, getPageObjects }: FtrProviderContext) {
const supertest = getService('supertest');
const esSupertestWithoutAuth = getService('esSupertestWithoutAuth');
const security = getService('security');
const PageObjects = getPageObjects(['common', 'security']);
const testSubjects = getService('testSubjects');
const scenario = {
async setup() {
await security.role.create('license_manager-role', {
elasticsearch: {
cluster: ['all'],
},
kibana: [
{
base: ['all'],
spaces: ['*'],
},
],
});
await security.user.create('license_manager_user', {
password: 'license_manager_user-password',
roles: ['license_manager-role'],
full_name: 'license_manager user',
});
// ensure we're logged out so we can login as the appropriate users
await PageObjects.security.forceLogout();
await PageObjects.security.login('license_manager_user', 'license_manager_user-password');
},
async teardown() {
await security.role.delete('license_manager-role');
},
async startBasic() {
const response = await esSupertestWithoutAuth
.post('/_license/start_basic?acknowledge=true')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.basic_was_started).to.be(true);
},
async startTrial() {
const response = await esSupertestWithoutAuth
.post('/_license/start_trial?acknowledge=true')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.trial_was_started).to.be(true);
},
async deleteLicense() {
const response = await esSupertestWithoutAuth
.delete('/_license')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.acknowledged).to.be(true);
},
async getLicense(): Promise<PublicLicenseJSON> {
// > --xpack.licensing.api_polling_frequency set in test config
// to wait for Kibana server to re-fetch the license from Elasticsearch
await delay(1000);
const { body } = await supertest.get('/api/licensing/info').expect(200);
return body;
},
};
describe('changes in license types', () => {
after(async () => {
await scenario.startBasic();
});
it('provides changes in license types', async () => {
await scenario.setup();
const initialLicense = await scenario.getLicense();
expect(initialLicense.license?.type).to.be('basic');
// security enabled explicitly in test config
expect(initialLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
const {
body: legacyInitialLicense,
headers: legacyInitialLicenseHeaders,
} = await supertest.get('/api/xpack/v1/info').expect(200);
expect(legacyInitialLicense.license?.type).to.be('basic');
expect(legacyInitialLicense.features).to.have.property('security');
expect(legacyInitialLicenseHeaders['kbn-xpack-sig']).to.be.a('string');
// license hasn't changed
const refetchedLicense = await scenario.getLicense();
expect(refetchedLicense.license?.type).to.be('basic');
expect(refetchedLicense.signature).to.be(initialLicense.signature);
const {
body: legacyRefetchedLicense,
headers: legacyRefetchedLicenseHeaders,
} = await supertest.get('/api/xpack/v1/info').expect(200);
expect(legacyRefetchedLicense.license?.type).to.be('basic');
expect(legacyRefetchedLicenseHeaders['kbn-xpack-sig']).to.be(
legacyInitialLicenseHeaders['kbn-xpack-sig']
);
// server allows to request trial only once.
// other attempts will throw 403
await scenario.startTrial();
const trialLicense = await scenario.getLicense();
expect(trialLicense.license?.type).to.be('trial');
expect(trialLicense.signature).to.not.be(initialLicense.signature);
expect(trialLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
const { body: legacyTrialLicense, headers: legacyTrialLicenseHeaders } = await supertest
.get('/api/xpack/v1/info')
.expect(200);
expect(legacyTrialLicense.license?.type).to.be('trial');
expect(legacyTrialLicense.features).to.have.property('security');
expect(legacyTrialLicenseHeaders['kbn-xpack-sig']).to.not.be(
legacyInitialLicenseHeaders['kbn-xpack-sig']
);
await scenario.startBasic();
const basicLicense = await scenario.getLicense();
expect(basicLicense.license?.type).to.be('basic');
expect(basicLicense.signature).not.to.be(initialLicense.signature);
expect(basicLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
const { body: legacyBasicLicense, headers: legacyBasicLicenseHeaders } = await supertest
.get('/api/xpack/v1/info')
.expect(200);
expect(legacyBasicLicense.license?.type).to.be('basic');
expect(legacyBasicLicense.features).to.have.property('security');
expect(legacyBasicLicenseHeaders['kbn-xpack-sig']).to.not.be(
legacyInitialLicenseHeaders['kbn-xpack-sig']
);
await scenario.deleteLicense();
const inactiveLicense = await scenario.getLicense();
expect(inactiveLicense.signature).to.not.be(initialLicense.signature);
expect(inactiveLicense).to.not.have.property('license');
expect(inactiveLicense.features?.security).to.eql({
isAvailable: false,
isEnabled: true,
});
// banner shown only when license expired not just deleted
await testSubjects.missingOrFail('licenseExpiredBanner');
});
});
}

View file

@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
export default async function({ readConfigFile }: FtrConfigProviderContext) {
const commonConfig = await readConfigFile(require.resolve('./config'));
return {
...commonConfig.getAll(),
testFiles: [require.resolve('./legacy')],
};
}

View file

@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import path from 'path';
import { KIBANA_ROOT } from '@kbn/test';
import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
export default async function({ readConfigFile }: FtrConfigProviderContext) {
const commonConfig = await readConfigFile(require.resolve('./config'));
return {
...commonConfig.getAll(),
testFiles: [require.resolve('./public')],
kbnTestServer: {
serverArgs: [
...commonConfig.get('kbnTestServer.serverArgs'),
// Required to load new platform plugin provider via `--plugin-path` flag.
'--env.name=development',
`--plugin-path=${path.resolve(
KIBANA_ROOT,
'test/plugin_functional/plugins/core_provider_plugin'
)}`,
],
},
};
}

View file

@ -22,7 +22,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) {
};
return {
testFiles: [require.resolve('./apis')],
testFiles: [require.resolve('./server')],
servers,
services,
pageObjects,
@ -43,7 +43,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) {
...functionalTestsConfig.get('kbnTestServer'),
serverArgs: [
...functionalTestsConfig.get('kbnTestServer.serverArgs'),
'--xpack.licensing.api_polling_frequency=300',
'--xpack.licensing.api_polling_frequency=100',
],
},

View file

@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { FtrProviderContext } from '../services';
// eslint-disable-next-line import/no-default-export
export default function({ loadTestFile }: FtrProviderContext) {
describe('Legacy licensing plugin', function() {
this.tags('ciGroup2');
// MUST BE LAST! CHANGES LICENSE TYPE!
loadTestFile(require.resolve('./updates'));
});
}

View file

@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
import { createScenario } from '../scenario';
import '../../../../test/plugin_functional/plugins/core_provider_plugin/types';
// eslint-disable-next-line import/no-default-export
export default function(ftrContext: FtrProviderContext) {
const { getService } = ftrContext;
const supertest = getService('supertest');
const testSubjects = getService('testSubjects');
const scenario = createScenario(ftrContext);
describe('changes in license types', () => {
after(async () => {
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
await scenario.teardown();
});
it('provides changes in license types', async () => {
await scenario.setup();
await scenario.waitForPluginToDetectLicenseUpdate();
const {
body: legacyInitialLicense,
headers: legacyInitialLicenseHeaders,
} = await supertest.get('/api/xpack/v1/info').expect(200);
expect(legacyInitialLicense.license?.type).to.be('basic');
expect(legacyInitialLicense.features).to.have.property('security');
expect(legacyInitialLicenseHeaders['kbn-xpack-sig']).to.be.a('string');
await scenario.startTrial();
await scenario.waitForPluginToDetectLicenseUpdate();
const { body: legacyTrialLicense, headers: legacyTrialLicenseHeaders } = await supertest
.get('/api/xpack/v1/info')
.expect(200);
expect(legacyTrialLicense.license?.type).to.be('trial');
expect(legacyTrialLicense.features).to.have.property('security');
expect(legacyTrialLicenseHeaders['kbn-xpack-sig']).to.not.be(
legacyInitialLicenseHeaders['kbn-xpack-sig']
);
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
const { body: legacyBasicLicense, headers: legacyBasicLicenseHeaders } = await supertest
.get('/api/xpack/v1/info')
.expect(200);
expect(legacyBasicLicense.license?.type).to.be('basic');
expect(legacyBasicLicense.features).to.have.property('security');
expect(legacyBasicLicenseHeaders['kbn-xpack-sig']).to.not.be(
legacyInitialLicenseHeaders['kbn-xpack-sig']
);
await scenario.deleteLicense();
await scenario.waitForPluginToDetectLicenseUpdate();
// banner shown only when license expired not just deleted
await testSubjects.missingOrFail('licenseExpiredBanner');
});
});
}

View file

@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { FtrProviderContext } from '../services';
// eslint-disable-next-line import/no-default-export
export default function({ loadTestFile }: FtrProviderContext) {
describe('Licensing plugin public client', function() {
this.tags('ciGroup2');
// MUST BE LAST! CHANGES LICENSE TYPE!
loadTestFile(require.resolve('./updates'));
});
}

View file

@ -0,0 +1,112 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
import { LicensingPluginSetup } from '../../../plugins/licensing/public';
import { createScenario } from '../scenario';
import '../../../../test/plugin_functional/plugins/core_provider_plugin/types';
// eslint-disable-next-line import/no-default-export
export default function(ftrContext: FtrProviderContext) {
const { getService } = ftrContext;
const testSubjects = getService('testSubjects');
const browser = getService('browser');
const scenario = createScenario(ftrContext);
describe('changes in license types', () => {
after(async () => {
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
await scenario.teardown();
});
it('provides changes in license types', async () => {
await scenario.setup();
await scenario.waitForPluginToDetectLicenseUpdate();
expect(
await browser.executeAsync(async (cb: Function) => {
const { setup, testUtils } = window.__coreProvider;
// this call enforces signature check to detect license update
// and causes license re-fetch
await setup.core.http.get('/');
await testUtils.delay(100);
const licensing: LicensingPluginSetup = setup.plugins.licensing;
licensing.license$.subscribe(license => cb(license.type));
})
).to.be('basic');
// license hasn't changed
await scenario.waitForPluginToDetectLicenseUpdate();
expect(
await browser.executeAsync(async (cb: Function) => {
const { setup, testUtils } = window.__coreProvider;
// this call enforces signature check to detect license update
// and causes license re-fetch
await setup.core.http.get('/');
await testUtils.delay(100);
const licensing: LicensingPluginSetup = setup.plugins.licensing;
licensing.license$.subscribe(license => cb(license.type));
})
).to.be('basic');
await scenario.startTrial();
await scenario.waitForPluginToDetectLicenseUpdate();
expect(
await browser.executeAsync(async (cb: Function) => {
const { setup, testUtils } = window.__coreProvider;
// this call enforces signature check to detect license update
// and causes license re-fetch
await setup.core.http.get('/');
await testUtils.delay(100);
const licensing: LicensingPluginSetup = setup.plugins.licensing;
licensing.license$.subscribe(license => cb(license.type));
})
).to.be('trial');
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
expect(
await browser.executeAsync(async (cb: Function) => {
const { setup, testUtils } = window.__coreProvider;
// this call enforces signature check to detect license update
// and causes license re-fetch
await setup.core.http.get('/');
await testUtils.delay(100);
const licensing: LicensingPluginSetup = setup.plugins.licensing;
licensing.license$.subscribe(license => cb(license.type));
})
).to.be('basic');
await scenario.deleteLicense();
await scenario.waitForPluginToDetectLicenseUpdate();
expect(
await browser.executeAsync(async (cb: Function) => {
const { setup, testUtils } = window.__coreProvider;
// this call enforces signature check to detect license update
// and causes license re-fetch
await setup.core.http.get('/');
await testUtils.delay(100);
const licensing: LicensingPluginSetup = setup.plugins.licensing;
licensing.license$.subscribe(license => cb(license.type));
})
).to.be(null);
// banner shown only when license expired not just deleted
await testSubjects.missingOrFail('licenseExpiredBanner');
});
});
}

View file

@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from './services';
import { PublicLicenseJSON } from '../../plugins/licensing/server';
import '../../../test/plugin_functional/plugins/core_provider_plugin/types';
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
export function createScenario({ getService, getPageObjects }: FtrProviderContext) {
const supertest = getService('supertest');
const esSupertestWithoutAuth = getService('esSupertestWithoutAuth');
const security = getService('security');
const PageObjects = getPageObjects(['common', 'security']);
const scenario = {
async setup() {
await security.role.create('license_manager-role', {
elasticsearch: {
cluster: ['all'],
},
kibana: [
{
base: ['all'],
spaces: ['*'],
},
],
});
await security.user.create('license_manager_user', {
password: 'license_manager_user-password',
roles: ['license_manager-role'],
full_name: 'license_manager user',
});
// ensure we're logged out so we can login as the appropriate users
await PageObjects.security.logout();
await PageObjects.security.login('license_manager_user', 'license_manager_user-password');
},
// make sure a license is present, otherwise the security is not available anymore.
async teardown() {
await security.role.delete('license_manager-role');
await security.user.delete('license_manager_user');
},
// elasticsearch allows to downgrade a license only once. other attempts will throw 403.
async startBasic() {
const response = await esSupertestWithoutAuth
.post('/_license/start_basic?acknowledge=true')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.basic_was_started).to.be(true);
},
// elasticsearch allows to request trial only once. other attempts will throw 403.
async startTrial() {
const response = await esSupertestWithoutAuth
.post('/_license/start_trial?acknowledge=true')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.trial_was_started).to.be(true);
},
async deleteLicense() {
const response = await esSupertestWithoutAuth
.delete('/_license')
.auth('license_manager_user', 'license_manager_user-password')
.expect(200);
expect(response.body.acknowledged).to.be(true);
},
async getLicense(): Promise<PublicLicenseJSON> {
const { body } = await supertest.get('/api/licensing/info').expect(200);
return body;
},
async waitForPluginToDetectLicenseUpdate() {
// > --xpack.licensing.api_polling_frequency set in test config
// to wait for Kibana server to re-fetch the license from Elasticsearch
await delay(500);
},
};
return scenario;
}

View file

@ -7,6 +7,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
// eslint-disable-next-line import/no-default-export
export default function({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

View file

@ -6,13 +6,14 @@
import { FtrProviderContext } from '../services';
// eslint-disable-next-line import/no-default-export
export default function({ loadTestFile }: FtrProviderContext) {
describe('Licensing plugin', function() {
describe('Licensing plugin server client', function() {
this.tags('ciGroup2');
loadTestFile(require.resolve('./info'));
loadTestFile(require.resolve('./header'));
// MUST BE LAST! CHANGES LICENSE TYPE!
loadTestFile(require.resolve('./changes'));
loadTestFile(require.resolve('./updates'));
});
}

View file

@ -7,6 +7,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
// eslint-disable-next-line import/no-default-export
export default function({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

View file

@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../services';
import { createScenario } from '../scenario';
import '../../../../test/plugin_functional/plugins/core_provider_plugin/types';
// eslint-disable-next-line import/no-default-export
export default function(ftrContext: FtrProviderContext) {
const { getService } = ftrContext;
const testSubjects = getService('testSubjects');
const scenario = createScenario(ftrContext);
describe('changes in license types', () => {
after(async () => {
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
await scenario.teardown();
});
it('provides changes in license types', async () => {
await scenario.setup();
await scenario.waitForPluginToDetectLicenseUpdate();
const initialLicense = await scenario.getLicense();
expect(initialLicense.license?.type).to.be('basic');
// security enabled explicitly in test config
expect(initialLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
// license hasn't changed
await scenario.waitForPluginToDetectLicenseUpdate();
const refetchedLicense = await scenario.getLicense();
expect(refetchedLicense.license?.type).to.be('basic');
expect(refetchedLicense.signature).to.be(initialLicense.signature);
await scenario.startTrial();
await scenario.waitForPluginToDetectLicenseUpdate();
const trialLicense = await scenario.getLicense();
expect(trialLicense.license?.type).to.be('trial');
expect(trialLicense.signature).to.not.be(initialLicense.signature);
expect(trialLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
await scenario.startBasic();
await scenario.waitForPluginToDetectLicenseUpdate();
const basicLicense = await scenario.getLicense();
expect(basicLicense.license?.type).to.be('basic');
expect(basicLicense.signature).not.to.be(initialLicense.signature);
expect(basicLicense.features?.security).to.eql({
isAvailable: true,
isEnabled: true,
});
await scenario.deleteLicense();
await scenario.waitForPluginToDetectLicenseUpdate();
const inactiveLicense = await scenario.getLicense();
expect(inactiveLicense.signature).to.not.be(initialLicense.signature);
expect(inactiveLicense).to.not.have.property('license');
expect(inactiveLicense.features?.security).to.eql({
isAvailable: false,
isEnabled: true,
});
// banner shown only when license expired not just deleted
await testSubjects.missingOrFail('licenseExpiredBanner');
});
});
}