[Usage Collection] Improves Collector fetch
API (#79595)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
b5c5bf706d
commit
70a9164790
|
@ -19,6 +19,8 @@
|
|||
|
||||
import { fetchProvider } from './fetch';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
jest.mock('../../../common', () => ({
|
||||
DEFAULT_QUERY_LANGUAGE: 'lucene',
|
||||
|
@ -29,6 +31,8 @@ jest.mock('../../../common', () => ({
|
|||
|
||||
let fetch: ReturnType<typeof fetchProvider>;
|
||||
let callCluster: LegacyAPICaller;
|
||||
let collectorFetchContext: CollectorFetchContext;
|
||||
const collectorFetchContextMock = createCollectorFetchContextMock();
|
||||
|
||||
function setupMockCallCluster(
|
||||
optCount: { optInCount?: number; optOutCount?: number } | null,
|
||||
|
@ -89,40 +93,64 @@ describe('makeKQLUsageCollector', () => {
|
|||
|
||||
it('should return opt in data from the .kibana/kql-telemetry doc', async () => {
|
||||
setupMockCallCluster({ optInCount: 1 }, 'kuery');
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.optInCount).toBe(1);
|
||||
expect(fetchResponse.optOutCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should return the default query language set in advanced settings', async () => {
|
||||
setupMockCallCluster({ optInCount: 1 }, 'kuery');
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.defaultQueryLanguage).toBe('kuery');
|
||||
});
|
||||
|
||||
// Indicates the user has modified the setting at some point but the value is currently the default
|
||||
it('should return the kibana default query language if the config value is null', async () => {
|
||||
setupMockCallCluster({ optInCount: 1 }, null);
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.defaultQueryLanguage).toBe('lucene');
|
||||
});
|
||||
|
||||
it('should indicate when the default language has never been modified by the user', async () => {
|
||||
setupMockCallCluster({ optInCount: 1 }, undefined);
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.defaultQueryLanguage).toBe('default-lucene');
|
||||
});
|
||||
|
||||
it('should default to 0 opt in counts if the .kibana/kql-telemetry doc does not exist', async () => {
|
||||
setupMockCallCluster(null, 'kuery');
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.optInCount).toBe(0);
|
||||
expect(fetchResponse.optOutCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should default to the kibana default language if the config document does not exist', async () => {
|
||||
setupMockCallCluster(null, 'missingConfigDoc');
|
||||
const fetchResponse = await fetch(callCluster);
|
||||
collectorFetchContext = {
|
||||
...collectorFetchContextMock,
|
||||
callCluster,
|
||||
};
|
||||
const fetchResponse = await fetch(collectorFetchContext);
|
||||
expect(fetchResponse.defaultQueryLanguage).toBe('default-lucene');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { DEFAULT_QUERY_LANGUAGE, UI_SETTINGS } from '../../../common';
|
||||
|
||||
const defaultSearchQueryLanguageSetting = DEFAULT_QUERY_LANGUAGE;
|
||||
|
@ -30,7 +30,7 @@ export interface Usage {
|
|||
}
|
||||
|
||||
export function fetchProvider(index: string) {
|
||||
return async (callCluster: LegacyAPICaller): Promise<Usage> => {
|
||||
return async ({ callCluster }: CollectorFetchContext): Promise<Usage> => {
|
||||
const [response, config] = await Promise.all([
|
||||
callCluster('get', {
|
||||
index,
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
import { Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { LegacyAPICaller, SharedGlobalConfig } from 'kibana/server';
|
||||
import { SharedGlobalConfig } from 'kibana/server';
|
||||
import { CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { Usage } from './register';
|
||||
|
||||
interface SearchTelemetrySavedObject {
|
||||
|
@ -27,7 +28,7 @@ interface SearchTelemetrySavedObject {
|
|||
}
|
||||
|
||||
export function fetchProvider(config$: Observable<SharedGlobalConfig>) {
|
||||
return async (callCluster: LegacyAPICaller): Promise<Usage> => {
|
||||
return async ({ callCluster }: CollectorFetchContext): Promise<Usage> => {
|
||||
const config = await config$.pipe(first()).toPromise();
|
||||
|
||||
const response = await callCluster<SearchTelemetrySavedObject>('search', {
|
||||
|
|
|
@ -17,39 +17,39 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import sinon from 'sinon';
|
||||
import { CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import { fetchProvider } from './collector_fetch';
|
||||
|
||||
describe('Sample Data Fetch', () => {
|
||||
let callClusterMock: sinon.SinonStub;
|
||||
const getMockFetchClients = (hits?: unknown[]) => {
|
||||
const fetchParamsMock = createCollectorFetchContextMock();
|
||||
fetchParamsMock.callCluster.mockResolvedValue({ hits: { hits } });
|
||||
return fetchParamsMock;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
callClusterMock = sinon.stub();
|
||||
});
|
||||
describe('Sample Data Fetch', () => {
|
||||
let collectorFetchContext: CollectorFetchContext;
|
||||
|
||||
test('uninitialized .kibana', async () => {
|
||||
const fetch = fetchProvider('index');
|
||||
const telemetry = await fetch(callClusterMock);
|
||||
collectorFetchContext = getMockFetchClients();
|
||||
const telemetry = await fetch(collectorFetchContext);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`undefined`);
|
||||
});
|
||||
|
||||
test('installed data set', async () => {
|
||||
const fetch = fetchProvider('index');
|
||||
callClusterMock.returns({
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
],
|
||||
collectorFetchContext = getMockFetchClients([
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
});
|
||||
const telemetry = await fetch(callClusterMock);
|
||||
]);
|
||||
const telemetry = await fetch(collectorFetchContext);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -67,27 +67,23 @@ Object {
|
|||
|
||||
test('multiple installed data sets', async () => {
|
||||
const fetch = fetchProvider('index');
|
||||
callClusterMock.returns({
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'sample-data-telemetry:test2',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:13:17Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
],
|
||||
collectorFetchContext = getMockFetchClients([
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
});
|
||||
const telemetry = await fetch(callClusterMock);
|
||||
{
|
||||
_id: 'sample-data-telemetry:test2',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:13:17Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
]);
|
||||
const telemetry = await fetch(collectorFetchContext);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -106,17 +102,13 @@ Object {
|
|||
|
||||
test('installed data set, missing counts', async () => {
|
||||
const fetch = fetchProvider('index');
|
||||
callClusterMock.returns({
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: { updated_at: '2019-03-13T22:02:09Z', 'sample-data-telemetry': {} },
|
||||
},
|
||||
],
|
||||
collectorFetchContext = getMockFetchClients([
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: { updated_at: '2019-03-13T22:02:09Z', 'sample-data-telemetry': {} },
|
||||
},
|
||||
});
|
||||
const telemetry = await fetch(callClusterMock);
|
||||
]);
|
||||
const telemetry = await fetch(collectorFetchContext);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -132,34 +124,30 @@ Object {
|
|||
|
||||
test('installed and uninstalled data sets', async () => {
|
||||
const fetch = fetchProvider('index');
|
||||
callClusterMock.returns({
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'sample-data-telemetry:test0',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:29:32Z',
|
||||
'sample-data-telemetry': { installCount: 4, unInstallCount: 4 },
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'sample-data-telemetry:test2',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:13:17Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
],
|
||||
collectorFetchContext = getMockFetchClients([
|
||||
{
|
||||
_id: 'sample-data-telemetry:test0',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:29:32Z',
|
||||
'sample-data-telemetry': { installCount: 4, unInstallCount: 4 },
|
||||
},
|
||||
},
|
||||
});
|
||||
const telemetry = await fetch(callClusterMock);
|
||||
{
|
||||
_id: 'sample-data-telemetry:test1',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:02:09Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'sample-data-telemetry:test2',
|
||||
_source: {
|
||||
updated_at: '2019-03-13T22:13:17Z',
|
||||
'sample-data-telemetry': { installCount: 1 },
|
||||
},
|
||||
},
|
||||
]);
|
||||
const telemetry = await fetch(collectorFetchContext);
|
||||
|
||||
expect(telemetry).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import { get } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { CollectorFetchContext } from '../../../../../usage_collection/server';
|
||||
|
||||
interface SearchHit {
|
||||
_id: string;
|
||||
|
@ -41,7 +42,7 @@ export interface TelemetryResponse {
|
|||
}
|
||||
|
||||
export function fetchProvider(index: string) {
|
||||
return async (callCluster: any) => {
|
||||
return async ({ callCluster }: CollectorFetchContext) => {
|
||||
const response = await callCluster('search', {
|
||||
index,
|
||||
body: {
|
||||
|
|
|
@ -17,16 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
savedObjectsRepositoryMock,
|
||||
loggingSystemMock,
|
||||
elasticsearchServiceMock,
|
||||
} from '../../../../../core/server/mocks';
|
||||
import { savedObjectsRepositoryMock, loggingSystemMock } from '../../../../../core/server/mocks';
|
||||
import {
|
||||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import {
|
||||
ROLL_INDICES_START,
|
||||
ROLL_TOTAL_INDICES_INTERVAL,
|
||||
|
@ -53,8 +50,7 @@ describe('telemetry_application_usage', () => {
|
|||
|
||||
const getUsageCollector = jest.fn();
|
||||
const registerType = jest.fn();
|
||||
const callCluster = jest.fn();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const mockedFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
beforeAll(() =>
|
||||
registerApplicationUsageCollector(logger, usageCollectionMock, registerType, getUsageCollector)
|
||||
|
@ -67,7 +63,7 @@ describe('telemetry_application_usage', () => {
|
|||
|
||||
test('if no savedObjectClient initialised, return undefined', async () => {
|
||||
expect(collector.isReady()).toBe(false);
|
||||
expect(await collector.fetch(callCluster, esClient)).toBeUndefined();
|
||||
expect(await collector.fetch(mockedFetchContext)).toBeUndefined();
|
||||
jest.runTimersToTime(ROLL_INDICES_START);
|
||||
});
|
||||
|
||||
|
@ -85,7 +81,7 @@ describe('telemetry_application_usage', () => {
|
|||
jest.runTimersToTime(ROLL_TOTAL_INDICES_INTERVAL); // Force rollTotals to run
|
||||
|
||||
expect(collector.isReady()).toBe(true);
|
||||
expect(await collector.fetch(callCluster, esClient)).toStrictEqual({});
|
||||
expect(await collector.fetch(mockedFetchContext)).toStrictEqual({});
|
||||
expect(savedObjectClient.bulkCreate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -142,7 +138,7 @@ describe('telemetry_application_usage', () => {
|
|||
|
||||
jest.runTimersToTime(ROLL_TOTAL_INDICES_INTERVAL); // Force rollTotals to run
|
||||
|
||||
expect(await collector.fetch(callCluster, esClient)).toStrictEqual({
|
||||
expect(await collector.fetch(mockedFetchContext)).toStrictEqual({
|
||||
appId: {
|
||||
clicks_total: total + 1 + 10,
|
||||
clicks_7_days: total + 1,
|
||||
|
@ -202,7 +198,7 @@ describe('telemetry_application_usage', () => {
|
|||
|
||||
getUsageCollector.mockImplementation(() => savedObjectClient);
|
||||
|
||||
expect(await collector.fetch(callCluster, esClient)).toStrictEqual({
|
||||
expect(await collector.fetch(mockedFetchContext)).toStrictEqual({
|
||||
appId: {
|
||||
clicks_total: 1,
|
||||
clicks_7_days: 0,
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import { registerCoreUsageCollector } from '.';
|
||||
import { coreUsageDataServiceMock } from '../../../../../core/server/mocks';
|
||||
import { CoreUsageData } from 'src/core/server/';
|
||||
|
@ -35,7 +35,7 @@ describe('telemetry_core', () => {
|
|||
return createUsageCollectionSetupMock().makeUsageCollector(config);
|
||||
});
|
||||
|
||||
const callCluster = jest.fn().mockImplementation(() => ({}));
|
||||
const collectorFetchContext = createCollectorFetchContextMock();
|
||||
const coreUsageDataStart = coreUsageDataServiceMock.createStartContract();
|
||||
const getCoreUsageDataReturnValue = (Symbol('core telemetry') as any) as CoreUsageData;
|
||||
coreUsageDataStart.getCoreUsageData.mockResolvedValue(getCoreUsageDataReturnValue);
|
||||
|
@ -48,6 +48,6 @@ describe('telemetry_core', () => {
|
|||
});
|
||||
|
||||
test('fetch', async () => {
|
||||
expect(await collector.fetch(callCluster)).toEqual(getCoreUsageDataReturnValue);
|
||||
expect(await collector.fetch(collectorFetchContext)).toEqual(getCoreUsageDataReturnValue);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
import { CspConfig, ICspConfig } from '../../../../../core/server';
|
||||
import { createCspCollector } from './csp_collector';
|
||||
import { httpServiceMock } from '../../../../../core/server/mocks';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
describe('csp collector', () => {
|
||||
let httpMock: ReturnType<typeof httpServiceMock.createSetupContract>;
|
||||
const mockCallCluster = null as any;
|
||||
// changed for consistency with expected implementation
|
||||
const mockedFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
function updateCsp(config: Partial<ICspConfig>) {
|
||||
httpMock.csp = new CspConfig(config);
|
||||
|
@ -36,28 +38,28 @@ describe('csp collector', () => {
|
|||
test('fetches whether strict mode is enabled', async () => {
|
||||
const collector = createCspCollector(httpMock);
|
||||
|
||||
expect((await collector.fetch(mockCallCluster)).strict).toEqual(true);
|
||||
expect((await collector.fetch(mockedFetchContext)).strict).toEqual(true);
|
||||
|
||||
updateCsp({ strict: false });
|
||||
expect((await collector.fetch(mockCallCluster)).strict).toEqual(false);
|
||||
expect((await collector.fetch(mockedFetchContext)).strict).toEqual(false);
|
||||
});
|
||||
|
||||
test('fetches whether the legacy browser warning is enabled', async () => {
|
||||
const collector = createCspCollector(httpMock);
|
||||
|
||||
expect((await collector.fetch(mockCallCluster)).warnLegacyBrowsers).toEqual(true);
|
||||
expect((await collector.fetch(mockedFetchContext)).warnLegacyBrowsers).toEqual(true);
|
||||
|
||||
updateCsp({ warnLegacyBrowsers: false });
|
||||
expect((await collector.fetch(mockCallCluster)).warnLegacyBrowsers).toEqual(false);
|
||||
expect((await collector.fetch(mockedFetchContext)).warnLegacyBrowsers).toEqual(false);
|
||||
});
|
||||
|
||||
test('fetches whether the csp rules have been changed or not', async () => {
|
||||
const collector = createCspCollector(httpMock);
|
||||
|
||||
expect((await collector.fetch(mockCallCluster)).rulesChangedFromDefault).toEqual(false);
|
||||
expect((await collector.fetch(mockedFetchContext)).rulesChangedFromDefault).toEqual(false);
|
||||
|
||||
updateCsp({ rules: ['not', 'default'] });
|
||||
expect((await collector.fetch(mockCallCluster)).rulesChangedFromDefault).toEqual(true);
|
||||
expect((await collector.fetch(mockedFetchContext)).rulesChangedFromDefault).toEqual(true);
|
||||
});
|
||||
|
||||
test('does not include raw csp rules under any property names', async () => {
|
||||
|
@ -69,7 +71,7 @@ describe('csp collector', () => {
|
|||
//
|
||||
// We use a snapshot here to ensure csp.rules isn't finding its way into the
|
||||
// payload under some new and unexpected variable name (e.g. cspRules).
|
||||
expect(await collector.fetch(mockCallCluster)).toMatchInlineSnapshot(`
|
||||
expect(await collector.fetch(mockedFetchContext)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"rulesChangedFromDefault": false,
|
||||
"strict": true,
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { createCollectorFetchContextMock } from '../../../../usage_collection/server/mocks';
|
||||
import { registerKibanaUsageCollector } from './';
|
||||
|
||||
describe('telemetry_kibana', () => {
|
||||
|
@ -35,7 +35,12 @@ describe('telemetry_kibana', () => {
|
|||
});
|
||||
|
||||
const legacyConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$;
|
||||
const callCluster = jest.fn().mockImplementation(() => ({}));
|
||||
|
||||
const getMockFetchClients = (hits?: unknown[]) => {
|
||||
const fetchParamsMock = createCollectorFetchContextMock();
|
||||
fetchParamsMock.callCluster.mockResolvedValue({ hits: { hits } });
|
||||
return fetchParamsMock;
|
||||
};
|
||||
|
||||
beforeAll(() => registerKibanaUsageCollector(usageCollectionMock, legacyConfig$));
|
||||
afterAll(() => jest.clearAllTimers());
|
||||
|
@ -46,7 +51,7 @@ describe('telemetry_kibana', () => {
|
|||
});
|
||||
|
||||
test('fetch', async () => {
|
||||
expect(await collector.fetch(callCluster)).toStrictEqual({
|
||||
expect(await collector.fetch(getMockFetchClients())).toStrictEqual({
|
||||
index: '.kibana-tests',
|
||||
dashboard: { total: 0 },
|
||||
visualization: { total: 0 },
|
||||
|
|
|
@ -44,7 +44,7 @@ export function getKibanaUsageCollector(
|
|||
graph_workspace: { total: { type: 'long' } },
|
||||
timelion_sheet: { total: { type: 'long' } },
|
||||
},
|
||||
async fetch(callCluster) {
|
||||
async fetch({ callCluster }) {
|
||||
const {
|
||||
kibana: { index },
|
||||
} = await legacyConfig$.pipe(take(1)).toPromise();
|
||||
|
|
|
@ -21,6 +21,7 @@ import { uiSettingsServiceMock } from '../../../../../core/server/mocks';
|
|||
import {
|
||||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { registerManagementUsageCollector } from './';
|
||||
|
@ -36,7 +37,7 @@ describe('telemetry_application_usage_collector', () => {
|
|||
|
||||
const uiSettingsClient = uiSettingsServiceMock.createClient();
|
||||
const getUiSettingsClient = jest.fn(() => uiSettingsClient);
|
||||
const callCluster = jest.fn();
|
||||
const mockedFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
beforeAll(() => {
|
||||
registerManagementUsageCollector(usageCollectionMock, getUiSettingsClient);
|
||||
|
@ -59,11 +60,11 @@ describe('telemetry_application_usage_collector', () => {
|
|||
uiSettingsClient.getUserProvided.mockImplementationOnce(async () => ({
|
||||
'my-key': { userValue: 'my-value' },
|
||||
}));
|
||||
await expect(collector.fetch(callCluster)).resolves.toMatchSnapshot();
|
||||
await expect(collector.fetch(mockedFetchContext)).resolves.toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('fetch() should not fail if invoked when not ready', async () => {
|
||||
getUiSettingsClient.mockImplementationOnce(() => undefined as any);
|
||||
await expect(collector.fetch(callCluster)).resolves.toBe(undefined);
|
||||
await expect(collector.fetch(mockedFetchContext)).resolves.toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,6 +21,7 @@ import { Subject } from 'rxjs';
|
|||
import {
|
||||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { registerOpsStatsCollector } from './';
|
||||
|
@ -36,7 +37,7 @@ describe('telemetry_ops_stats', () => {
|
|||
});
|
||||
|
||||
const metrics$ = new Subject<OpsMetrics>();
|
||||
const callCluster = jest.fn();
|
||||
const mockedFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
const metric: OpsMetrics = {
|
||||
collected_at: new Date('2020-01-01 01:00:00'),
|
||||
|
@ -92,7 +93,7 @@ describe('telemetry_ops_stats', () => {
|
|||
test('should return something when there is a metric', async () => {
|
||||
metrics$.next(metric);
|
||||
expect(collector.isReady()).toBe(true);
|
||||
expect(await collector.fetch(callCluster)).toMatchSnapshot({
|
||||
expect(await collector.fetch(mockedFetchContext)).toMatchSnapshot({
|
||||
concurrent_connections: 20,
|
||||
os: {
|
||||
load: {
|
||||
|
|
|
@ -21,6 +21,7 @@ import { savedObjectsRepositoryMock } from '../../../../../core/server/mocks';
|
|||
import {
|
||||
CollectorOptions,
|
||||
createUsageCollectionSetupMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from '../../../../usage_collection/server/usage_collection.mock';
|
||||
|
||||
import { registerUiMetricUsageCollector } from './';
|
||||
|
@ -36,7 +37,7 @@ describe('telemetry_ui_metric', () => {
|
|||
|
||||
const getUsageCollector = jest.fn();
|
||||
const registerType = jest.fn();
|
||||
const callCluster = jest.fn();
|
||||
const mockedFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
beforeAll(() =>
|
||||
registerUiMetricUsageCollector(usageCollectionMock, registerType, getUsageCollector)
|
||||
|
@ -47,7 +48,7 @@ describe('telemetry_ui_metric', () => {
|
|||
});
|
||||
|
||||
test('if no savedObjectClient initialised, return undefined', async () => {
|
||||
expect(await collector.fetch(callCluster)).toBeUndefined();
|
||||
expect(await collector.fetch(mockedFetchContext)).toBeUndefined();
|
||||
});
|
||||
|
||||
test('when savedObjectClient is initialised, return something', async () => {
|
||||
|
@ -61,7 +62,7 @@ describe('telemetry_ui_metric', () => {
|
|||
);
|
||||
getUsageCollector.mockImplementation(() => savedObjectClient);
|
||||
|
||||
expect(await collector.fetch(callCluster)).toStrictEqual({});
|
||||
expect(await collector.fetch(mockedFetchContext)).toStrictEqual({});
|
||||
expect(savedObjectClient.bulkCreate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -85,7 +86,7 @@ describe('telemetry_ui_metric', () => {
|
|||
|
||||
getUsageCollector.mockImplementation(() => savedObjectClient);
|
||||
|
||||
expect(await collector.fetch(callCluster)).toStrictEqual({
|
||||
expect(await collector.fetch(mockedFetchContext)).toStrictEqual({
|
||||
testAppName: [
|
||||
{ key: 'testKeyName1', value: 3 },
|
||||
{ key: 'testKeyName2', value: 5 },
|
||||
|
|
|
@ -37,10 +37,9 @@ All you need to provide is a `type` for organizing your fields, `schema` field t
|
|||
```
|
||||
|
||||
3. Creating and registering a Usage Collector. Ideally collectors would be defined in a separate directory `server/collectors/register.ts`.
|
||||
|
||||
```ts
|
||||
// server/collectors/register.ts
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { UsageCollectionSetup, CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { APICluster } from 'kibana/server';
|
||||
|
||||
interface Usage {
|
||||
|
@ -63,7 +62,7 @@ All you need to provide is a `type` for organizing your fields, `schema` field t
|
|||
total: 'long',
|
||||
},
|
||||
},
|
||||
fetch: async (callCluster: APICluster, esClient: IClusterClient) => {
|
||||
fetch: async (collectorFetchContext: CollectorFetchContext) => {
|
||||
|
||||
// query ES and get some data
|
||||
// summarize the data into a model
|
||||
|
|
|
@ -45,11 +45,23 @@ export type MakeSchemaFrom<Base> = {
|
|||
: RecursiveMakeSchemaFrom<Required<Base>[Key]>;
|
||||
};
|
||||
|
||||
export interface CollectorFetchContext {
|
||||
/**
|
||||
* @depricated Scoped Legacy Elasticsearch client: use esClient instead
|
||||
*/
|
||||
callCluster: LegacyAPICaller;
|
||||
/**
|
||||
* Request-scoped Elasticsearch client:
|
||||
* - When users are requesting a sample of data, it is scoped to their role to avoid exposing data they should't read
|
||||
* - When building the telemetry data payload to report to the remote cluster, the requests are scoped to the `kibana` internal user
|
||||
*/
|
||||
esClient: ElasticsearchClient;
|
||||
}
|
||||
export interface CollectorOptions<T = unknown, U = T> {
|
||||
type: string;
|
||||
init?: Function;
|
||||
schema?: MakeSchemaFrom<T>;
|
||||
fetch: (callCluster: LegacyAPICaller, esClient?: ElasticsearchClient) => Promise<T> | T;
|
||||
fetch: (collectorFetchContext: CollectorFetchContext) => Promise<T> | T;
|
||||
/*
|
||||
* A hook for allowing the fetched data payload to be organized into a typed
|
||||
* data model for internal bulk upload. See defaultFormatterForBulkUpload for
|
||||
|
|
|
@ -81,7 +81,9 @@ describe('CollectorSet', () => {
|
|||
collectors.registerCollector(
|
||||
new Collector(logger, {
|
||||
type: 'MY_TEST_COLLECTOR',
|
||||
fetch: (caller: any) => caller(),
|
||||
fetch: (collectorFetchContext: any) => {
|
||||
return collectorFetchContext.callCluster();
|
||||
},
|
||||
isReady: () => true,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -122,9 +122,6 @@ export class CollectorSet {
|
|||
return allReady;
|
||||
};
|
||||
|
||||
// all collections eventually pass through bulkFetch.
|
||||
// the shape of the response is different when using the new ES client as is the error handling.
|
||||
// We'll handle the refactor for using the new client in a follow up PR.
|
||||
public bulkFetch = async (
|
||||
callCluster: LegacyAPICaller,
|
||||
esClient: ElasticsearchClient,
|
||||
|
@ -136,7 +133,7 @@ export class CollectorSet {
|
|||
try {
|
||||
return {
|
||||
type: collector.type,
|
||||
result: await collector.fetch(callCluster, esClient), // each collector must ensure they handle the response appropriately.
|
||||
result: await collector.fetch({ callCluster, esClient }),
|
||||
};
|
||||
} catch (err) {
|
||||
this.logger.warn(err);
|
||||
|
|
|
@ -24,5 +24,6 @@ export {
|
|||
SchemaField,
|
||||
MakeSchemaFrom,
|
||||
CollectorOptions,
|
||||
CollectorFetchContext,
|
||||
} from './collector';
|
||||
export { UsageCollector } from './usage_collector';
|
||||
|
|
|
@ -26,6 +26,7 @@ export {
|
|||
SchemaField,
|
||||
CollectorOptions,
|
||||
Collector,
|
||||
CollectorFetchContext,
|
||||
} from './collector';
|
||||
export { UsageCollectionSetup } from './plugin';
|
||||
export { config } from './config';
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import { loggingSystemMock } from '../../../core/server/mocks';
|
||||
import { UsageCollectionSetup } from './plugin';
|
||||
import { CollectorSet } from './collector';
|
||||
export { createCollectorFetchContextMock } from './usage_collection.mock';
|
||||
|
||||
const createSetupContract = () => {
|
||||
return {
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { elasticsearchServiceMock } from '../../../../src/core/server/mocks';
|
||||
|
||||
import { CollectorOptions } from './collector/collector';
|
||||
import { UsageCollectionSetup } from './index';
|
||||
import { UsageCollectionSetup, CollectorFetchContext } from './index';
|
||||
|
||||
export { CollectorOptions };
|
||||
|
||||
|
@ -45,3 +47,11 @@ export const createUsageCollectionSetupMock = () => {
|
|||
usageCollectionSetupMock.areAllCollectorsReady.mockResolvedValue(true);
|
||||
return usageCollectionSetupMock;
|
||||
};
|
||||
|
||||
export function createCollectorFetchContextMock(): jest.Mocked<CollectorFetchContext> {
|
||||
const collectorFetchClientsMock: jest.Mocked<CollectorFetchContext> = {
|
||||
callCluster: elasticsearchServiceMock.createLegacyClusterClient().callAsInternalUser,
|
||||
esClient: elasticsearchServiceMock.createClusterClient().asInternalUser,
|
||||
};
|
||||
return collectorFetchClientsMock;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyAPICaller, CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server';
|
||||
import { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server';
|
||||
import { UsageCollectionSetup } from '../../../usage_collection/server';
|
||||
import { tsvbTelemetrySavedObjectType } from '../saved_objects';
|
||||
|
||||
|
@ -49,7 +49,7 @@ export class ValidationTelemetryService implements Plugin<ValidationTelemetrySer
|
|||
usageCollection.makeUsageCollector<Usage>({
|
||||
type: 'tsvb-validation',
|
||||
isReady: () => this.kibanaIndex !== '',
|
||||
fetch: async (callCluster: LegacyAPICaller) => {
|
||||
fetch: async ({ callCluster }) => {
|
||||
try {
|
||||
const response = await callCluster('get', {
|
||||
index: this.kibanaIndex,
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyAPICaller } from 'src/core/server';
|
||||
import { getStats } from './get_usage_collector';
|
||||
import { HomeServerPluginSetup } from '../../../home/server';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
const mockedSavedObjects = [
|
||||
// vega-lite lib spec
|
||||
|
@ -70,8 +70,11 @@ const mockedSavedObjects = [
|
|||
},
|
||||
];
|
||||
|
||||
const getMockCallCluster = (hits?: unknown[]) =>
|
||||
jest.fn().mockReturnValue(Promise.resolve({ hits: { hits } }) as unknown) as LegacyAPICaller;
|
||||
const getMockCollectorFetchContext = (hits?: unknown[]) => {
|
||||
const fetchParamsMock = createCollectorFetchContextMock();
|
||||
fetchParamsMock.callCluster.mockResolvedValue({ hits: { hits } });
|
||||
return fetchParamsMock;
|
||||
};
|
||||
|
||||
describe('Vega visualization usage collector', () => {
|
||||
const mockIndex = 'mock_index';
|
||||
|
@ -101,19 +104,23 @@ describe('Vega visualization usage collector', () => {
|
|||
};
|
||||
|
||||
test('Returns undefined when no results found (undefined)', async () => {
|
||||
const result = await getStats(getMockCallCluster(), mockIndex, mockDeps);
|
||||
const result = await getStats(getMockCollectorFetchContext().callCluster, mockIndex, mockDeps);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('Returns undefined when no results found (0 results)', async () => {
|
||||
const result = await getStats(getMockCallCluster([]), mockIndex, mockDeps);
|
||||
const result = await getStats(
|
||||
getMockCollectorFetchContext([]).callCluster,
|
||||
mockIndex,
|
||||
mockDeps
|
||||
);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('Returns undefined when no vega saved objects found', async () => {
|
||||
const mockCallCluster = getMockCallCluster([
|
||||
const mockCollectorFetchContext = getMockCollectorFetchContext([
|
||||
{
|
||||
_id: 'visualization:myvis-123',
|
||||
_source: {
|
||||
|
@ -122,13 +129,13 @@ describe('Vega visualization usage collector', () => {
|
|||
},
|
||||
},
|
||||
]);
|
||||
const result = await getStats(mockCallCluster, mockIndex, mockDeps);
|
||||
const result = await getStats(mockCollectorFetchContext.callCluster, mockIndex, mockDeps);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('Should ingnore sample data visualizations', async () => {
|
||||
const mockCallCluster = getMockCallCluster([
|
||||
const mockCollectorFetchContext = getMockCollectorFetchContext([
|
||||
{
|
||||
_id: 'visualization:sampledata-123',
|
||||
_source: {
|
||||
|
@ -146,14 +153,14 @@ describe('Vega visualization usage collector', () => {
|
|||
},
|
||||
]);
|
||||
|
||||
const result = await getStats(mockCallCluster, mockIndex, mockDeps);
|
||||
const result = await getStats(mockCollectorFetchContext.callCluster, mockIndex, mockDeps);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('Summarizes visualizations response data', async () => {
|
||||
const mockCallCluster = getMockCallCluster(mockedSavedObjects);
|
||||
const result = await getStats(mockCallCluster, mockIndex, mockDeps);
|
||||
const mockCollectorFetchContext = getMockCollectorFetchContext(mockedSavedObjects);
|
||||
const result = await getStats(mockCollectorFetchContext.callCluster, mockIndex, mockDeps);
|
||||
|
||||
expect(result).toMatchObject({
|
||||
vega_lib_specs_total: 2,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import { of } from 'rxjs';
|
||||
import { mockStats, mockGetStats } from './get_usage_collector.mock';
|
||||
import { createUsageCollectionSetupMock } from 'src/plugins/usage_collection/server/usage_collection.mock';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import { HomeServerPluginSetup } from '../../../home/server';
|
||||
import { registerVegaUsageCollector } from './register_vega_collector';
|
||||
|
||||
|
@ -59,10 +60,14 @@ describe('registerVegaUsageCollector', () => {
|
|||
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||
registerVegaUsageCollector(mockCollectorSet, mockConfig, mockDeps);
|
||||
const usageCollectorConfig = mockCollectorSet.makeUsageCollector.mock.calls[0][0];
|
||||
const mockCallCluster = jest.fn();
|
||||
const fetchResult = await usageCollectorConfig.fetch(mockCallCluster);
|
||||
const mockedCollectorFetchContext = createCollectorFetchContextMock();
|
||||
const fetchResult = await usageCollectorConfig.fetch(mockedCollectorFetchContext);
|
||||
expect(mockGetStats).toBeCalledTimes(1);
|
||||
expect(mockGetStats).toBeCalledWith(mockCallCluster, mockIndex, mockDeps);
|
||||
expect(mockGetStats).toBeCalledWith(
|
||||
mockedCollectorFetchContext.callCluster,
|
||||
mockIndex,
|
||||
mockDeps
|
||||
);
|
||||
expect(fetchResult).toBe(mockStats);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ export function registerVegaUsageCollector(
|
|||
vega_lite_lib_specs_total: { type: 'long' },
|
||||
vega_use_map_total: { type: 'long' },
|
||||
},
|
||||
fetch: async (callCluster) => {
|
||||
fetch: async ({ callCluster }) => {
|
||||
const { index } = (await config.pipe(first()).toPromise()).kibana;
|
||||
|
||||
return await getStats(callCluster, index, dependencies);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import { of } from 'rxjs';
|
||||
import { mockStats, mockGetStats } from './get_usage_collector.mock';
|
||||
import { createUsageCollectionSetupMock } from 'src/plugins/usage_collection/server/usage_collection.mock';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
import { registerVisualizationsCollector } from './register_visualizations_collector';
|
||||
|
||||
|
@ -58,10 +59,10 @@ describe('registerVisualizationsCollector', () => {
|
|||
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||
registerVisualizationsCollector(mockCollectorSet, mockConfig);
|
||||
const usageCollectorConfig = mockCollectorSet.makeUsageCollector.mock.calls[0][0];
|
||||
const mockCallCluster = jest.fn();
|
||||
const fetchResult = await usageCollectorConfig.fetch(mockCallCluster);
|
||||
const mockCollectorFetchContext = createCollectorFetchContextMock();
|
||||
const fetchResult = await usageCollectorConfig.fetch(mockCollectorFetchContext);
|
||||
expect(mockGetStats).toBeCalledTimes(1);
|
||||
expect(mockGetStats).toBeCalledWith(mockCallCluster, mockIndex);
|
||||
expect(mockGetStats).toBeCalledWith(mockCollectorFetchContext.callCluster, mockIndex);
|
||||
expect(fetchResult).toBe(mockStats);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,7 +41,7 @@ export function registerVisualizationsCollector(
|
|||
saved_90_days_total: { type: 'long' },
|
||||
},
|
||||
},
|
||||
fetch: async (callCluster) => {
|
||||
fetch: async ({ callCluster }) => {
|
||||
const index = (await config.pipe(first()).toPromise()).kibana.index;
|
||||
return await getStats(callCluster, index);
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { TelemetryCollector } from '../../types';
|
||||
|
||||
import { workpadCollector, workpadSchema, WorkpadTelemetry } from './workpad_collector';
|
||||
|
@ -37,7 +37,7 @@ export function registerCanvasUsageCollector(
|
|||
const canvasCollector = usageCollection.makeUsageCollector<CanvasUsage>({
|
||||
type: 'canvas',
|
||||
isReady: () => true,
|
||||
fetch: async (callCluster) => {
|
||||
fetch: async ({ callCluster }: CollectorFetchContext) => {
|
||||
const collectorResults = await Promise.all(
|
||||
collectors.map((collector) => collector(kibanaIndex, callCluster))
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { createCloudUsageCollector } from './cloud_usage_collector';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
const mockUsageCollection = () => ({
|
||||
makeUsageCollector: jest.fn().mockImplementation((args: any) => ({ ...args })),
|
||||
|
@ -25,9 +26,9 @@ describe('createCloudUsageCollector', () => {
|
|||
const mockConfigs = getMockConfigs(true);
|
||||
const usageCollection = mockUsageCollection() as any;
|
||||
const collector = createCloudUsageCollector(usageCollection, mockConfigs);
|
||||
const callCluster = {} as any; // Sending any as the callCluster client because it's not needed in this collector but TS requires it when calling it.
|
||||
const collectorFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
expect((await collector.fetch(callCluster)).isCloudEnabled).toBe(true); // Adding the await because the fetch can be a Promise or a synchronous method and TS complains in the test if not awaited
|
||||
expect((await collector.fetch(collectorFetchContext)).isCloudEnabled).toBe(true); // Adding the await because the fetch can be a Promise or a synchronous method and TS complains in the test if not awaited
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
import * as Rx from 'rxjs';
|
||||
import sinon from 'sinon';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import { ReportingConfig, ReportingCore } from '../';
|
||||
import { getExportTypesRegistry } from '../lib/export_types_registry';
|
||||
import { createMockConfig, createMockConfigSchema, createMockReportingCore } from '../test_helpers';
|
||||
|
@ -56,6 +57,11 @@ function getPluginsMock(
|
|||
|
||||
const getResponseMock = (base = {}) => base;
|
||||
|
||||
const getMockFetchClients = (resp: any) => {
|
||||
const fetchParamsMock = createCollectorFetchContextMock();
|
||||
fetchParamsMock.callCluster.mockResolvedValue(resp);
|
||||
return fetchParamsMock;
|
||||
};
|
||||
describe('license checks', () => {
|
||||
let mockConfig: ReportingConfig;
|
||||
let mockCore: ReportingCore;
|
||||
|
@ -68,7 +74,6 @@ describe('license checks', () => {
|
|||
let usageStats: any;
|
||||
beforeAll(async () => {
|
||||
const plugins = getPluginsMock({ license: 'basic' });
|
||||
const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
|
||||
const { fetch } = getReportingUsageCollector(
|
||||
mockCore,
|
||||
plugins.usageCollection,
|
||||
|
@ -78,7 +83,7 @@ describe('license checks', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
usageStats = await fetch(callClusterMock as any);
|
||||
usageStats = await fetch(getMockFetchClients(getResponseMock()));
|
||||
});
|
||||
|
||||
test('sets enables to true', async () => {
|
||||
|
@ -98,7 +103,6 @@ describe('license checks', () => {
|
|||
let usageStats: any;
|
||||
beforeAll(async () => {
|
||||
const plugins = getPluginsMock({ license: 'none' });
|
||||
const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
|
||||
const { fetch } = getReportingUsageCollector(
|
||||
mockCore,
|
||||
plugins.usageCollection,
|
||||
|
@ -108,7 +112,7 @@ describe('license checks', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
usageStats = await fetch(callClusterMock as any);
|
||||
usageStats = await fetch(getMockFetchClients(getResponseMock()));
|
||||
});
|
||||
|
||||
test('sets enables to true', async () => {
|
||||
|
@ -128,7 +132,6 @@ describe('license checks', () => {
|
|||
let usageStats: any;
|
||||
beforeAll(async () => {
|
||||
const plugins = getPluginsMock({ license: 'platinum' });
|
||||
const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock()));
|
||||
const { fetch } = getReportingUsageCollector(
|
||||
mockCore,
|
||||
plugins.usageCollection,
|
||||
|
@ -138,7 +141,7 @@ describe('license checks', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
usageStats = await fetch(callClusterMock as any);
|
||||
usageStats = await fetch(getMockFetchClients(getResponseMock()));
|
||||
});
|
||||
|
||||
test('sets enables to true', async () => {
|
||||
|
@ -158,7 +161,6 @@ describe('license checks', () => {
|
|||
let usageStats: any;
|
||||
beforeAll(async () => {
|
||||
const plugins = getPluginsMock({ license: 'basic' });
|
||||
const callClusterMock = jest.fn(() => Promise.resolve({}));
|
||||
const { fetch } = getReportingUsageCollector(
|
||||
mockCore,
|
||||
plugins.usageCollection,
|
||||
|
@ -168,7 +170,7 @@ describe('license checks', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
usageStats = await fetch(callClusterMock as any);
|
||||
usageStats = await fetch(getMockFetchClients({}));
|
||||
});
|
||||
|
||||
test('sets enables to true', async () => {
|
||||
|
@ -184,6 +186,7 @@ describe('license checks', () => {
|
|||
describe('data modeling', () => {
|
||||
let mockConfig: ReportingConfig;
|
||||
let mockCore: ReportingCore;
|
||||
let collectorFetchContext: CollectorFetchContext;
|
||||
beforeAll(async () => {
|
||||
mockConfig = createMockConfig(createMockConfigSchema());
|
||||
mockCore = await createMockReportingCore(mockConfig);
|
||||
|
@ -199,44 +202,42 @@ describe('data modeling', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
const callClusterMock = jest.fn(() =>
|
||||
Promise.resolve(
|
||||
getResponseMock({
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 12,
|
||||
jobTypes: { buckets: [ { doc_count: 9, key: 'printable_pdf' }, { doc_count: 3, key: 'PNG' }, ], },
|
||||
layoutTypes: { doc_count: 9, pdf: { buckets: [{ doc_count: 9, key: 'preserve_layout' }] }, },
|
||||
objectTypes: { doc_count: 9, pdf: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, },
|
||||
statusByApp: { buckets: [ { doc_count: 10, jobTypes: { buckets: [ { appNames: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, doc_count: 9, key: 'printable_pdf', }, { appNames: { buckets: [{ doc_count: 1, key: 'visualization' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'failed', }, ], },
|
||||
statusTypes: { buckets: [ { doc_count: 10, key: 'completed' }, { doc_count: 1, key: 'completed_with_warnings' }, { doc_count: 1, key: 'failed' }, ], },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 1,
|
||||
jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], },
|
||||
statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 1,
|
||||
jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], },
|
||||
statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] },
|
||||
},
|
||||
collectorFetchContext = getMockFetchClients(
|
||||
getResponseMock(
|
||||
{
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 12,
|
||||
jobTypes: { buckets: [ { doc_count: 9, key: 'printable_pdf' }, { doc_count: 3, key: 'PNG' }, ], },
|
||||
layoutTypes: { doc_count: 9, pdf: { buckets: [{ doc_count: 9, key: 'preserve_layout' }] }, },
|
||||
objectTypes: { doc_count: 9, pdf: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, },
|
||||
statusByApp: { buckets: [ { doc_count: 10, jobTypes: { buckets: [ { appNames: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, doc_count: 9, key: 'printable_pdf', }, { appNames: { buckets: [{ doc_count: 1, key: 'visualization' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'failed', }, ], },
|
||||
statusTypes: { buckets: [ { doc_count: 10, key: 'completed' }, { doc_count: 1, key: 'completed_with_warnings' }, { doc_count: 1, key: 'failed' }, ], },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 1,
|
||||
jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], },
|
||||
statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 1,
|
||||
jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], },
|
||||
statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as SearchResponse) // prettier-ignore
|
||||
)
|
||||
},
|
||||
} as SearchResponse) // prettier-ignore
|
||||
);
|
||||
|
||||
const usageStats = await fetch(callClusterMock as any);
|
||||
const usageStats = await fetch(collectorFetchContext);
|
||||
expect(usageStats).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -251,44 +252,42 @@ describe('data modeling', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
const callClusterMock = jest.fn(() =>
|
||||
Promise.resolve(
|
||||
getResponseMock({
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
collectorFetchContext = getMockFetchClients(
|
||||
getResponseMock(
|
||||
{
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 4,
|
||||
layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, },
|
||||
statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], },
|
||||
objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, },
|
||||
statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] },
|
||||
jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as SearchResponse) // prettier-ignore
|
||||
)
|
||||
},
|
||||
} as SearchResponse) // prettier-ignore
|
||||
);
|
||||
|
||||
const usageStats = await fetch(callClusterMock as any);
|
||||
const usageStats = await fetch(collectorFetchContext);
|
||||
expect(usageStats).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -303,43 +302,42 @@ describe('data modeling', () => {
|
|||
return Promise.resolve(true);
|
||||
}
|
||||
);
|
||||
const callClusterMock = jest.fn(() =>
|
||||
Promise.resolve(
|
||||
getResponseMock({
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
},
|
||||
|
||||
collectorFetchContext = getMockFetchClients(
|
||||
getResponseMock({
|
||||
aggregations: {
|
||||
ranges: {
|
||||
buckets: {
|
||||
all: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
last7Days: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
lastDay: {
|
||||
doc_count: 0,
|
||||
jobTypes: { buckets: [] },
|
||||
layoutTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
objectTypes: { doc_count: 0, pdf: { buckets: [] } },
|
||||
statusByApp: { buckets: [] },
|
||||
statusTypes: { buckets: [] },
|
||||
},
|
||||
},
|
||||
} as SearchResponse)
|
||||
)
|
||||
},
|
||||
},
|
||||
} as SearchResponse) // prettier-ignore
|
||||
);
|
||||
const usageStats = await fetch(callClusterMock as any);
|
||||
const usageStats = await fetch(collectorFetchContext);
|
||||
expect(usageStats).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
*/
|
||||
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { ReportingCore } from '../';
|
||||
import { ExportTypesRegistry } from '../lib/export_types_registry';
|
||||
import { ReportingSetupDeps } from '../types';
|
||||
|
@ -37,7 +36,7 @@ export function getReportingUsageCollector(
|
|||
) {
|
||||
return usageCollection.makeUsageCollector<ReportingUsageType, XpackBulkUpload>({
|
||||
type: 'reporting',
|
||||
fetch: (callCluster: LegacyAPICaller) => {
|
||||
fetch: ({ callCluster }: CollectorFetchContext) => {
|
||||
const config = reporting.getConfig();
|
||||
return getReportingUsage(config, getLicense, callCluster, exportTypesRegistry);
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { UsageCollectionSetup, CollectorFetchContext } from 'src/plugins/usage_collection/server';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
|
||||
interface IdToFlagMap {
|
||||
|
@ -211,7 +211,7 @@ export function registerRollupUsageCollector(
|
|||
total: { type: 'long' },
|
||||
},
|
||||
},
|
||||
fetch: async (callCluster: LegacyAPICaller) => {
|
||||
fetch: async ({ callCluster }: CollectorFetchContext) => {
|
||||
const rollupIndexPatterns = await fetchRollupIndexPatterns(kibanaIndex, callCluster);
|
||||
const rollupIndexPatternToFlagMap = createIdToFlagMap(rollupIndexPatterns);
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
import { createConfig, ConfigSchema } from '../config';
|
||||
import { loggingSystemMock } from 'src/core/server/mocks';
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import { usageCollectionPluginMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
import {
|
||||
usageCollectionPluginMock,
|
||||
createCollectorFetchContextMock,
|
||||
} from 'src/plugins/usage_collection/server/mocks';
|
||||
import { registerSecurityUsageCollector } from './security_usage_collector';
|
||||
import { elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
import { licenseMock } from '../../common/licensing/index.mock';
|
||||
import { SecurityLicenseFeatures } from '../../common/licensing';
|
||||
|
||||
|
@ -34,7 +36,7 @@ describe('Security UsageCollector', () => {
|
|||
return license;
|
||||
};
|
||||
|
||||
const clusterClient = elasticsearchServiceMock.createLegacyClusterClient();
|
||||
const collectorFetchContext = createCollectorFetchContextMock();
|
||||
|
||||
describe('initialization', () => {
|
||||
it('handles an undefined usage collector', () => {
|
||||
|
@ -68,7 +70,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -89,7 +91,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -133,7 +135,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -182,7 +184,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -220,7 +222,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -258,7 +260,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -299,7 +301,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -338,7 +340,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -366,7 +368,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: true,
|
||||
|
@ -392,7 +394,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -422,7 +424,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
@ -450,7 +452,7 @@ describe('Security UsageCollector', () => {
|
|||
|
||||
const usage = await usageCollection
|
||||
.getCollectorByType('security')
|
||||
?.fetch(clusterClient.asScoped().callAsCurrentUser);
|
||||
?.fetch(collectorFetchContext);
|
||||
|
||||
expect(usage).toEqual({
|
||||
auditLoggingEnabled: false,
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { LegacyAPICaller, CoreSetup } from '../../../../../src/core/server';
|
||||
import { CoreSetup } from '../../../../../src/core/server';
|
||||
import { CollectorFetchContext } from '../../../../../src/plugins/usage_collection/server';
|
||||
import { CollectorDependencies } from './types';
|
||||
import { DetectionsUsage, fetchDetectionsUsage, defaultDetectionsUsage } from './detections';
|
||||
import { EndpointUsage, getEndpointTelemetryFromFleet } from './endpoints';
|
||||
|
@ -77,7 +78,7 @@ export const registerCollector: RegisterCollector = ({
|
|||
},
|
||||
},
|
||||
isReady: () => kibanaIndex.length > 0,
|
||||
fetch: async (callCluster: LegacyAPICaller): Promise<UsageData> => {
|
||||
fetch: async ({ callCluster }: CollectorFetchContext): Promise<UsageData> => {
|
||||
const savedObjectsClient = await getInternalSavedObjectsClient(core);
|
||||
const [detections, endpoints] = await Promise.allSettled([
|
||||
fetchDetectionsUsage(kibanaIndex, callCluster, ml),
|
||||
|
|
|
@ -10,6 +10,7 @@ import { PluginsSetup } from '../plugin';
|
|||
import { KibanaFeature } from '../../../features/server';
|
||||
import { ILicense, LicensingPluginSetup } from '../../../licensing/server';
|
||||
import { pluginInitializerContextConfigMock } from 'src/core/server/mocks';
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
|
||||
interface SetupOpts {
|
||||
license?: Partial<ILicense>;
|
||||
|
@ -67,6 +68,13 @@ const defaultCallClusterMock = jest.fn().mockResolvedValue({
|
|||
},
|
||||
});
|
||||
|
||||
const getMockFetchContext = (mockedCallCluster: jest.Mock) => {
|
||||
return {
|
||||
...createCollectorFetchContextMock(),
|
||||
callCluster: mockedCallCluster,
|
||||
};
|
||||
};
|
||||
|
||||
describe('error handling', () => {
|
||||
it('handles a 404 when searching for space usage', async () => {
|
||||
const { features, licensing, usageCollecion } = setup({
|
||||
|
@ -78,7 +86,7 @@ describe('error handling', () => {
|
|||
licensing,
|
||||
});
|
||||
|
||||
await getSpacesUsage(jest.fn().mockRejectedValue({ status: 404 }));
|
||||
await getSpacesUsage(getMockFetchContext(jest.fn().mockRejectedValue({ status: 404 })));
|
||||
});
|
||||
|
||||
it('throws error for a non-404', async () => {
|
||||
|
@ -94,7 +102,9 @@ describe('error handling', () => {
|
|||
const statusCodes = [401, 402, 403, 500];
|
||||
for (const statusCode of statusCodes) {
|
||||
const error = { status: statusCode };
|
||||
await expect(getSpacesUsage(jest.fn().mockRejectedValue(error))).rejects.toBe(error);
|
||||
await expect(
|
||||
getSpacesUsage(getMockFetchContext(jest.fn().mockRejectedValue(error)))
|
||||
).rejects.toBe(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -110,7 +120,7 @@ describe('with a basic license', () => {
|
|||
features,
|
||||
licensing,
|
||||
});
|
||||
usageStats = await getSpacesUsage(defaultCallClusterMock);
|
||||
usageStats = await getSpacesUsage(getMockFetchContext(defaultCallClusterMock));
|
||||
|
||||
expect(defaultCallClusterMock).toHaveBeenCalledWith('search', {
|
||||
body: {
|
||||
|
@ -158,7 +168,7 @@ describe('with no license', () => {
|
|||
features,
|
||||
licensing,
|
||||
});
|
||||
usageStats = await getSpacesUsage(defaultCallClusterMock);
|
||||
usageStats = await getSpacesUsage(getMockFetchContext(defaultCallClusterMock));
|
||||
});
|
||||
|
||||
test('sets enabled to false', () => {
|
||||
|
@ -189,7 +199,7 @@ describe('with platinum license', () => {
|
|||
features,
|
||||
licensing,
|
||||
});
|
||||
usageStats = await getSpacesUsage(defaultCallClusterMock);
|
||||
usageStats = await getSpacesUsage(getMockFetchContext(defaultCallClusterMock));
|
||||
});
|
||||
|
||||
test('sets enabled to true', () => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { LegacyCallAPIOptions } from 'src/core/server';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { Observable } from 'rxjs';
|
||||
import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants';
|
||||
import { PluginsSetup } from '../plugin';
|
||||
|
@ -188,7 +188,7 @@ export function getSpacesUsageCollector(
|
|||
enabled: { type: 'boolean' },
|
||||
count: { type: 'long' },
|
||||
},
|
||||
fetch: async (callCluster: CallCluster) => {
|
||||
fetch: async ({ callCluster }: CollectorFetchContext) => {
|
||||
const license = await deps.licensing.license$.pipe(take(1)).toPromise();
|
||||
const available = license.isAvailable; // some form of spaces is available for all valid licenses
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { KibanaTelemetryAdapter } from '../kibana_telemetry_adapter';
|
||||
|
||||
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||
jest
|
||||
.spyOn(KibanaTelemetryAdapter, 'countNoOfUniqueMonitorAndLocations')
|
||||
.mockResolvedValue(undefined as any);
|
||||
|
@ -13,7 +13,12 @@ jest
|
|||
describe('KibanaTelemetryAdapter', () => {
|
||||
let usageCollection: any;
|
||||
let getSavedObjectsClient: any;
|
||||
let collector: { type: string; fetch: () => Promise<any>; isReady: () => boolean };
|
||||
let collectorFetchContext: any;
|
||||
let collector: {
|
||||
type: string;
|
||||
fetch: (collectorFetchParams: any) => Promise<any>;
|
||||
isReady: () => boolean;
|
||||
};
|
||||
beforeEach(() => {
|
||||
usageCollection = {
|
||||
makeUsageCollector: (val: any) => {
|
||||
|
@ -23,6 +28,7 @@ describe('KibanaTelemetryAdapter', () => {
|
|||
getSavedObjectsClient = () => {
|
||||
return {};
|
||||
};
|
||||
collectorFetchContext = createCollectorFetchContextMock();
|
||||
});
|
||||
|
||||
it('collects monitor and overview data', async () => {
|
||||
|
@ -49,7 +55,7 @@ describe('KibanaTelemetryAdapter', () => {
|
|||
autoRefreshEnabled: true,
|
||||
autorefreshInterval: 30,
|
||||
});
|
||||
const result = await collector.fetch();
|
||||
const result = await collector.fetch(collectorFetchContext);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -87,7 +93,7 @@ describe('KibanaTelemetryAdapter', () => {
|
|||
autoRefreshEnabled: true,
|
||||
autorefreshInterval: 30,
|
||||
});
|
||||
const result = await collector.fetch();
|
||||
const result = await collector.fetch(collectorFetchContext);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import moment from 'moment';
|
||||
import { ISavedObjectsRepository, SavedObjectsClientContract } from 'kibana/server';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { CollectorFetchContext, UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { PageViewParams, UptimeTelemetry, Usage } from './types';
|
||||
import { ESAPICaller } from '../framework';
|
||||
import { savedObjectsAdapter } from '../../saved_objects';
|
||||
|
@ -69,7 +69,7 @@ export class KibanaTelemetryAdapter {
|
|||
},
|
||||
},
|
||||
},
|
||||
fetch: async (callCluster: ESAPICaller) => {
|
||||
fetch: async ({ callCluster }: CollectorFetchContext) => {
|
||||
const savedObjectsClient = getSavedObjectsClient()!;
|
||||
if (savedObjectsClient) {
|
||||
await this.countNoOfUniqueMonitorAndLocations(callCluster, savedObjectsClient);
|
||||
|
|
|
@ -13,14 +13,14 @@ import {
|
|||
ServiceStatus,
|
||||
ServiceStatusLevels,
|
||||
} from '../../../../../src/core/server';
|
||||
import { contextServiceMock } from '../../../../../src/core/server/mocks';
|
||||
import { contextServiceMock, elasticsearchServiceMock } from '../../../../../src/core/server/mocks';
|
||||
import { createHttpServer } from '../../../../../src/core/server/test_utils';
|
||||
import { registerSettingsRoute } from './settings';
|
||||
|
||||
type HttpService = ReturnType<typeof createHttpServer>;
|
||||
type HttpSetup = UnwrapPromise<ReturnType<HttpService['setup']>>;
|
||||
|
||||
describe('/api/stats', () => {
|
||||
describe('/api/settings', () => {
|
||||
let server: HttpService;
|
||||
let httpSetup: HttpSetup;
|
||||
let overallStatus$: BehaviorSubject<ServiceStatus>;
|
||||
|
@ -38,6 +38,9 @@ describe('/api/stats', () => {
|
|||
callAsCurrentUser: mockApiCaller,
|
||||
},
|
||||
},
|
||||
client: {
|
||||
asCurrentUser: elasticsearchServiceMock.createScopedClusterClient().asCurrentUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -42,6 +42,10 @@ export function registerSettingsRoute({
|
|||
},
|
||||
async (context, req, res) => {
|
||||
const { callAsCurrentUser } = context.core.elasticsearch.legacy.client;
|
||||
const collectorFetchContext = {
|
||||
callCluster: callAsCurrentUser,
|
||||
esClient: context.core.elasticsearch.client.asCurrentUser,
|
||||
};
|
||||
|
||||
const settingsCollector = usageCollection.getCollectorByType(KIBANA_SETTINGS_TYPE) as
|
||||
| KibanaSettingsCollector
|
||||
|
@ -51,7 +55,7 @@ export function registerSettingsRoute({
|
|||
}
|
||||
|
||||
const settings =
|
||||
(await settingsCollector.fetch(callAsCurrentUser)) ??
|
||||
(await settingsCollector.fetch(collectorFetchContext)) ??
|
||||
settingsCollector.getEmailValueStructure(null);
|
||||
const { cluster_uuid: uuid } = await callAsCurrentUser('info', {
|
||||
filterPath: 'cluster_uuid',
|
||||
|
|
Loading…
Reference in a new issue