mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Dashboard favorites telemetry (#190706)
## Summary Add telemetry to favorites feature https://github.com/elastic/kibana/pull/189285 - Adds UI usage counter telemetry, increase the counter when favorite / unfavorite is clicked - Add snapshot telemetry: - total "favorite" object in the deployment - total users+spaces count combination who have used the favorites feature - avg per user per space (only counts those users who favorited at least once) - max favorites objects per user per space Unfortunately, for snapshot telemetry, I had to add fields to kibana mapping. We didn't need them for a feature, but I didn't realize that will have to add them to a mapping. Not sure if there is a better way
This commit is contained in:
parent
7d54e4e026
commit
ec0230b1cc
24 changed files with 317 additions and 26 deletions
|
@ -28,9 +28,11 @@ import {
|
|||
FavoriteButton,
|
||||
} from '@kbn/content-management-favorites-public';
|
||||
|
||||
const appName = 'my-app';
|
||||
const favoriteObjectType = 'dashboard';
|
||||
const favoritesClient = new FavoritesClient('dashboard', {
|
||||
const favoritesClient = new FavoritesClient(appName, favoriteObjectType, {
|
||||
http: core.http,
|
||||
usageCollection: plugins.usageCollection,
|
||||
});
|
||||
|
||||
// wrap your content with the favorites context provider
|
||||
|
|
|
@ -12,6 +12,7 @@ import classNames from 'classnames';
|
|||
import { EuiButtonIcon, euiCanAnimate, EuiThemeComputed } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { useFavorites, useRemoveFavorite, useAddFavorite } from '../favorites_query';
|
||||
import { useFavoritesClient } from '../favorites_context';
|
||||
|
||||
export interface FavoriteButtonProps {
|
||||
id: string;
|
||||
|
@ -24,6 +25,8 @@ export const FavoriteButton = ({ id, className }: FavoriteButtonProps) => {
|
|||
const removeFavorite = useRemoveFavorite();
|
||||
const addFavorite = useAddFavorite();
|
||||
|
||||
const favoritesClient = useFavoritesClient();
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
const isFavorite = data.favoriteIds.includes(id);
|
||||
|
@ -40,6 +43,7 @@ export const FavoriteButton = ({ id, className }: FavoriteButtonProps) => {
|
|||
aria-label={title}
|
||||
iconType={'starFilled'}
|
||||
onClick={() => {
|
||||
favoritesClient?.reportRemoveFavoriteClick();
|
||||
removeFavorite.mutate({ id });
|
||||
}}
|
||||
className={classNames(className, 'cm-favorite-button', {
|
||||
|
@ -59,6 +63,7 @@ export const FavoriteButton = ({ id, className }: FavoriteButtonProps) => {
|
|||
aria-label={title}
|
||||
iconType={'starEmpty'}
|
||||
onClick={() => {
|
||||
favoritesClient?.reportAddFavoriteClick();
|
||||
addFavorite.mutate({ id });
|
||||
}}
|
||||
className={classNames(className, 'cm-favorite-button', {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import type { HttpStart } from '@kbn/core-http-browser';
|
||||
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import type { GetFavoritesResponse } from '@kbn/content-management-favorites-server';
|
||||
|
||||
export interface FavoritesClientPublic {
|
||||
|
@ -15,10 +16,16 @@ export interface FavoritesClientPublic {
|
|||
removeFavorite({ id }: { id: string }): Promise<GetFavoritesResponse>;
|
||||
|
||||
getFavoriteType(): string;
|
||||
reportAddFavoriteClick(): void;
|
||||
reportRemoveFavoriteClick(): void;
|
||||
}
|
||||
|
||||
export class FavoritesClient implements FavoritesClientPublic {
|
||||
constructor(private favoriteObjectType: string, private deps: { http: HttpStart }) {}
|
||||
constructor(
|
||||
private readonly appName: string,
|
||||
private readonly favoriteObjectType: string,
|
||||
private readonly deps: { http: HttpStart; usageCollection?: UsageCollectionStart }
|
||||
) {}
|
||||
|
||||
public async getFavorites(): Promise<GetFavoritesResponse> {
|
||||
return this.deps.http.get(`/internal/content_management/favorites/${this.favoriteObjectType}`);
|
||||
|
@ -39,4 +46,11 @@ export class FavoritesClient implements FavoritesClientPublic {
|
|||
public getFavoriteType() {
|
||||
return this.favoriteObjectType;
|
||||
}
|
||||
|
||||
public reportAddFavoriteClick() {
|
||||
this.deps.usageCollection?.reportUiCounter(this.appName, 'click', 'add_favorite');
|
||||
}
|
||||
public reportRemoveFavoriteClick() {
|
||||
this.deps.usageCollection?.reportUiCounter(this.appName, 'click', 'remove_favorite');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,5 +22,6 @@
|
|||
"@kbn/core-http-browser",
|
||||
"@kbn/content-management-favorites-server",
|
||||
"@kbn/i18n-react",
|
||||
"@kbn/usage-collection-plugin",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -21,13 +21,19 @@ const schemaV1 = schema.object({
|
|||
favoriteIds: schema.arrayOf(schema.string()),
|
||||
});
|
||||
|
||||
export const favoritesSavedObjectName = 'favorites';
|
||||
|
||||
export const favoritesSavedObjectType: SavedObjectsType = {
|
||||
name: 'favorites',
|
||||
name: favoritesSavedObjectName,
|
||||
hidden: true,
|
||||
namespaceType: 'single',
|
||||
mappings: {
|
||||
dynamic: false,
|
||||
properties: {},
|
||||
properties: {
|
||||
userId: { type: 'keyword' },
|
||||
type: { type: 'keyword' },
|
||||
favoriteIds: { type: 'keyword' },
|
||||
},
|
||||
},
|
||||
modelVersions: {
|
||||
1: {
|
||||
|
@ -41,5 +47,22 @@ export const favoritesSavedObjectType: SavedObjectsType = {
|
|||
create: schemaV1,
|
||||
},
|
||||
},
|
||||
2: {
|
||||
// the model stays the same, but we added the mappings for the snapshot telemetry needs
|
||||
changes: [
|
||||
{
|
||||
type: 'mappings_addition',
|
||||
addedMappings: {
|
||||
userId: { type: 'keyword' },
|
||||
type: { type: 'keyword' },
|
||||
favoriteIds: { type: 'keyword' },
|
||||
},
|
||||
},
|
||||
],
|
||||
schemas: {
|
||||
forwardCompatibility: schemaV1.extends({}, { unknowns: 'ignore' }),
|
||||
create: schemaV1,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core-lifecycle-server';
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { favoritesSavedObjectName } from './favorites_saved_object';
|
||||
|
||||
interface FavoritesUsage {
|
||||
[favorite_object_type: string]: {
|
||||
total: number;
|
||||
total_users_spaces: number;
|
||||
avg_per_user_per_space: number;
|
||||
max_per_user_per_space: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function registerFavoritesUsageCollection({
|
||||
core,
|
||||
usageCollection,
|
||||
}: {
|
||||
core: CoreSetup;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
}) {
|
||||
usageCollection.registerCollector(
|
||||
usageCollection.makeUsageCollector<FavoritesUsage>({
|
||||
type: 'favorites',
|
||||
isReady: () => true,
|
||||
schema: {
|
||||
DYNAMIC_KEY /* e.g. 'dashboard' */: {
|
||||
total: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Total favorite object count in this deployment' },
|
||||
},
|
||||
total_users_spaces: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Total users per space that have favorited an object of this type in this deployment',
|
||||
},
|
||||
},
|
||||
avg_per_user_per_space: {
|
||||
type: 'double',
|
||||
_meta: {
|
||||
description:
|
||||
'Average favorite objects count of this type per user per space for this deployment, only counts users who have favorited at least one object of this type',
|
||||
},
|
||||
},
|
||||
max_per_user_per_space: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Max favorite objects count of this type per user per space for this deployment',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fetch: async (context) => {
|
||||
const favoritesIndex = await core
|
||||
.getStartServices()
|
||||
.then(([{ savedObjects }]) => savedObjects.getIndexForType(favoritesSavedObjectName));
|
||||
|
||||
const response = await context.esClient.search<
|
||||
unknown,
|
||||
{ types: estypes.AggregationsStringTermsAggregate }
|
||||
>({
|
||||
index: favoritesIndex,
|
||||
size: 0,
|
||||
_source: false,
|
||||
filter_path: ['aggregations'],
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
type: 'favorites',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime_mappings: {
|
||||
number_of_favorites: {
|
||||
type: 'long',
|
||||
script: {
|
||||
source: "emit(doc['favorites.favoriteIds'].length)",
|
||||
},
|
||||
},
|
||||
},
|
||||
aggs: {
|
||||
types: {
|
||||
terms: {
|
||||
field: 'favorites.type',
|
||||
},
|
||||
aggs: {
|
||||
stats: {
|
||||
stats: {
|
||||
field: 'number_of_favorites',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const favoritesUsage: FavoritesUsage = {};
|
||||
|
||||
const typesBuckets = (response.aggregations?.types?.buckets ??
|
||||
[]) as estypes.AggregationsStringTermsBucket[];
|
||||
|
||||
typesBuckets.forEach((bucket) => {
|
||||
favoritesUsage[bucket.key] = {
|
||||
total: bucket.stats.sum,
|
||||
total_users_spaces: bucket.stats.count,
|
||||
avg_per_user_per_space: bucket.stats.avg,
|
||||
max_per_user_per_space: bucket.stats.max,
|
||||
};
|
||||
});
|
||||
|
||||
return favoritesUsage;
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
import type { CoreSetup, Logger } from '@kbn/core/server';
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import { registerFavoritesRoutes } from './favorites_routes';
|
||||
import { favoritesSavedObjectType } from './favorites_saved_object';
|
||||
import { registerFavoritesUsageCollection } from './favorites_usage_collection';
|
||||
|
||||
export type { GetFavoritesResponse } from './favorites_routes';
|
||||
|
||||
|
@ -18,8 +20,21 @@ export type { GetFavoritesResponse } from './favorites_routes';
|
|||
*
|
||||
* @param logger
|
||||
* @param core
|
||||
* @param usageCollection
|
||||
*/
|
||||
export function registerFavorites({ logger, core }: { core: CoreSetup; logger: Logger }) {
|
||||
export function registerFavorites({
|
||||
logger,
|
||||
core,
|
||||
usageCollection,
|
||||
}: {
|
||||
core: CoreSetup;
|
||||
logger: Logger;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}) {
|
||||
core.savedObjects.registerType(favoritesSavedObjectType);
|
||||
registerFavoritesRoutes({ core, logger });
|
||||
|
||||
if (usageCollection) {
|
||||
registerFavoritesUsageCollection({ core, usageCollection });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,7 @@
|
|||
"@kbn/core",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/core-saved-objects-api-server",
|
||||
"@kbn/core-lifecycle-server",
|
||||
"@kbn/usage-collection-plugin",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -436,7 +436,11 @@
|
|||
"updated_by",
|
||||
"version"
|
||||
],
|
||||
"favorites": [],
|
||||
"favorites": [
|
||||
"favoriteIds",
|
||||
"type",
|
||||
"userId"
|
||||
],
|
||||
"file": [
|
||||
"FileKind",
|
||||
"Meta",
|
||||
|
|
|
@ -1484,7 +1484,17 @@
|
|||
},
|
||||
"favorites": {
|
||||
"dynamic": false,
|
||||
"properties": {}
|
||||
"properties": {
|
||||
"favoriteIds": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"userId": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"dynamic": false,
|
||||
|
|
|
@ -98,7 +98,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"event_loop_delays_daily": "01b967e8e043801357503de09199dfa3853bab88",
|
||||
"exception-list": "4aebc4e61fb5d608cae48eaeb0977e8db21c61a4",
|
||||
"exception-list-agnostic": "6d3262d58eee28ac381ec9654f93126a58be6f5d",
|
||||
"favorites": "ef282e9fb5a91df3cc88409a9f86d993fb51a6e9",
|
||||
"favorites": "a68c7c8ae22eaddcca324d8b3bfc80a94e3eec3a",
|
||||
"file": "6b65ae5899b60ebe08656fd163ea532e557d3c98",
|
||||
"file-upload-usage-collection-telemetry": "06e0a8c04f991e744e09d03ab2bd7f86b2088200",
|
||||
"fileShare": "5be52de1747d249a221b5241af2838264e19aaa1",
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
"plugin": {
|
||||
"id": "contentManagement",
|
||||
"server": true,
|
||||
"browser": true
|
||||
"browser": true,
|
||||
"optionalPlugins": [
|
||||
"usageCollection"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,14 +80,15 @@ const setup = () => {
|
|||
...coreSetup,
|
||||
http,
|
||||
},
|
||||
pluginsSetup: {},
|
||||
};
|
||||
};
|
||||
|
||||
describe('ContentManagementPlugin', () => {
|
||||
describe('setup()', () => {
|
||||
test('should expose the core API', () => {
|
||||
const { plugin, coreSetup } = setup();
|
||||
const api = plugin.setup(coreSetup);
|
||||
const { plugin, coreSetup, pluginsSetup } = setup();
|
||||
const api = plugin.setup(coreSetup, pluginsSetup);
|
||||
|
||||
expect(Object.keys(api).sort()).toEqual(['crud', 'eventBus', 'register']);
|
||||
expect(api.crud('')).toBe('mockedCrud');
|
||||
|
@ -97,8 +98,8 @@ describe('ContentManagementPlugin', () => {
|
|||
|
||||
describe('RPC', () => {
|
||||
test('should create a rpc POST HTTP route on the router', () => {
|
||||
const { plugin, coreSetup, router } = setup();
|
||||
plugin.setup(coreSetup);
|
||||
const { plugin, coreSetup, router, pluginsSetup } = setup();
|
||||
plugin.setup(coreSetup, pluginsSetup);
|
||||
|
||||
const [routeConfig]: Parameters<IRouter['post']> = (router.post as jest.Mock).mock.calls[0];
|
||||
|
||||
|
@ -106,8 +107,8 @@ describe('ContentManagementPlugin', () => {
|
|||
});
|
||||
|
||||
test('should register all the procedures in the RPC service and the route handler must send to each procedure the core request context + the request body as input', async () => {
|
||||
const { plugin, coreSetup, router } = setup();
|
||||
plugin.setup(coreSetup);
|
||||
const { plugin, coreSetup, router, pluginsSetup } = setup();
|
||||
plugin.setup(coreSetup, pluginsSetup);
|
||||
|
||||
const [_, handler]: Parameters<IRouter['post']> = (router.post as jest.Mock).mock.calls[0];
|
||||
|
||||
|
@ -150,8 +151,8 @@ describe('ContentManagementPlugin', () => {
|
|||
});
|
||||
|
||||
test('should return error in custom error format', async () => {
|
||||
const { plugin, coreSetup, router } = setup();
|
||||
plugin.setup(coreSetup);
|
||||
const { plugin, coreSetup, router, pluginsSetup } = setup();
|
||||
plugin.setup(coreSetup, pluginsSetup);
|
||||
|
||||
const [_, handler]: Parameters<IRouter['post']> = (router.post as jest.Mock).mock.calls[0];
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ export class ContentManagementPlugin
|
|||
});
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
public setup(core: CoreSetup, plugins: ContentManagementServerSetupDependencies) {
|
||||
if (this.#eventStream) {
|
||||
this.#eventStream.setup({ core });
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ export class ContentManagementPlugin
|
|||
contentRegistry,
|
||||
});
|
||||
|
||||
registerFavorites({ core, logger: this.logger });
|
||||
registerFavorites({ core, logger: this.logger, usageCollection: plugins.usageCollection });
|
||||
|
||||
return {
|
||||
...coreApi,
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
*/
|
||||
|
||||
import type { Version } from '@kbn/object-versioning';
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import type { CoreApi, StorageContextGetTransformFn } from './core';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface ContentManagementServerSetupDependencies {}
|
||||
export interface ContentManagementServerSetupDependencies {
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface ContentManagementServerStartDependencies {}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"@kbn/saved-objects-settings",
|
||||
"@kbn/core-http-server",
|
||||
"@kbn/content-management-favorites-server",
|
||||
"@kbn/usage-collection-plugin",
|
||||
"@kbn/object-versioning-utils",
|
||||
],
|
||||
"exclude": [
|
||||
|
|
|
@ -14,5 +14,7 @@ import { DashboardFavoritesService } from './types';
|
|||
export type DashboardFavoritesServiceFactory = PluginServiceFactory<DashboardFavoritesService>;
|
||||
|
||||
export const dashboardFavoritesServiceFactory: DashboardFavoritesServiceFactory = () => {
|
||||
return new FavoritesClient('dashboard', { http: httpServiceMock.createStartContract() });
|
||||
return new FavoritesClient('dashboards', 'dashboard', {
|
||||
http: httpServiceMock.createStartContract(),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ import { FavoritesClient } from '@kbn/content-management-favorites-public';
|
|||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { DashboardStartDependencies } from '../../plugin';
|
||||
import { DashboardFavoritesService } from './types';
|
||||
import { DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID } from '../../dashboard_constants';
|
||||
|
||||
export type DashboardFavoritesServiceFactory = KibanaPluginServiceFactory<
|
||||
DashboardFavoritesService,
|
||||
|
@ -18,6 +19,10 @@ export type DashboardFavoritesServiceFactory = KibanaPluginServiceFactory<
|
|||
|
||||
export const dashboardFavoritesServiceFactory: DashboardFavoritesServiceFactory = ({
|
||||
coreStart,
|
||||
startPlugins,
|
||||
}) => {
|
||||
return new FavoritesClient('dashboard', { http: coreStart.http });
|
||||
return new FavoritesClient(DASHBOARD_APP_ID, DASHBOARD_CONTENT_ID, {
|
||||
http: coreStart.http,
|
||||
usageCollection: startPlugins.usageCollection,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,36 @@
|
|||
{
|
||||
"properties": {
|
||||
"favorites": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Total favorite object count in this deployment"
|
||||
}
|
||||
},
|
||||
"total_users_spaces": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Total users per space that have favorited an object of this type in this deployment"
|
||||
}
|
||||
},
|
||||
"avg_per_user_per_space": {
|
||||
"type": "double",
|
||||
"_meta": {
|
||||
"description": "Average favorite objects count of this type per user per space for this deployment, only counts users who have favorited at least one object of this type"
|
||||
}
|
||||
},
|
||||
"max_per_user_per_space": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Max favorite objects count of this type per user per space for this deployment"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"../../../typings/**/*",
|
||||
"schema/oss_plugins.json",
|
||||
"schema/oss_root.json",
|
||||
"schema/kbn_packages.json"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import type { UnencryptedTelemetryPayload } from '@kbn/telemetry-plugin/common/types';
|
||||
import {
|
||||
ELASTIC_HTTP_VERSION_HEADER,
|
||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||
} from '@kbn/core-http-common';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import {
|
||||
|
@ -163,6 +168,28 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
response = await api.favorite({ dashboardId: 'fav1', user: interactiveUser3 });
|
||||
expect(response.body.favoriteIds).to.eql(['fav1']);
|
||||
});
|
||||
|
||||
// depends on the state from previous test
|
||||
it('reports favorites stats', async () => {
|
||||
const { body }: { body: UnencryptedTelemetryPayload } = await getService('supertest')
|
||||
.post('/internal/telemetry/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set(ELASTIC_HTTP_VERSION_HEADER, '2')
|
||||
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
|
||||
.send({ unencrypted: true, refreshCache: true })
|
||||
.expect(200);
|
||||
|
||||
// @ts-ignore
|
||||
const favoritesStats = body[0].stats.stack_stats.kibana.plugins.favorites;
|
||||
expect(favoritesStats).to.eql({
|
||||
dashboard: {
|
||||
total: 3,
|
||||
total_users_spaces: 3,
|
||||
avg_per_user_per_space: 1,
|
||||
max_per_user_per_space: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json';
|
|||
import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json';
|
||||
import monitoringRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_monitoring.json';
|
||||
import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json';
|
||||
import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json';
|
||||
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
||||
import type { UnencryptedTelemetryPayload } from '@kbn/telemetry-plugin/common/types';
|
||||
import type {
|
||||
|
@ -160,7 +161,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
// It's nested because of the way it's collected and declared
|
||||
monitoringRootTelemetrySchema.properties.monitoringTelemetry.properties.stats.items
|
||||
);
|
||||
const plugins = deepmerge(ossPluginsTelemetrySchema, xpackPluginsTelemetrySchema);
|
||||
const plugins = deepmerge(
|
||||
deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema),
|
||||
xpackPluginsTelemetrySchema
|
||||
);
|
||||
|
||||
try {
|
||||
assertTelemetryPayload({ root, plugins }, localXPack);
|
||||
|
|
|
@ -9,6 +9,7 @@ import expect from '@kbn/expect';
|
|||
import deepmerge from 'deepmerge';
|
||||
import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json';
|
||||
import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json';
|
||||
import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json';
|
||||
import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json';
|
||||
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
||||
|
@ -56,7 +57,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('should pass the schema validation', () => {
|
||||
const root = deepmerge(ossRootTelemetrySchema, xpackRootTelemetrySchema);
|
||||
const plugins = deepmerge(ossPluginsTelemetrySchema, xpackPluginsTelemetrySchema);
|
||||
const plugins = deepmerge(
|
||||
deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema),
|
||||
xpackPluginsTelemetrySchema
|
||||
);
|
||||
|
||||
try {
|
||||
assertTelemetryPayload({ root, plugins }, stats);
|
||||
|
|
|
@ -10,6 +10,7 @@ import deepmerge from 'deepmerge';
|
|||
import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json';
|
||||
import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json';
|
||||
import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json';
|
||||
import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json';
|
||||
import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json';
|
||||
import { assertTelemetryPayload } from '@kbn/telemetry-tools';
|
||||
import type { UsageStatsPayloadTestFriendly } from '@kbn/test-suites-xpack/api_integration/services/usage_api';
|
||||
|
@ -41,7 +42,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('should pass the schema validation (ensures BWC with Classic offering)', () => {
|
||||
const root = deepmerge(ossRootTelemetrySchema, xpackRootTelemetrySchema);
|
||||
const plugins = deepmerge(ossPluginsTelemetrySchema, xpackPluginsTelemetrySchema);
|
||||
const plugins = deepmerge(
|
||||
deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema),
|
||||
xpackPluginsTelemetrySchema
|
||||
);
|
||||
|
||||
try {
|
||||
assertTelemetryPayload({ root, plugins }, stats);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue