-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* add licensed feature usage API (#63549) * add licensed feature usage API * add FTR test and plugin * jsdoc * fix FTR test suite name * remove clear API * accept Date for notifyUsage * fix mocks
- Loading branch information
1 parent
4dff742
commit 594419f
Showing
19 changed files
with
514 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* 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 { IRouter, StartServicesAccessor } from 'src/core/server'; | ||
import { LicensingPluginStart } from '../types'; | ||
|
||
export function registerFeatureUsageRoute( | ||
router: IRouter, | ||
getStartServices: StartServicesAccessor<{}, LicensingPluginStart> | ||
) { | ||
router.get( | ||
{ path: '/api/licensing/feature_usage', validate: false }, | ||
async (context, request, response) => { | ||
const [, , { featureUsage }] = await getStartServices(); | ||
return response.ok({ | ||
body: [...featureUsage.getLastUsages().entries()].reduce( | ||
(res, [featureName, lastUsage]) => { | ||
return { | ||
...res, | ||
[featureName]: new Date(lastUsage).toISOString(), | ||
}; | ||
}, | ||
{} | ||
), | ||
}); | ||
} | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
x-pack/plugins/licensing/server/services/feature_usage_service.mock.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* 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 { | ||
FeatureUsageService, | ||
FeatureUsageServiceSetup, | ||
FeatureUsageServiceStart, | ||
} from './feature_usage_service'; | ||
|
||
const createSetupMock = (): jest.Mocked<FeatureUsageServiceSetup> => { | ||
const mock = { | ||
register: jest.fn(), | ||
}; | ||
|
||
return mock; | ||
}; | ||
|
||
const createStartMock = (): jest.Mocked<FeatureUsageServiceStart> => { | ||
const mock = { | ||
notifyUsage: jest.fn(), | ||
getLastUsages: jest.fn(), | ||
}; | ||
|
||
return mock; | ||
}; | ||
|
||
const createServiceMock = (): jest.Mocked<PublicMethodsOf<FeatureUsageService>> => { | ||
const mock = { | ||
setup: jest.fn(() => createSetupMock()), | ||
start: jest.fn(() => createStartMock()), | ||
}; | ||
|
||
return mock; | ||
}; | ||
|
||
export const featureUsageMock = { | ||
create: createServiceMock, | ||
createSetup: createSetupMock, | ||
createStart: createStartMock, | ||
}; |
116 changes: 116 additions & 0 deletions
116
x-pack/plugins/licensing/server/services/feature_usage_service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* 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 { FeatureUsageService } from './feature_usage_service'; | ||
|
||
describe('FeatureUsageService', () => { | ||
let service: FeatureUsageService; | ||
|
||
beforeEach(() => { | ||
service = new FeatureUsageService(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
const toObj = (map: ReadonlyMap<string, any>): Record<string, any> => | ||
Object.fromEntries(map.entries()); | ||
|
||
describe('#setup', () => { | ||
describe('#register', () => { | ||
it('throws when registering the same feature twice', () => { | ||
const setup = service.setup(); | ||
setup.register('foo'); | ||
expect(() => { | ||
setup.register('foo'); | ||
}).toThrowErrorMatchingInlineSnapshot(`"Feature 'foo' has already been registered."`); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('#start', () => { | ||
describe('#notifyUsage', () => { | ||
it('allows to notify a feature usage', () => { | ||
const setup = service.setup(); | ||
setup.register('feature'); | ||
const start = service.start(); | ||
start.notifyUsage('feature', 127001); | ||
|
||
expect(start.getLastUsages().get('feature')).toBe(127001); | ||
}); | ||
|
||
it('can receive a Date object', () => { | ||
const setup = service.setup(); | ||
setup.register('feature'); | ||
const start = service.start(); | ||
|
||
const usageTime = new Date(2015, 9, 21, 17, 54, 12); | ||
start.notifyUsage('feature', usageTime); | ||
expect(start.getLastUsages().get('feature')).toBe(usageTime.getTime()); | ||
}); | ||
|
||
it('uses the current time when `usedAt` is unspecified', () => { | ||
jest.spyOn(Date, 'now').mockReturnValue(42); | ||
|
||
const setup = service.setup(); | ||
setup.register('feature'); | ||
const start = service.start(); | ||
start.notifyUsage('feature'); | ||
|
||
expect(start.getLastUsages().get('feature')).toBe(42); | ||
}); | ||
|
||
it('throws when notifying for an unregistered feature', () => { | ||
service.setup(); | ||
const start = service.start(); | ||
expect(() => { | ||
start.notifyUsage('unregistered'); | ||
}).toThrowErrorMatchingInlineSnapshot(`"Feature 'unregistered' is not registered."`); | ||
}); | ||
}); | ||
|
||
describe('#getLastUsages', () => { | ||
it('returns the last usage for all used features', () => { | ||
const setup = service.setup(); | ||
setup.register('featureA'); | ||
setup.register('featureB'); | ||
const start = service.start(); | ||
start.notifyUsage('featureA', 127001); | ||
start.notifyUsage('featureB', 6666); | ||
|
||
expect(toObj(start.getLastUsages())).toEqual({ | ||
featureA: 127001, | ||
featureB: 6666, | ||
}); | ||
}); | ||
|
||
it('returns the last usage even after notifying for an older usage', () => { | ||
const setup = service.setup(); | ||
setup.register('featureA'); | ||
const start = service.start(); | ||
start.notifyUsage('featureA', 1000); | ||
start.notifyUsage('featureA', 500); | ||
|
||
expect(toObj(start.getLastUsages())).toEqual({ | ||
featureA: 1000, | ||
}); | ||
}); | ||
|
||
it('does not return entries for unused registered features', () => { | ||
const setup = service.setup(); | ||
setup.register('featureA'); | ||
setup.register('featureB'); | ||
const start = service.start(); | ||
start.notifyUsage('featureA', 127001); | ||
|
||
expect(toObj(start.getLastUsages())).toEqual({ | ||
featureA: 127001, | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.