[Discover] Replace RxJS firstValueFrom with RxJS lastValueFrom to prevent problem with partial results (#134682)

This commit is contained in:
Matthias Wilhelm 2022-06-20 17:15:15 +02:00 committed by GitHub
parent 44b2a2ded0
commit 69cd603a90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 167 additions and 73 deletions

View file

@ -7,7 +7,7 @@
import React from 'react';
import 'brace';
import { of } from 'rxjs';
import { of, Subject } from 'rxjs';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import { act } from 'react-dom/test-utils';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
@ -220,6 +220,42 @@ describe('EsQueryAlertTypeExpression', () => {
);
});
test('should show success message if Test Query is successful (with partial result)', async () => {
const partial = {
isRunning: true,
isPartial: true,
};
const complete = {
isRunning: false,
isPartial: false,
rawResponse: {
hits: {
total: 1234,
},
},
};
const searchResponseMock$ = new Subject();
dataMock.search.search.mockImplementation(() => searchResponseMock$);
const wrapper = await setup(defaultEsQueryExpressionParams);
const testQueryButton = wrapper.find('EuiButton[data-test-subj="testQuery"]');
testQueryButton.simulate('click');
expect(dataMock.search.search).toHaveBeenCalled();
await act(async () => {
searchResponseMock$.next(partial);
searchResponseMock$.next(complete);
searchResponseMock$.complete();
await nextTick();
wrapper.update();
});
expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy();
expect(wrapper.find('EuiText[data-test-subj="testQuerySuccess"]').text()).toEqual(
`Query matched 1234 documents in the last 15s.`
);
});
test('should show error message if Test Query is throws error', async () => {
dataMock.search.search.mockImplementation(() => {
throw new Error('What is this query');

View file

@ -6,7 +6,7 @@
*/
import React, { useState, Fragment, useEffect, useCallback } from 'react';
import { firstValueFrom } from 'rxjs';
import { lastValueFrom } from 'rxjs';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
@ -141,7 +141,7 @@ export const EsQueryExpression = ({
const timeWindow = parseDuration(window);
const parsedQuery = JSON.parse(esQuery);
const now = Date.now();
const { rawResponse } = await firstValueFrom(
const { rawResponse } = await lastValueFrom(
data.search.search({
params: buildSortedEventsQuery({
index,

View file

@ -14,8 +14,8 @@ import { EsQueryAlertParams, SearchType } from '../types';
import { SearchSourceExpression } from './search_source_expression';
import { chartPluginMock } from '@kbn/charts-plugin/public/mocks';
import { act } from 'react-dom/test-utils';
import { of } from 'rxjs';
import { IKibanaSearchResponse, ISearchSource } from '@kbn/data-plugin/common';
import { Subject } from 'rxjs';
import { ISearchSource } from '@kbn/data-plugin/common';
import { IUiSettingsClient } from '@kbn/core/public';
import { findTestSubject } from '@elastic/eui/lib/test';
import { EuiLoadingSpinner } from '@elastic/eui';
@ -40,6 +40,20 @@ const defaultSearchSourceExpressionParams: EsQueryAlertParams<SearchType.searchS
searchConfiguration: {},
};
const mockSearchResult = new Subject();
const testResultComplete = {
rawResponse: {
hits: {
total: 1234,
},
},
};
const testResultPartial = {
partial: true,
running: true,
};
const searchSourceMock = {
id: 'data_source6',
fields: {
@ -67,13 +81,7 @@ const searchSourceMock = {
return searchSourceMock;
}),
fetch$: jest.fn(() => {
return of<IKibanaSearchResponse>({
rawResponse: {
hits: {
total: 1234,
},
},
});
return mockSearchResult;
}),
} as unknown as ISearchSource;
@ -143,6 +151,7 @@ describe('SearchSourceAlertTypeExpression', () => {
wrapper = await wrapper.update();
expect(findTestSubject(wrapper, 'thresholdExpression')).toBeTruthy();
});
test('should show success message if Test Query is successful', async () => {
let wrapper = setup(defaultSearchSourceExpressionParams);
await act(async () => {
@ -156,6 +165,9 @@ describe('SearchSourceAlertTypeExpression', () => {
wrapper = await wrapper.update();
await act(async () => {
mockSearchResult.next(testResultPartial);
mockSearchResult.next(testResultComplete);
mockSearchResult.complete();
await nextTick();
wrapper.update();
});

View file

@ -7,7 +7,7 @@
import React, { Fragment, useCallback, useEffect, useMemo, useReducer, useState } from 'react';
import deepEqual from 'fast-deep-equal';
import { firstValueFrom } from 'rxjs';
import { lastValueFrom } from 'rxjs';
import { Filter } from '@kbn/es-query';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiSpacer, EuiTitle } from '@elastic/eui';
@ -183,7 +183,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
'filter',
timeFilter ? [timeFilter, ...ruleConfiguration.filter] : ruleConfiguration.filter
);
const { rawResponse } = await firstValueFrom(testSearchSource.fetch$());
const { rawResponse } = await lastValueFrom(testSearchSource.fetch$());
return { nrOfDocs: totalHitsToNumber(rawResponse.hits.total), timeWindow };
}, [searchSource, timeWindowSize, timeWindowUnit, ruleConfiguration]);