Skip to content

Commit

Permalink
Fix typo in license_api_guard README name and import http server mock…
Browse files Browse the repository at this point in the history
…s from public interface (#97334) (#97415)

* Reject basic minimum licenses.
  • Loading branch information
cjcenizal authored Apr 19, 2021
1 parent 0bbd498 commit 262e983
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 55 deletions.
4 changes: 2 additions & 2 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,8 @@ the infrastructure monitoring use-case within Kibana.
|Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads.
|{kib-repo}blob/{branch}/x-pack/plugins/license_api_guard[licenseApiGuard]
|WARNING: Missing README.
|{kib-repo}blob/{branch}/x-pack/plugins/license_api_guard/README.md[licenseApiGuard]
|This plugin is used by ES UI plugins to reject API requests when the plugin is unsupported by the user's license.
|{kib-repo}blob/{branch}/x-pack/plugins/license_management/README.md[licenseManagement]
Expand Down
3 changes: 0 additions & 3 deletions x-pack/plugins/license_api_guard/READM.md

This file was deleted.

3 changes: 3 additions & 0 deletions x-pack/plugins/license_api_guard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License API guard plugin

This plugin is used by ES UI plugins to reject API requests when the plugin is unsupported by the user's license.
135 changes: 85 additions & 50 deletions x-pack/plugins/license_api_guard/server/license.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,50 @@
*/

import { of } from 'rxjs';
import type { KibanaRequest, RequestHandlerContext } from 'src/core/server';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { httpServerMock } from 'src/core/server/http/http_server.mocks';

import type { Logger, KibanaRequest, RequestHandlerContext } from 'src/core/server';
import { httpServerMock } from 'src/core/server/mocks';
import { License } from './license';
import { LicenseCheckState, licensingMock } from './shared_imports';
import { LicenseCheckState, licensingMock, LicenseType } from './shared_imports';

describe('License API guard', () => {
const pluginName = 'testPlugin';
const currentLicenseType = 'basic';

const testRoute = ({ licenseState }: { licenseState: string }) => {
const mockLicensingService = ({
licenseType,
licenseState,
}: {
licenseType: LicenseType;
licenseState: LicenseCheckState;
}) => {
const licenseMock = licensingMock.createLicenseMock();
licenseMock.type = licenseType;
licenseMock.check('test', 'gold'); // Flush default mocked state
licenseMock.check.mockReturnValue({ state: licenseState }); // Replace with new mocked state

return {
license$: of(licenseMock),
};
};

const testRoute = ({
licenseType,
licenseState,
}: {
licenseType: LicenseType;
licenseState: LicenseCheckState;
}) => {
const license = new License();

const logger = {
warn: jest.fn(),
};

license.setup({ pluginName, logger });

const licenseMock = licensingMock.createLicenseMock();
licenseMock.type = currentLicenseType;
licenseMock.check('test', 'basic'); // Flush default mocked state
licenseMock.check.mockReturnValue({ state: licenseState as LicenseCheckState }); // Replace with new mocked state

const licensing = {
license$: of(licenseMock),
};
const licensing = mockLicensingService({ licenseType, licenseState });

license.start({
pluginId: 'id',
minimumLicenseType: 'basic',
minimumLicenseType: 'gold',
licensing,
});

Expand All @@ -61,44 +73,67 @@ describe('License API guard', () => {
};
};

describe('valid license', () => {
it('the original route is called and nothing is logged', () => {
const { errorResponse, logMesssage, route } = testRoute({ licenseState: 'valid' });

expect(errorResponse).toBeUndefined();
expect(logMesssage).toBeUndefined();
expect(route).toHaveBeenCalled();
describe('basic minimum license', () => {
it('is rejected', () => {
const license = new License();
license.setup({ pluginName, logger: {} as Logger });
expect(() => {
license.start({
pluginId: pluginName,
minimumLicenseType: 'basic',
licensing: mockLicensingService({ licenseType: 'gold', licenseState: 'valid' }),
});
}).toThrowError(
`Basic licenses don't restrict the use of plugins. Please don't use license_api_guard in the ${pluginName} plugin, or provide a more restrictive minimumLicenseType.`
);
});
});

[
{
licenseState: 'invalid',
expectedMessage: `Your ${currentLicenseType} license does not support ${pluginName}. Please upgrade your license.`,
},
{
licenseState: 'expired',
expectedMessage: `You cannot use ${pluginName} because your ${currentLicenseType} license has expired.`,
},
{
licenseState: 'unavailable',
expectedMessage: `You cannot use ${pluginName} because license information is not available at this time.`,
},
].forEach(({ licenseState, expectedMessage }) => {
describe(`${licenseState} license`, () => {
it('replies with and logs the error message', () => {
const { errorResponse, logMesssage, route } = testRoute({ licenseState });

// We depend on the call to `response.forbidden()` to generate the 403 status code,
// so we can't assert for it here.
expect(errorResponse).toEqual({
body: {
message: expectedMessage,
},
describe('non-basic minimum license', () => {
const licenseType = 'gold';

describe('when valid', () => {
it('the original route is called and nothing is logged', () => {
const { errorResponse, logMesssage, route } = testRoute({
licenseType,
licenseState: 'valid',
});

expect(logMesssage).toBe(expectedMessage);
expect(route).not.toHaveBeenCalled();
expect(errorResponse).toBeUndefined();
expect(logMesssage).toBeUndefined();
expect(route).toHaveBeenCalled();
});
});

[
{
licenseState: 'invalid' as LicenseCheckState,
expectedMessage: `Your ${licenseType} license does not support ${pluginName}. Please upgrade your license.`,
},
{
licenseState: 'expired' as LicenseCheckState,
expectedMessage: `You cannot use ${pluginName} because your ${licenseType} license has expired.`,
},
{
licenseState: 'unavailable' as LicenseCheckState,
expectedMessage: `You cannot use ${pluginName} because license information is not available at this time.`,
},
].forEach(({ licenseState, expectedMessage }) => {
describe(`when ${licenseState}`, () => {
it('replies with and logs the error message', () => {
const { errorResponse, logMesssage, route } = testRoute({ licenseType, licenseState });

// We depend on the call to `response.forbidden()` to generate the 403 status code,
// so we can't assert for it here.
expect(errorResponse).toEqual({
body: {
message: expectedMessage,
},
});

expect(logMesssage).toBe(expectedMessage);
expect(route).not.toHaveBeenCalled();
});
});
});
});
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/license_api_guard/server/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export class License {
}

start({ pluginId, minimumLicenseType, licensing }: StartSettings) {
if (minimumLicenseType === 'basic') {
throw Error(
`Basic licenses don't restrict the use of plugins. Please don't use license_api_guard in the ${pluginId} plugin, or provide a more restrictive minimumLicenseType.`
);
}

licensing.license$.subscribe((license: ILicense) => {
this.licenseType = license.type;
this.licenseCheckState = license.check(pluginId, minimumLicenseType!).state;
Expand Down

0 comments on commit 262e983

Please sign in to comment.