From 51ef0e7034e4aa4c3515e3e863221bed08e118a8 Mon Sep 17 00:00:00 2001 From: Irene Blanco Date: Wed, 4 Dec 2024 12:41:44 +0100 Subject: [PATCH] [Infra] Send Host View Total Host Count Retrieved event on every query submission in hosts inventory (#202691) ## Summary Fixes https://github.com/elastic/kibana/issues/202441 This PR reintroduces the `Host View Total Host Count Retrieved` event, which was unintentionally removed in the past. It has been added back to the same position in the code as previously |Scenario|Event| |-|-| |Page load|![Screenshot 2024-12-03 at 12 37 28](https://github.com/user-attachments/assets/8a12d713-219b-4c1f-a08e-7b475634b4fc)| |Query|![Screenshot 2024-12-03 at 12 40 12](https://github.com/user-attachments/assets/501a8a81-b0b0-46a6-a470-dceeba791c01)| |Filter|![Screenshot 2024-12-03 at 12 40 56](https://github.com/user-attachments/assets/586f2176-b05b-4571-b3d8-f3f9cb803249)| --- .../hosts/hooks/use_host_count.test.ts | 144 ++++++++++++++++++ .../metrics/hosts/hooks/use_host_count.ts | 17 ++- 2 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.test.ts diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.test.ts new file mode 100644 index 0000000000000..641194c82888a --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.test.ts @@ -0,0 +1,144 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react'; +import { useFetcher } from '../../../../hooks/use_fetcher'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; +import * as useKibanaContextForPluginHook from '../../../../hooks/use_kibana'; +import * as useUnifiedSearchHooks from './use_unified_search'; +import { useHostCount } from './use_host_count'; + +jest.mock('../../../../hooks/use_fetcher'); +jest.mock('../../../../hooks/use_kibana'); +jest.mock('./use_unified_search'); + +describe('useHostCount', () => { + const useKibanaContextForPluginMock = useKibanaContextForPlugin as jest.MockedFunction< + typeof useKibanaContextForPlugin + >; + + const telemetryMock = { reportHostsViewTotalHostCountRetrieved: jest.fn() }; + + useKibanaContextForPluginMock.mockReturnValue({ + services: { telemetry: telemetryMock }, + } as unknown as ReturnType); + + const useUnifiedSearchContextMock = + useUnifiedSearchHooks.useUnifiedSearchContext as jest.MockedFunction< + typeof useUnifiedSearchHooks.useUnifiedSearchContext + >; + + const mockUseUnifiedContext = (searchCriteria: any) => { + useUnifiedSearchContextMock.mockReturnValue({ + buildQuery: jest.fn(() => 'query'), + parsedDateRange: { from: '', to: '' }, + searchCriteria, + } as unknown as ReturnType); + }; + + describe('when data is fetched', () => { + const fetcherDataMock = { count: 10 }; + + beforeAll(() => { + (useFetcher as jest.Mock).mockReturnValue({ + data: fetcherDataMock, + status: 'success', + error: null, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('and there is no filters or query applied', () => { + it('should call reportHostsViewTotalHostCountRetrieved with the correct data', async () => { + mockUseUnifiedContext({ + query: { query: null }, + filters: [], + panelFilters: [], + }); + + await renderHook(() => useHostCount()); + + expect(telemetryMock.reportHostsViewTotalHostCountRetrieved).toHaveBeenCalledWith({ + total: fetcherDataMock.count, + with_query: false, + with_filters: false, + }); + }); + }); + + describe('and query is applied', () => { + it('should call reportHostsViewTotalHostCountRetrieved with the correct data', async () => { + mockUseUnifiedContext({ query: { query: 'test' }, filters: [], panelFilters: [] }); + + await renderHook(() => useHostCount()); + + expect(telemetryMock.reportHostsViewTotalHostCountRetrieved).toHaveBeenCalledWith({ + total: fetcherDataMock.count, + with_query: true, + with_filters: false, + }); + }); + }); + + describe('and filters are applied', () => { + it('should call reportHostsViewTotalHostCountRetrieved with the correct data', async () => { + mockUseUnifiedContext({ + query: { query: null }, + filters: [{ filter: 'filter' }], + panelFilters: [], + }); + + await renderHook(() => useHostCount()); + + expect(telemetryMock.reportHostsViewTotalHostCountRetrieved).toHaveBeenCalledWith({ + total: fetcherDataMock.count, + with_query: false, + with_filters: true, + }); + }); + }); + + describe('and panel filters are applied', () => { + it('should call reportHostsViewTotalHostCountRetrieved with the correct data', async () => { + mockUseUnifiedContext({ + query: { query: null }, + filters: [{ filter: 'filter' }], + panelFilters: [{ filter: 'filter' }], + }); + + await renderHook(() => useHostCount()); + + expect(telemetryMock.reportHostsViewTotalHostCountRetrieved).toHaveBeenCalledWith({ + total: fetcherDataMock.count, + with_query: false, + with_filters: true, + }); + }); + }); + }); + + describe('when data is fetched with error', () => { + beforeAll(() => { + (useFetcher as jest.Mock).mockReturnValue({ + data: {}, + status: 'error', + error: 'error', + }); + }); + + it('should NOT call reportHostsViewTotalHostCountRetrieved ', async () => { + mockUseUnifiedContext(null); + + await renderHook(() => useHostCount()); + + expect(telemetryMock.reportHostsViewTotalHostCountRetrieved).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.ts index a09e46ed2792a..fd723fd596146 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_host_count.ts @@ -7,13 +7,16 @@ import createContainer from 'constate'; import { decodeOrThrow } from '@kbn/io-ts-utils'; -import { useMemo } from 'react'; +import { useMemo, useEffect } from 'react'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { GetInfraAssetCountResponsePayloadRT } from '../../../../../common/http_api'; import { isPending, useFetcher } from '../../../../hooks/use_fetcher'; import { useUnifiedSearchContext } from './use_unified_search'; export const useHostCount = () => { - const { buildQuery, parsedDateRange } = useUnifiedSearchContext(); + const { buildQuery, parsedDateRange, searchCriteria } = useUnifiedSearchContext(); + const { services } = useKibanaContextForPlugin(); + const { telemetry } = services; const payload = useMemo( () => @@ -37,6 +40,16 @@ export const useHostCount = () => { [payload] ); + useEffect(() => { + if (data && !error) { + telemetry.reportHostsViewTotalHostCountRetrieved({ + total: data.count ?? 0, + with_query: !!searchCriteria.query.query, + with_filters: searchCriteria.filters.length > 0 || searchCriteria.panelFilters.length > 0, + }); + } + }, [data, error, payload, searchCriteria, telemetry]); + return { errors: error, loading: isPending(status),