Skip to content

Commit

Permalink
Merge branch 'main' into reporting/tests-serverless-improvements-ii
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan authored Oct 24, 2024
2 parents 8e4ee0f + b5f51e4 commit ba8a7a0
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 53 deletions.
2 changes: 1 addition & 1 deletion packages/deeplinks/search/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

export const ENTERPRISE_SEARCH_APP_ID = 'enterpriseSearch';
export const ENTERPRISE_SEARCH_CONTENT_APP_ID = 'enterpriseSearchContent';
export const ENTERPRISE_SEARCH_RELEVANCE_APP_ID = 'enterpriseSearchRelevance';
export const ENTERPRISE_SEARCH_RELEVANCE_APP_ID = 'searchInferenceEndpoints';
export const ENTERPRISE_SEARCH_APPLICATIONS_APP_ID = 'enterpriseSearchApplications';
export const ENTERPRISE_SEARCH_ANALYTICS_APP_ID = 'enterpriseSearchAnalytics';
export const ENTERPRISE_SEARCH_APPSEARCH_APP_ID = 'appSearch';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const applicationUsageSchema = {
canvas: commonSchema,
enterpriseSearch: commonSchema,
enterpriseSearchContent: commonSchema,
enterpriseSearchRelevance: commonSchema,
searchInferenceEndpoints: commonSchema,
enterpriseSearchAnalytics: commonSchema,
enterpriseSearchApplications: commonSchema,
enterpriseSearchAISearch: commonSchema,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/telemetry/schema/oss_plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,7 @@
}
}
},
"enterpriseSearchRelevance": {
"searchInferenceEndpoints": {
"properties": {
"appId": {
"type": "keyword",
Expand Down
96 changes: 96 additions & 0 deletions x-pack/plugins/enterprise_search/common/utils/licensing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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 type { ILicense } from '@kbn/licensing-plugin/public';

import { hasEnterpriseLicense } from './licensing';

describe('licensing utils', () => {
const baseLicense: ILicense = {
isActive: true,
type: 'trial',
isAvailable: true,
signature: 'fake',
toJSON: jest.fn(),
getUnavailableReason: jest.fn().mockReturnValue(undefined),
hasAtLeast: jest.fn().mockReturnValue(false),
check: jest.fn().mockReturnValue({ state: 'valid' }),
getFeature: jest.fn().mockReturnValue({ isAvailable: false, isEnabled: false }),
};
describe('hasEnterpriseLicense', () => {
let license: ILicense;
beforeEach(() => {
jest.resetAllMocks();
license = {
...baseLicense,
};
});
it('returns true for active enterprise license', () => {
license.type = 'enterprise';

expect(hasEnterpriseLicense(license)).toEqual(true);
});
it('returns true for active trial license', () => {
expect(hasEnterpriseLicense(license)).toEqual(true);
});
it('returns false for active basic license', () => {
license.type = 'basic';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active gold license', () => {
license.type = 'gold';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active platinum license', () => {
license.type = 'platinum';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive enterprise license', () => {
license.type = 'enterprise';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive trial license', () => {
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive basic license', () => {
license.type = 'basic';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive gold license', () => {
license.type = 'gold';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive platinum license', () => {
license.type = 'platinum';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active license is missing type', () => {
delete license.type;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for null license', () => {
expect(hasEnterpriseLicense(null)).toEqual(false);
});
it('returns false for undefined license', () => {
expect(hasEnterpriseLicense(undefined)).toEqual(false);
});
});
});
16 changes: 16 additions & 0 deletions x-pack/plugins/enterprise_search/common/utils/licensing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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 type { ILicense } from '@kbn/licensing-plugin/public';

/* hasEnterpriseLicense return if the given license is an active `enterprise` or `trial` license
*/
export function hasEnterpriseLicense(license: ILicense | null | undefined): boolean {
if (license === undefined || license === null) return false;
const qualifyingLicenses = ['enterprise', 'trial'];
return license.isActive && qualifyingLicenses.includes(license?.type ?? '');
}
2 changes: 1 addition & 1 deletion x-pack/plugins/enterprise_search/public/navigation_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const getNavigationTreeDefinition = ({
}),
},
{
children: [{ link: 'enterpriseSearchRelevance:inferenceEndpoints' }],
children: [{ link: 'searchInferenceEndpoints:inferenceEndpoints' }],
id: 'relevance',
title: i18n.translate('xpack.enterpriseSearch.searchNav.relevance', {
defaultMessage: 'Relevance',
Expand Down
21 changes: 19 additions & 2 deletions x-pack/plugins/enterprise_search/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
PluginInitializerContext,
DEFAULT_APP_CATEGORIES,
AppDeepLink,
type AppUpdater,
AppStatus,
} from '@kbn/core/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';

Expand Down Expand Up @@ -53,8 +55,8 @@ import {
SEARCH_RELEVANCE_PLUGIN,
} from '../common/constants';
import { registerLocators } from '../common/locators';

import { ClientConfigType, InitialAppData } from '../common/types';
import { hasEnterpriseLicense } from '../common/utils/licensing';

import { ENGINES_PATH } from './applications/app_search/routes';
import { SEARCH_APPLICATIONS_PATH, PLAYGROUND_PATH } from './applications/applications/routes';
Expand Down Expand Up @@ -134,7 +136,7 @@ const contentLinks: AppDeepLink[] = [

const relevanceLinks: AppDeepLink[] = [
{
id: 'searchInferenceEndpoints',
id: 'inferenceEndpoints',
path: `/${INFERENCE_ENDPOINTS_PATH}`,
title: i18n.translate(
'xpack.enterpriseSearch.navigation.relevanceInferenceEndpointsLinkLabel',
Expand Down Expand Up @@ -180,6 +182,7 @@ const appSearchLinks: AppDeepLink[] = [

export class EnterpriseSearchPlugin implements Plugin {
private config: ClientConfigType;
private enterpriseLicenseAppUpdater$ = new BehaviorSubject<AppUpdater>(() => ({}));

constructor(initializerContext: PluginInitializerContext) {
this.config = initializerContext.config.get<ClientConfigType>();
Expand Down Expand Up @@ -440,6 +443,8 @@ export class EnterpriseSearchPlugin implements Plugin {
deepLinks: relevanceLinks,
euiIconType: SEARCH_RELEVANCE_PLUGIN.LOGO,
id: SEARCH_RELEVANCE_PLUGIN.ID,
status: AppStatus.inaccessible,
updater$: this.enterpriseLicenseAppUpdater$,
mount: async (params: AppMountParameters) => {
const kibanaDeps = await this.getKibanaDeps(core, params, cloud);
const { chrome, http } = kibanaDeps.core;
Expand Down Expand Up @@ -615,6 +620,18 @@ export class EnterpriseSearchPlugin implements Plugin {
);
});

plugins.licensing?.license$.subscribe((license) => {
if (hasEnterpriseLicense(license)) {
this.enterpriseLicenseAppUpdater$.next(() => ({
status: AppStatus.accessible,
}));
} else {
this.enterpriseLicenseAppUpdater$.next(() => ({
status: AppStatus.inaccessible,
}));
}
});

// Return empty start contract rather than void in order for plugins
// that depend on the enterprise search plugin to determine whether it is enabled or not
return {};
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
} from '../../tasks/live_query';
import { generateRandomStringName, interceptCaseId } from '../../tasks/integrations';

describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () => {
// Failing: See https://github.com/elastic/kibana/issues/197151
describe.skip('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () => {
let ruleId: string;
let packId: string;
let packName: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
import type { FC } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import styled from 'styled-components';
import { euiThemeVars } from '@kbn/ui-theme';
import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, useEuiTheme, EuiFlyoutFooter, EuiPanel } from '@elastic/eui';
import { find } from 'lodash/fp';
import { FLYOUT_FOOTER_TEST_ID } from './test_ids';
import type { Status } from '../../../../common/api/detection_engine';
Expand All @@ -27,10 +25,6 @@ import { useExceptionFlyout } from '../../../detections/components/alerts_table/
import { isActiveTimeline } from '../../../helpers';
import { useEventFilterModal } from '../../../detections/components/alerts_table/timeline_actions/use_event_filter_modal';

const StyledEuiFlyoutFooter = styled('div')`
padding: ${euiThemeVars.euiPanelPaddingModifiers.paddingMedium};
`;

interface AlertSummaryData {
/**
* Status of the alert (open, closed...)
Expand Down Expand Up @@ -182,27 +176,29 @@ export const PanelFooter: FC<PanelFooterProps> = ({ isPreview }) => {

return (
<>
<StyledEuiFlyoutFooter data-test-subj={FLYOUT_FOOTER_TEST_ID}>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
{dataAsNestedObject && (
<TakeActionDropdown
dataFormattedForFieldBrowser={dataFormattedForFieldBrowser}
dataAsNestedObject={dataAsNestedObject}
handleOnEventClosed={closeFlyout}
isHostIsolationPanelOpen={isHostIsolationPanelOpen}
onAddEventFilterClick={onAddEventFilterClick}
onAddExceptionTypeClick={onAddExceptionTypeClick}
onAddIsolationStatusClick={showHostIsolationPanelCallback}
refetchFlyoutData={refetchFlyoutData}
refetch={refetchAll}
scopeId={scopeId}
onOsqueryClick={setOsqueryFlyoutOpenWithAgentId}
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
</StyledEuiFlyoutFooter>
<EuiFlyoutFooter data-test-subj={FLYOUT_FOOTER_TEST_ID}>
<EuiPanel color="transparent">
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
{dataAsNestedObject && (
<TakeActionDropdown
dataFormattedForFieldBrowser={dataFormattedForFieldBrowser}
dataAsNestedObject={dataAsNestedObject}
handleOnEventClosed={closeFlyout}
isHostIsolationPanelOpen={isHostIsolationPanelOpen}
onAddEventFilterClick={onAddEventFilterClick}
onAddExceptionTypeClick={onAddExceptionTypeClick}
onAddIsolationStatusClick={showHostIsolationPanelCallback}
refetchFlyoutData={refetchFlyoutData}
refetch={refetchAll}
scopeId={scopeId}
onOsqueryClick={setOsqueryFlyoutOpenWithAgentId}
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlyoutFooter>

{openAddExceptionFlyout &&
alertSummaryData.ruleId != null &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,17 @@ describe('createManagedConfiguration()', () => {
expect(subscription).toHaveBeenNthCalledWith(2, 8);
});

test('should decrease configuration at the next interval when a 503 error is emitted', async () => {
const { subscription, errors$ } = setupScenario(10);
errors$.next(SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('a', 'b'));
clock.tick(ADJUST_THROUGHPUT_INTERVAL - 1);
expect(subscription).toHaveBeenCalledTimes(1);
expect(subscription).toHaveBeenNthCalledWith(1, 10);
clock.tick(1);
expect(subscription).toHaveBeenCalledTimes(2);
expect(subscription).toHaveBeenNthCalledWith(2, 8);
});

test('should log a warning when the configuration changes from the starting value', async () => {
const { errors$ } = setupScenario(10);
errors$.next(SavedObjectsErrorHelpers.createTooManyRequestsError('a', 'b'));
Expand Down Expand Up @@ -235,6 +246,17 @@ describe('createManagedConfiguration()', () => {
expect(subscription).toHaveBeenNthCalledWith(2, 8);
});

test('should decrease configuration at the next interval when a 503 error is emitted', async () => {
const { subscription, errors$ } = setupScenario(10, CLAIM_STRATEGY_MGET);
errors$.next(SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('a', 'b'));
clock.tick(ADJUST_THROUGHPUT_INTERVAL - 1);
expect(subscription).toHaveBeenCalledTimes(1);
expect(subscription).toHaveBeenNthCalledWith(1, 10);
clock.tick(1);
expect(subscription).toHaveBeenCalledTimes(2);
expect(subscription).toHaveBeenNthCalledWith(2, 8);
});

test('should log a warning when the configuration changes from the starting value', async () => {
const { errors$ } = setupScenario(10, CLAIM_STRATEGY_MGET);
errors$.next(SavedObjectsErrorHelpers.createTooManyRequestsError('a', 'b'));
Expand Down Expand Up @@ -305,6 +327,16 @@ describe('createManagedConfiguration()', () => {
expect(subscription).toHaveBeenNthCalledWith(2, 120);
});

test('should increase configuration at the next interval when a 503 error is emitted', async () => {
const { subscription, errors$ } = setupScenario(100);
errors$.next(SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('a', 'b'));
clock.tick(ADJUST_THROUGHPUT_INTERVAL - 1);
expect(subscription).toHaveBeenCalledTimes(1);
clock.tick(1);
expect(subscription).toHaveBeenCalledTimes(2);
expect(subscription).toHaveBeenNthCalledWith(2, 120);
});

test('should log a warning when the configuration changes from the starting value', async () => {
const { errors$ } = setupScenario(100);
errors$.next(SavedObjectsErrorHelpers.createTooManyRequestsError('a', 'b'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ function countErrors(errors$: Observable<Error>, countInterval: number): Observa
interval(countInterval).pipe(map(() => FLUSH_MARKER)),
errors$.pipe(
filter(
(e) => SavedObjectsErrorHelpers.isTooManyRequestsError(e) || isEsCannotExecuteScriptError(e)
(e) =>
SavedObjectsErrorHelpers.isTooManyRequestsError(e) ||
SavedObjectsErrorHelpers.isEsUnavailableError(e) ||
isEsCannotExecuteScriptError(e)
)
)
).pipe(
Expand Down
Loading

0 comments on commit ba8a7a0

Please sign in to comment.