Skip to content

Commit

Permalink
Use new ES client for licensing plugin (elastic#92143)
Browse files Browse the repository at this point in the history
* use new client for licensing API

* add logs

* adapt unit tests

* Revert "add logs"

This reverts commit 4a61b64

* fix some type errors

* fix test types

* adapt monitoring usage of `createLicensePoller`

* remove test comment

* fix unit test

* remove createLicensePoller from setup contract

* fix unit tests
  • Loading branch information
pgayvallet committed Jun 30, 2021
1 parent f4b29da commit d606e20
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 153 deletions.
5 changes: 0 additions & 5 deletions x-pack/plugins/licensing/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,9 @@ const createSetupMock = (): jest.Mocked<LicensingPluginSetup> => {
const mock = {
license$: new BehaviorSubject(license),
refresh: jest.fn(),
createLicensePoller: jest.fn(),
featureUsage: featureUsageMock.createSetup(),
};
mock.refresh.mockResolvedValue(license);
mock.createLicensePoller.mockReturnValue({
license$: mock.license$,
refresh: mock.refresh,
});

return mock;
};
Expand Down
128 changes: 69 additions & 59 deletions x-pack/plugins/licensing/server/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,42 @@
*/

import { take, toArray } from 'rxjs/operators';
import { estypes } from '@elastic/elasticsearch';
import moment from 'moment';
import { LicenseType } from '../common/types';
import { ElasticsearchError, RawLicense } from './types';
import { ElasticsearchError } from './types';
import { LicensingPlugin } from './plugin';
import {
coreMock,
elasticsearchServiceMock,
loggingSystemMock,
} from '../../../../src/core/server/mocks';
import { ILegacyClusterClient } from '../../../../src/core/server/';
import { IClusterClient } from '../../../../src/core/server';

function buildRawLicense(options: Partial<RawLicense> = {}): RawLicense {
const defaultRawLicense: RawLicense = {
function buildRawLicense(
options: Partial<estypes.XpackInfoMinimalLicenseInformation> = {}
): estypes.XpackInfoMinimalLicenseInformation {
return {
uid: 'uid-000000001234',
status: 'active',
type: 'basic',
mode: 'basic',
expiry_date_in_millis: 1000,
...options,
};
return Object.assign(defaultRawLicense, options);
}

const flushPromises = (ms = 50) => new Promise((res) => setTimeout(res, ms));

function createCoreSetupWith(esClient: ILegacyClusterClient) {
function createCoreSetupWith(esClient: IClusterClient) {
const coreSetup = coreMock.createSetup();
const coreStart = coreMock.createStart();
coreSetup.getStartServices.mockResolvedValue([
{
...coreStart,
elasticsearch: {
...coreStart.elasticsearch,
legacy: {
...coreStart.elasticsearch.legacy,
client: esClient,
createClient: jest.fn(),
},
client: esClient,
},
},
{},
Expand All @@ -52,6 +51,16 @@ function createCoreSetupWith(esClient: ILegacyClusterClient) {
}

describe('licensing plugin', () => {
const createEsClient = (response?: Record<string, any>) => {
const client = elasticsearchServiceMock.createClusterClient();
if (response) {
client.asInternalUser.xpack.info.mockReturnValue(
elasticsearchServiceMock.createSuccessTransportRequestPromise(response as any)
);
}
return client;
};

describe('#start', () => {
describe('#license$', () => {
let plugin: LicensingPlugin;
Expand All @@ -69,8 +78,7 @@ describe('licensing plugin', () => {
});

it('returns license', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
Expand All @@ -83,8 +91,7 @@ describe('licensing plugin', () => {
});

it('calls `callAsInternalUser` with the correct parameters', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
Expand All @@ -94,23 +101,22 @@ describe('licensing plugin', () => {
const { license$ } = await plugin.start();
await license$.pipe(take(1)).toPromise();

expect(esClient.callAsInternalUser).toHaveBeenCalledTimes(1);
expect(esClient.callAsInternalUser).toHaveBeenCalledWith('transport.request', {
method: 'GET',
path: '/_xpack?accept_enterprise=true',
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledWith({
accept_enterprise: true,
});
});

it('observable receives updated licenses', async () => {
const types: LicenseType[] = ['basic', 'gold', 'platinum'];

const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockImplementation(() =>
Promise.resolve({
const esClient = createEsClient();
esClient.asInternalUser.xpack.info.mockImplementation(() => {
return elasticsearchServiceMock.createSuccessTransportRequestPromise({
license: buildRawLicense({ type: types.shift() }),
features: {},
})
);
} as estypes.XpackInfoResponse);
});

const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
Expand All @@ -123,8 +129,8 @@ describe('licensing plugin', () => {
});

it('returns a license with error when request fails', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockRejectedValue(new Error('test'));
const esClient = createEsClient();
esClient.asInternalUser.xpack.info.mockRejectedValue(new Error('test'));

const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
Expand All @@ -136,10 +142,10 @@ describe('licensing plugin', () => {
});

it('generate error message when x-pack plugin was not installed', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
const esClient = createEsClient();
const error: ElasticsearchError = new Error('reason');
error.status = 400;
esClient.callAsInternalUser.mockRejectedValue(error);
esClient.asInternalUser.xpack.info.mockRejectedValue(error);

const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
Expand All @@ -154,26 +160,35 @@ describe('licensing plugin', () => {
const error1 = new Error('reason-1');
const error2 = new Error('reason-2');

const esClient = elasticsearchServiceMock.createLegacyClusterClient();

esClient.callAsInternalUser
.mockRejectedValueOnce(error1)
.mockRejectedValueOnce(error2)
.mockResolvedValue({ license: buildRawLicense(), features: {} });
const esClient = createEsClient();
let i = 0;
esClient.asInternalUser.xpack.info.mockImplementation(() => {
i++;
if (i === 1) {
return elasticsearchServiceMock.createErrorTransportRequestPromise(error1);
}
if (i === 2) {
return elasticsearchServiceMock.createErrorTransportRequestPromise(error2);
}
return elasticsearchServiceMock.createSuccessTransportRequestPromise({
license: buildRawLicense(),
features: {},
} as estypes.XpackInfoResponse);
});

const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
const { license$ } = await plugin.start();

const [first, second, third] = await license$.pipe(take(3), toArray()).toPromise();

expect(first.error).toBe(error1.message);
expect(second.error).toBe(error2.message);
expect(third.type).toBe('basic');
});

it('fetch license immediately without subscriptions', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
Expand All @@ -184,12 +199,11 @@ describe('licensing plugin', () => {

await flushPromises();

expect(esClient.callAsInternalUser).toHaveBeenCalledTimes(1);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1);
});

it('logs license details without subscriptions', async () => {
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
Expand All @@ -214,13 +228,13 @@ describe('licensing plugin', () => {
it('generates signature based on fetched license content', async () => {
const types: LicenseType[] = ['basic', 'gold', 'basic'];

const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockImplementation(() =>
Promise.resolve({
const esClient = createEsClient();
esClient.asInternalUser.xpack.info.mockImplementation(() => {
return elasticsearchServiceMock.createSuccessTransportRequestPromise({
license: buildRawLicense({ type: types.shift() }),
features: {},
})
);
} as estypes.XpackInfoResponse);
});

const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
Expand All @@ -245,8 +259,7 @@ describe('licensing plugin', () => {
api_polling_frequency: moment.duration(50000),
})
);
const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
Expand All @@ -255,14 +268,14 @@ describe('licensing plugin', () => {
await plugin.setup(coreSetup);
const { refresh, license$ } = await plugin.start();

expect(esClient.callAsInternalUser).toHaveBeenCalledTimes(0);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(0);

await license$.pipe(take(1)).toPromise();
expect(esClient.callAsInternalUser).toHaveBeenCalledTimes(1);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1);

refresh();
await flushPromises();
expect(esClient.callAsInternalUser).toHaveBeenCalledTimes(2);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(2);
});
});

Expand All @@ -280,17 +293,15 @@ describe('licensing plugin', () => {
})
);

const esClient = elasticsearchServiceMock.createLegacyClusterClient();
esClient.callAsInternalUser.mockResolvedValue({
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});
const coreSetup = createCoreSetupWith(esClient);
await plugin.setup(coreSetup);
const { createLicensePoller, license$ } = await plugin.start();

const customClient = elasticsearchServiceMock.createLegacyClusterClient();
customClient.callAsInternalUser.mockResolvedValue({
const customClient = createEsClient({
license: buildRawLicense({ type: 'gold' }),
features: {},
});
Expand All @@ -300,10 +311,10 @@ describe('licensing plugin', () => {
customClient,
customPollingFrequency
);
expect(customClient.callAsInternalUser).toHaveBeenCalledTimes(0);
expect(customClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(0);

const customLicense = await customLicense$.pipe(take(1)).toPromise();
expect(customClient.callAsInternalUser).toHaveBeenCalledTimes(1);
expect(customClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1);

await flushPromises(customPollingFrequency * 1.5);

Expand All @@ -324,18 +335,17 @@ describe('licensing plugin', () => {
await plugin.setup(coreSetup);
const { createLicensePoller } = await plugin.start();

const customClient = elasticsearchServiceMock.createLegacyClusterClient();
customClient.callAsInternalUser.mockResolvedValue({
const customClient = createEsClient({
license: buildRawLicense({ type: 'gold' }),
features: {},
});

const { license$, refresh } = createLicensePoller(customClient, 10000);
expect(customClient.callAsInternalUser).toHaveBeenCalledTimes(0);
expect(customClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(0);

await refresh();

expect(customClient.callAsInternalUser).toHaveBeenCalledTimes(1);
expect(customClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1);
const license = await license$.pipe(take(1)).toPromise();
expect(license.type).toBe('gold');
});
Expand Down
Loading

0 comments on commit d606e20

Please sign in to comment.