mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Fix Custom Threshold Rule ViewInAppUrl
does not honor space (#201793)
## Summary Close https://github.com/elastic/kibana/issues/201378 Fix https://github.com/elastic/kibana/issues/201333 - [Share] Allow to pass `spaceId` to `getRedirectUrl` to build a URL with a specific `spaceId` - Fix Custom Threshold Rule ViewInAppUrl does not honor Space --------- Co-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>
This commit is contained in:
parent
4511abe03e
commit
f1f3a4fddd
19 changed files with 421 additions and 113 deletions
|
@ -13,8 +13,9 @@ import { KibanaLocation } from '../../../public';
|
|||
import { LocatorGetUrlParams } from '.';
|
||||
import { decompressFromBase64 } from 'lz-string';
|
||||
|
||||
const setup = () => {
|
||||
const baseUrl = 'http://localhost:5601';
|
||||
const setup = (
|
||||
{ baseUrl = 'http://localhost:5601' }: { baseUrl: string } = { baseUrl: 'http://localhost:5601' }
|
||||
) => {
|
||||
const version = '1.2.3';
|
||||
const deps: LocatorDependencies = {
|
||||
baseUrl,
|
||||
|
@ -88,6 +89,48 @@ describe('Locator', () => {
|
|||
baz: 'b',
|
||||
});
|
||||
});
|
||||
|
||||
test('returns URL of the redirect endpoint with custom spaceid', async () => {
|
||||
const { locator } = setup();
|
||||
const url = await locator.getRedirectUrl(
|
||||
{ foo: 'a', baz: 'b' },
|
||||
{ spaceId: 'custom-space-id' }
|
||||
);
|
||||
|
||||
expect(url).toBe(
|
||||
'http://localhost:5601/s/custom-space-id/app/r?l=TEST_LOCATOR&v=1.2.3&lz=N4IgZg9hIFwghiANCARvAXrNIC%2BQ'
|
||||
);
|
||||
});
|
||||
|
||||
test('returns URL of the redirect endpoint with replaced spaceid', async () => {
|
||||
const { locator } = setup({ baseUrl: 'http://localhost:5601/s/space-id' });
|
||||
const url = await locator.getRedirectUrl(
|
||||
{ foo: 'a', baz: 'b' },
|
||||
{ spaceId: 'custom-space-id' }
|
||||
);
|
||||
|
||||
expect(url).toBe(
|
||||
'http://localhost:5601/s/custom-space-id/app/r?l=TEST_LOCATOR&v=1.2.3&lz=N4IgZg9hIFwghiANCARvAXrNIC%2BQ'
|
||||
);
|
||||
});
|
||||
|
||||
test('returns URL of the redirect endpoint without spaceid', async () => {
|
||||
const { locator } = setup({ baseUrl: 'http://localhost:5601/s/space-id' });
|
||||
const url = await locator.getRedirectUrl({ foo: 'a', baz: 'b' }, { spaceId: 'default' });
|
||||
|
||||
expect(url).toBe(
|
||||
'http://localhost:5601/app/r?l=TEST_LOCATOR&v=1.2.3&lz=N4IgZg9hIFwghiANCARvAXrNIC%2BQ'
|
||||
);
|
||||
});
|
||||
|
||||
test('returns URL of the redirect endpoint with untouched spaceId', async () => {
|
||||
const { locator } = setup({ baseUrl: 'http://localhost:5601/s/space-id' });
|
||||
const url = await locator.getRedirectUrl({ foo: 'a', baz: 'b' });
|
||||
|
||||
expect(url).toBe(
|
||||
'http://localhost:5601/s/space-id/app/r?l=TEST_LOCATOR&v=1.2.3&lz=N4IgZg9hIFwghiANCARvAXrNIC%2BQ'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.navigate()', () => {
|
||||
|
|
|
@ -19,7 +19,13 @@ import type {
|
|||
LocatorNavigationParams,
|
||||
LocatorGetUrlParams,
|
||||
} from './types';
|
||||
import { formatSearchParams, FormatSearchParamsOptions, RedirectOptions } from './redirect';
|
||||
import {
|
||||
formatSearchParams,
|
||||
FormatSearchParamsOptions,
|
||||
RedirectOptions,
|
||||
GetRedirectUrlOptions,
|
||||
addSpaceIdToPath,
|
||||
} from './redirect';
|
||||
|
||||
export interface LocatorDependencies {
|
||||
/**
|
||||
|
@ -92,7 +98,7 @@ export class Locator<P extends SerializableRecord> implements LocatorPublic<P> {
|
|||
return url;
|
||||
}
|
||||
|
||||
public getRedirectUrl(params: P, options: FormatSearchParamsOptions = {}): string {
|
||||
public getRedirectUrl(params: P, options: GetRedirectUrlOptions = {}): string {
|
||||
const { baseUrl = '', version = '0.0.0' } = this.deps;
|
||||
const redirectOptions: RedirectOptions = {
|
||||
id: this.definition.id,
|
||||
|
@ -100,12 +106,16 @@ export class Locator<P extends SerializableRecord> implements LocatorPublic<P> {
|
|||
params,
|
||||
};
|
||||
const formatOptions: FormatSearchParamsOptions = {
|
||||
...options,
|
||||
lzCompress: options.lzCompress ?? true,
|
||||
};
|
||||
const search = formatSearchParams(redirectOptions, formatOptions).toString();
|
||||
const path = '/app/r?' + search;
|
||||
|
||||
return baseUrl + '/app/r?' + search;
|
||||
if (options.spaceId) {
|
||||
return addSpaceIdToPath(baseUrl, options.spaceId, path);
|
||||
} else {
|
||||
return baseUrl + path;
|
||||
}
|
||||
}
|
||||
|
||||
public async navigate(
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
export * from './types';
|
||||
export * from './format_search_params';
|
||||
export * from './parse_search_params';
|
||||
export * from './space_url_parser';
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { addSpaceIdToPath } from './space_url_parser';
|
||||
|
||||
describe('addSpaceIdToPath', () => {
|
||||
test('handles no parameters', () => {
|
||||
expect(addSpaceIdToPath()).toEqual(`/`);
|
||||
});
|
||||
|
||||
test('it adds to the basePath correctly', () => {
|
||||
expect(addSpaceIdToPath('/my/base/path', 'url-context')).toEqual('/my/base/path/s/url-context');
|
||||
});
|
||||
|
||||
test('it appends the requested path to the end of the url context', () => {
|
||||
expect(addSpaceIdToPath('/base', 'context', '/final/destination')).toEqual(
|
||||
'/base/s/context/final/destination'
|
||||
);
|
||||
});
|
||||
|
||||
test('it replaces existing space identifiers', () => {
|
||||
expect(addSpaceIdToPath('/my/base/path/s/old-space/', 'new-space')).toEqual(
|
||||
'/my/base/path/s/new-space'
|
||||
);
|
||||
|
||||
expect(addSpaceIdToPath('/my/base/path/s/old-space-no-trailing', 'new-space')).toEqual(
|
||||
'/my/base/path/s/new-space'
|
||||
);
|
||||
});
|
||||
|
||||
test('it removes existing space identifier when spaceId is default', () => {
|
||||
expect(addSpaceIdToPath('/my/base/path/s/old-space', 'default')).toEqual('/my/base/path');
|
||||
expect(addSpaceIdToPath('/my/base/path/s/old-space')).toEqual('/my/base/path');
|
||||
});
|
||||
|
||||
test('it throws an error when the requested path does not start with a slash', () => {
|
||||
expect(() => {
|
||||
addSpaceIdToPath('', '', 'foo');
|
||||
}).toThrowErrorMatchingInlineSnapshot(`"path must start with a /"`);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export function addSpaceIdToPath(
|
||||
basePath: string = '/',
|
||||
spaceId: string = '',
|
||||
requestedPath: string = ''
|
||||
): string {
|
||||
if (requestedPath && !requestedPath.startsWith('/')) {
|
||||
throw new Error(`path must start with a /`);
|
||||
}
|
||||
|
||||
if (basePath.includes('/s/')) {
|
||||
// If the base path already contains a space identifier, remove it
|
||||
basePath = basePath.replace(/\/s\/[^/]+/, '');
|
||||
}
|
||||
|
||||
const normalizedBasePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
||||
|
||||
if (spaceId && spaceId !== 'default') {
|
||||
return `${normalizedBasePath}/s/${spaceId}${requestedPath}`;
|
||||
}
|
||||
|
||||
return `${normalizedBasePath}${requestedPath}` || '/';
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { FormatSearchParamsOptions } from './format_search_params';
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -27,3 +28,13 @@ export interface RedirectOptions<P extends SerializableRecord = unknown & Serial
|
|||
/** Locator params. */
|
||||
params: P;
|
||||
}
|
||||
|
||||
export interface GetRedirectUrlOptions extends FormatSearchParamsOptions {
|
||||
/**
|
||||
* Optional space ID to use when generating the URL.
|
||||
* If not provided:
|
||||
* - on the client the current space ID will be used.
|
||||
* - on the server the URL will be generated without a space ID.
|
||||
*/
|
||||
spaceId?: string;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
PersistableStateService,
|
||||
VersionedState,
|
||||
} from '@kbn/kibana-utils-plugin/common';
|
||||
import type { FormatSearchParamsOptions } from './redirect';
|
||||
import type { GetRedirectUrlOptions } from './redirect';
|
||||
|
||||
/**
|
||||
* URL locator registry.
|
||||
|
@ -88,7 +88,7 @@ export interface LocatorPublic<P extends SerializableRecord> extends Persistable
|
|||
* @param params URL locator parameters.
|
||||
* @param options URL serialization options.
|
||||
*/
|
||||
getRedirectUrl(params: P, options?: FormatSearchParamsOptions): string;
|
||||
getRedirectUrl(params: P, options?: GetRedirectUrlOptions): string;
|
||||
|
||||
/**
|
||||
* Navigate using the `core.application.navigateToApp()` method to a Kibana
|
||||
|
|
|
@ -44,3 +44,7 @@
|
|||
level: custom
|
||||
type: long
|
||||
description: "Number of outgoing bytes"
|
||||
- name: core.system.ticks
|
||||
level: custom
|
||||
type: long
|
||||
description: "The amount of CPU time spent in kernel space"
|
||||
|
|
|
@ -121,6 +121,11 @@ export const generateEvent: GeneratorFunction = (config, schedule, index, timest
|
|||
bytes: generateNetworkData(timestamp.toISOString()),
|
||||
},
|
||||
},
|
||||
core: {
|
||||
system: {
|
||||
ticks: randomBetween(1_000_000, 1_500_100),
|
||||
},
|
||||
},
|
||||
},
|
||||
metricset: {
|
||||
period: interval,
|
||||
|
@ -159,6 +164,11 @@ export const generateEvent: GeneratorFunction = (config, schedule, index, timest
|
|||
bytes: generateNetworkData(timestamp.toISOString()),
|
||||
},
|
||||
},
|
||||
core: {
|
||||
system: {
|
||||
ticks: randomBetween(1_000_000, 1_500_100),
|
||||
},
|
||||
},
|
||||
},
|
||||
metricset: {
|
||||
period: interval,
|
||||
|
|
|
@ -59,15 +59,18 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: args.dataViewId,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter and mockedCountFilter',
|
||||
language: 'kuery',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: args.dataViewId,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter and mockedCountFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with only count filter', () => {
|
||||
|
@ -85,15 +88,18 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedCountFilter',
|
||||
language: 'kuery',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedCountFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with only filter', () => {
|
||||
|
@ -111,15 +117,18 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with empty query if metrics and filter are not not provided', () => {
|
||||
|
@ -130,15 +139,18 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with empty if there are multiple metrics', () => {
|
||||
|
@ -161,15 +173,18 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with filters if group and searchConfiguration filter are provided', () => {
|
||||
|
@ -217,33 +232,67 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
term: {
|
||||
field: {
|
||||
value: 'justTesting',
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
term: {
|
||||
field: {
|
||||
value: 'justTesting',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'host.name': 'host-1',
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'host.name': 'host-1',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with spaceId', () => {
|
||||
const spaceId = 'mockedSpaceId';
|
||||
const args: GetViewInAppUrlArgs = {
|
||||
metrics: [
|
||||
{
|
||||
name: 'A',
|
||||
aggType: Aggregators.COUNT,
|
||||
filter: 'mockedCountFilter',
|
||||
},
|
||||
],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
logsExplorerLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
spaceId,
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedCountFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
{ spaceId }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ export interface GetViewInAppUrlArgs {
|
|||
logsExplorerLocator?: LocatorPublic<LogsExplorerLocatorParams>;
|
||||
metrics?: CustomThresholdExpressionMetric[];
|
||||
startedAt?: string;
|
||||
spaceId?: string;
|
||||
}
|
||||
|
||||
export const getViewInAppUrl = ({
|
||||
|
@ -32,6 +33,7 @@ export const getViewInAppUrl = ({
|
|||
metrics = [],
|
||||
searchConfiguration,
|
||||
startedAt = new Date().toISOString(),
|
||||
spaceId,
|
||||
}: GetViewInAppUrlArgs) => {
|
||||
if (!logsExplorerLocator) return '';
|
||||
|
||||
|
@ -56,10 +58,13 @@ export const getViewInAppUrl = ({
|
|||
query.query = searchConfigurationQuery;
|
||||
}
|
||||
|
||||
return logsExplorerLocator?.getRedirectUrl({
|
||||
dataset,
|
||||
timeRange,
|
||||
query,
|
||||
filters: [...searchConfigurationFilters, ...groupFilters],
|
||||
});
|
||||
return logsExplorerLocator?.getRedirectUrl(
|
||||
{
|
||||
dataset,
|
||||
timeRange,
|
||||
query,
|
||||
filters: [...searchConfigurationFilters, ...groupFilters],
|
||||
},
|
||||
{ spaceId }
|
||||
);
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ const initialRuleState: TestRuleState = {
|
|||
};
|
||||
|
||||
const fakeLogger = <Meta extends LogMeta = LogMeta>(msg: string, meta?: Meta) => {};
|
||||
const MOCKED_SPACE_ID = 'mockedSpaceId';
|
||||
|
||||
const logger = {
|
||||
trace: fakeLogger,
|
||||
|
@ -90,7 +91,7 @@ const mockOptions = {
|
|||
},
|
||||
trackedAlertsRecovered: {},
|
||||
},
|
||||
spaceId: '',
|
||||
spaceId: MOCKED_SPACE_ID,
|
||||
rule: {
|
||||
id: '',
|
||||
name: '',
|
||||
|
@ -1563,7 +1564,7 @@ describe('The custom threshold alert type', () => {
|
|||
expect(services.alertsClient.setAlertData).toBeCalledTimes(1);
|
||||
expect(services.alertsClient.setAlertData).toBeCalledWith({
|
||||
context: {
|
||||
alertDetailsUrl: 'http://localhost:5601/app/observability/alerts/uuid-a',
|
||||
alertDetailsUrl: `http://localhost:5601/s/${MOCKED_SPACE_ID}/app/observability/alerts/uuid-a`,
|
||||
viewInAppUrl: 'mockedViewInApp',
|
||||
group: [
|
||||
{
|
||||
|
@ -1584,6 +1585,7 @@ describe('The custom threshold alert type', () => {
|
|||
});
|
||||
expect(getViewInAppUrl).lastCalledWith({
|
||||
dataViewId: 'c34a7c79-a88b-4b4a-ad19-72f6d24104e4',
|
||||
spaceId: MOCKED_SPACE_ID,
|
||||
groups: [
|
||||
{
|
||||
field: 'host.name',
|
||||
|
@ -1800,7 +1802,7 @@ describe('The custom threshold alert type', () => {
|
|||
await execute(true);
|
||||
const recentAlert = getLastReportedAlert(instanceID);
|
||||
expect(recentAlert?.context).toEqual({
|
||||
alertDetailsUrl: 'http://localhost:5601/app/observability/alerts/uuid-*',
|
||||
alertDetailsUrl: `http://localhost:5601/s/${MOCKED_SPACE_ID}/app/observability/alerts/uuid-*`,
|
||||
reason: 'Average test.metric.3 reported no data in the last 1m',
|
||||
timestamp: STARTED_AT_MOCK_DATE.toISOString(),
|
||||
value: ['[NO DATA]', null],
|
||||
|
@ -3438,6 +3440,7 @@ describe('The custom threshold alert type', () => {
|
|||
const execute = (alertOnNoData: boolean, sourceId: string = 'default') =>
|
||||
executor({
|
||||
...mockOptions,
|
||||
spaceId: '',
|
||||
services,
|
||||
params: {
|
||||
...mockOptions.params,
|
||||
|
|
|
@ -285,6 +285,7 @@ export const createCustomThresholdExecutor = ({
|
|||
metrics: alertResults.length === 1 ? alertResults[0][group].metrics : [],
|
||||
searchConfiguration: params.searchConfiguration,
|
||||
startedAt: indexedStartedAt,
|
||||
spaceId,
|
||||
}),
|
||||
...additionalContext,
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
const dataViewApi = getService('dataViewApi');
|
||||
const logger = getService('log');
|
||||
const config = getService('config');
|
||||
const spacesService = getService('spaces');
|
||||
const isServerless = config.get('serverless');
|
||||
const expectedConsumer = isServerless ? 'observability' : 'logs';
|
||||
let roleAuthc: RoleCredentials;
|
||||
|
@ -39,6 +40,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
const DATA_VIEW_TITLE = 'kbn-data-forge-fake_hosts.fake_hosts-*';
|
||||
const DATA_VIEW_NAME = 'data-view-name';
|
||||
const DATA_VIEW_ID = 'data-view-id';
|
||||
const SPACE_ID = 'test-space';
|
||||
let dataForgeConfig: PartialConfig;
|
||||
let dataForgeIndices: string[];
|
||||
let actionId: string;
|
||||
|
@ -73,8 +75,15 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
name: DATA_VIEW_NAME,
|
||||
id: DATA_VIEW_ID,
|
||||
title: DATA_VIEW_TITLE,
|
||||
spaceId: SPACE_ID,
|
||||
roleAuthc,
|
||||
});
|
||||
await spacesService.create({
|
||||
id: SPACE_ID,
|
||||
name: 'Test Space',
|
||||
disabledFeatures: [],
|
||||
color: '#AABBCC',
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
@ -98,11 +107,13 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
});
|
||||
await dataViewApi.delete({
|
||||
id: DATA_VIEW_ID,
|
||||
spaceId: SPACE_ID,
|
||||
roleAuthc,
|
||||
});
|
||||
await esDeleteAllIndices([ALERT_ACTION_INDEX, ...dataForgeIndices]);
|
||||
await cleanup({ client: esClient, config: dataForgeConfig, logger });
|
||||
await samlAuth.invalidateM2mApiKeyWithRoleScope(roleAuthc);
|
||||
await spacesService.delete(SPACE_ID);
|
||||
});
|
||||
|
||||
describe('Rule creation', () => {
|
||||
|
@ -111,10 +122,12 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
roleAuthc,
|
||||
name: 'Index Connector: Threshold API test',
|
||||
indexName: ALERT_ACTION_INDEX,
|
||||
spaceId: SPACE_ID,
|
||||
});
|
||||
|
||||
const createdRule = await alertingApi.createRule({
|
||||
roleAuthc,
|
||||
spaceId: SPACE_ID,
|
||||
tags: ['observability'],
|
||||
consumer: expectedConsumer,
|
||||
name: 'Threshold rule',
|
||||
|
@ -174,12 +187,13 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
roleAuthc,
|
||||
ruleId,
|
||||
expectedStatus: 'active',
|
||||
spaceId: SPACE_ID,
|
||||
});
|
||||
expect(executionStatus).to.be('active');
|
||||
});
|
||||
|
||||
it('should find the created rule with correct information about the consumer', async () => {
|
||||
const match = await alertingApi.findInRules(roleAuthc, ruleId);
|
||||
const match = await alertingApi.findInRules(roleAuthc, ruleId, SPACE_ID);
|
||||
expect(match).not.to.be(undefined);
|
||||
expect(match.consumer).to.be(expectedConsumer);
|
||||
});
|
||||
|
@ -204,7 +218,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
'observability.rules.custom_threshold'
|
||||
);
|
||||
expect(resp.hits.hits[0]._source).property('kibana.alert.rule.uuid', ruleId);
|
||||
expect(resp.hits.hits[0]._source).property('kibana.space_ids').contain('default');
|
||||
expect(resp.hits.hits[0]._source).property('kibana.space_ids').contain(SPACE_ID);
|
||||
expect(resp.hits.hits[0]._source)
|
||||
.property('kibana.alert.rule.tags')
|
||||
.contain('observability');
|
||||
|
@ -245,7 +259,9 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
const { protocol, hostname, port } = kbnTestConfig.getUrlPartsWithStrippedDefaultPort();
|
||||
expect(resp.hits.hits[0]._source?.ruleType).eql('observability.rules.custom_threshold');
|
||||
expect(resp.hits.hits[0]._source?.alertDetailsUrl).eql(
|
||||
`${protocol}://${hostname}${port ? `:${port}` : ''}/app/observability/alerts/${alertId}`
|
||||
`${protocol}://${hostname}${
|
||||
port ? `:${port}` : ''
|
||||
}/s/${SPACE_ID}/app/observability/alerts/${alertId}`
|
||||
);
|
||||
expect(resp.hits.hits[0]._source?.reason).eql(
|
||||
`Average system.cpu.user.pct is 250%, above the threshold of 50%. (duration: 5 mins, data view: ${DATA_VIEW_NAME})`
|
||||
|
@ -255,6 +271,10 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
const parsedViewInAppUrl = parseSearchParams<LogsExplorerLocatorParsedParams>(
|
||||
new URL(resp.hits.hits[0]._source?.viewInAppUrl || '').search
|
||||
);
|
||||
const viewInAppUrlPathName = new URL(resp.hits.hits[0]._source?.viewInAppUrl || '')
|
||||
.pathname;
|
||||
|
||||
expect(viewInAppUrlPathName).contain(`/s/${SPACE_ID}/app/r`);
|
||||
|
||||
expect(resp.hits.hits[0]._source?.viewInAppUrl).contain('LOGS_EXPLORER_LOCATOR');
|
||||
expect(omit(parsedViewInAppUrl.params, 'timeRange.from')).eql({
|
||||
|
|
|
@ -5,45 +5,44 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { format } from 'url';
|
||||
import { omit } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
import { cleanup, generate, Dataset, PartialConfig } from '@kbn/data-forge';
|
||||
import { COMPARATORS } from '@kbn/alerting-comparators';
|
||||
import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
|
||||
import { FIRED_ACTIONS_ID } from '@kbn/observability-plugin/server/lib/rules/custom_threshold/constants';
|
||||
import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils';
|
||||
import { parseSearchParams } from '@kbn/share-plugin/common/url_service';
|
||||
import { kbnTestConfig } from '@kbn/test';
|
||||
import type { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services';
|
||||
import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';
|
||||
import { getSyntraceClient, generateData } from './helpers/syntrace';
|
||||
import { ActionDocument } from './types';
|
||||
import { ISO_DATE_REGEX } from './constants';
|
||||
import { ActionDocument, LogsExplorerLocatorParsedParams } from './types';
|
||||
|
||||
export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
||||
const start = moment(Date.now()).subtract(10, 'minutes').valueOf();
|
||||
const end = moment(Date.now()).add(15, 'minutes').valueOf();
|
||||
const esClient = getService('es');
|
||||
const samlAuth = getService('samlAuth');
|
||||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
const esDeleteAllIndices = getService('esDeleteAllIndices');
|
||||
const alertingApi = getService('alertingApi');
|
||||
const dataViewApi = getService('dataViewApi');
|
||||
const logger = getService('log');
|
||||
const config = getService('config');
|
||||
const kibanaServerConfig = config.get('servers.kibana');
|
||||
const isServerless = config.get('serverless');
|
||||
const expectedConsumer = isServerless ? 'observability' : 'logs';
|
||||
const kibanaUrl = format(kibanaServerConfig);
|
||||
const spacesService = getService('spaces');
|
||||
let roleAuthc: RoleCredentials;
|
||||
let internalReqHeader: InternalRequestHeader;
|
||||
|
||||
describe('AVG - US - FIRED', () => {
|
||||
describe('AVG - TICKS - FIRED', () => {
|
||||
const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default';
|
||||
const ALERT_ACTION_INDEX = 'alert-action-threshold';
|
||||
const DATA_VIEW = 'traces-apm*,metrics-apm*,logs-apm*';
|
||||
const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*';
|
||||
const DATA_VIEW_ID = 'data-view-id';
|
||||
const DATA_VIEW_NAME = 'test-data-view-name';
|
||||
|
||||
let synthtraceEsClient: ApmSynthtraceEsClient;
|
||||
const SPACE_ID = 'test-space';
|
||||
let dataForgeConfig: PartialConfig;
|
||||
let dataForgeIndices: string[];
|
||||
let actionId: string;
|
||||
let ruleId: string;
|
||||
let alertId: string;
|
||||
|
@ -51,14 +50,47 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
before(async () => {
|
||||
roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin');
|
||||
internalReqHeader = samlAuth.getInternalRequestHeader();
|
||||
synthtraceEsClient = await getSyntraceClient({ esClient, kibanaUrl });
|
||||
await generateData({ synthtraceEsClient, start, end });
|
||||
dataForgeConfig = {
|
||||
schedule: [
|
||||
{
|
||||
template: 'good',
|
||||
start: 'now-10m',
|
||||
end: 'now+5m',
|
||||
metrics: [
|
||||
{
|
||||
name: 'system.core.system.ticks',
|
||||
method: 'linear',
|
||||
start: 10_000_000,
|
||||
end: 10_000_000,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
indexing: {
|
||||
dataset: 'fake_hosts' as Dataset,
|
||||
eventsPerCycle: 1,
|
||||
interval: 10000,
|
||||
alignEventsToInterval: true,
|
||||
},
|
||||
};
|
||||
dataForgeIndices = await generate({ client: esClient, config: dataForgeConfig, logger });
|
||||
await alertingApi.waitForDocumentInIndex({
|
||||
indexName: dataForgeIndices.join(','),
|
||||
docCountTarget: 270,
|
||||
});
|
||||
await dataViewApi.create({
|
||||
name: DATA_VIEW_NAME,
|
||||
id: DATA_VIEW_ID,
|
||||
title: DATA_VIEW,
|
||||
spaceId: SPACE_ID,
|
||||
roleAuthc,
|
||||
});
|
||||
await spacesService.create({
|
||||
id: SPACE_ID,
|
||||
name: 'Test Space',
|
||||
disabledFeatures: [],
|
||||
color: '#AABBCC',
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
@ -70,7 +102,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
.delete(`/api/actions/connector/${actionId}`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(internalReqHeader);
|
||||
await esDeleteAllIndices([ALERT_ACTION_INDEX]);
|
||||
await esDeleteAllIndices([ALERT_ACTION_INDEX, ...dataForgeIndices]);
|
||||
await esClient.deleteByQuery({
|
||||
index: CUSTOM_THRESHOLD_RULE_ALERT_INDEX,
|
||||
query: { term: { 'kibana.alert.rule.uuid': ruleId } },
|
||||
|
@ -79,11 +111,13 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
index: '.kibana-event-log-*',
|
||||
query: { term: { 'kibana.alert.rule.consumer': expectedConsumer } },
|
||||
});
|
||||
await synthtraceEsClient.clean();
|
||||
await dataViewApi.delete({
|
||||
id: DATA_VIEW_ID,
|
||||
spaceId: SPACE_ID,
|
||||
roleAuthc,
|
||||
});
|
||||
await cleanup({ client: esClient, config: dataForgeConfig, logger });
|
||||
await spacesService.delete(SPACE_ID);
|
||||
await samlAuth.invalidateM2mApiKeyWithRoleScope(roleAuthc);
|
||||
});
|
||||
|
||||
|
@ -93,10 +127,12 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
roleAuthc,
|
||||
name: 'Index Connector: Threshold API test',
|
||||
indexName: ALERT_ACTION_INDEX,
|
||||
spaceId: SPACE_ID,
|
||||
});
|
||||
|
||||
const createdRule = await alertingApi.createRule({
|
||||
roleAuthc,
|
||||
spaceId: SPACE_ID,
|
||||
tags: ['observability'],
|
||||
consumer: expectedConsumer,
|
||||
name: 'Threshold rule',
|
||||
|
@ -109,7 +145,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
timeSize: 5,
|
||||
timeUnit: 'm',
|
||||
metrics: [
|
||||
{ name: 'A', field: 'span.self_time.sum.us', aggType: Aggregators.AVERAGE },
|
||||
{ name: 'A', field: 'system.core.system.ticks', aggType: Aggregators.AVERAGE },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -134,6 +170,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
alertDetailsUrl: '{{context.alertDetailsUrl}}',
|
||||
reason: '{{context.reason}}',
|
||||
value: '{{context.value}}',
|
||||
viewInAppUrl: '{{context.viewInAppUrl}}',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -154,6 +191,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
roleAuthc,
|
||||
ruleId,
|
||||
expectedStatus: 'active',
|
||||
spaceId: SPACE_ID,
|
||||
});
|
||||
expect(executionStatus).to.be('active');
|
||||
});
|
||||
|
@ -178,7 +216,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
'observability.rules.custom_threshold'
|
||||
);
|
||||
expect(resp.hits.hits[0]._source).property('kibana.alert.rule.uuid', ruleId);
|
||||
expect(resp.hits.hits[0]._source).property('kibana.space_ids').contain('default');
|
||||
expect(resp.hits.hits[0]._source).property('kibana.space_ids').contain(SPACE_ID);
|
||||
expect(resp.hits.hits[0]._source)
|
||||
.property('kibana.alert.rule.tags')
|
||||
.contain('observability');
|
||||
|
@ -203,7 +241,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
threshold: [7500000],
|
||||
timeSize: 5,
|
||||
timeUnit: 'm',
|
||||
metrics: [{ name: 'A', field: 'span.self_time.sum.us', aggType: 'avg' }],
|
||||
metrics: [{ name: 'A', field: 'system.core.system.ticks', aggType: 'avg' }],
|
||||
},
|
||||
],
|
||||
alertOnNoData: true,
|
||||
|
@ -220,12 +258,30 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
|
|||
const { protocol, hostname, port } = kbnTestConfig.getUrlPartsWithStrippedDefaultPort();
|
||||
expect(resp.hits.hits[0]._source?.ruleType).eql('observability.rules.custom_threshold');
|
||||
expect(resp.hits.hits[0]._source?.alertDetailsUrl).eql(
|
||||
`${protocol}://${hostname}${port ? `:${port}` : ''}/app/observability/alerts/${alertId}`
|
||||
`${protocol}://${hostname}${
|
||||
port ? `:${port}` : ''
|
||||
}/s/${SPACE_ID}/app/observability/alerts/${alertId}`
|
||||
);
|
||||
expect(resp.hits.hits[0]._source?.reason).eql(
|
||||
`Average span.self_time.sum.us is 10,000,000, above the threshold of 7,500,000. (duration: 5 mins, data view: ${DATA_VIEW_NAME})`
|
||||
`Average system.core.system.ticks is 10,000,000, above the threshold of 7,500,000. (duration: 5 mins, data view: ${DATA_VIEW_NAME})`
|
||||
);
|
||||
expect(resp.hits.hits[0]._source?.value).eql('10,000,000');
|
||||
|
||||
const parsedViewInAppUrl = parseSearchParams<LogsExplorerLocatorParsedParams>(
|
||||
new URL(resp.hits.hits[0]._source?.viewInAppUrl || '').search
|
||||
);
|
||||
const viewInAppUrlPathName = new URL(resp.hits.hits[0]._source?.viewInAppUrl || '')
|
||||
.pathname;
|
||||
|
||||
expect(viewInAppUrlPathName).contain(`/s/${SPACE_ID}/app/r`);
|
||||
expect(resp.hits.hits[0]._source?.viewInAppUrl).contain('LOGS_EXPLORER_LOCATOR');
|
||||
expect(omit(parsedViewInAppUrl.params, 'timeRange.from')).eql({
|
||||
dataset: DATA_VIEW_ID,
|
||||
timeRange: { to: 'now' },
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
});
|
||||
expect(parsedViewInAppUrl.params.timeRange.from).match(ISO_DATE_REGEX);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -11,7 +11,7 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext)
|
|||
describe('Custom Threshold rule', () => {
|
||||
loadTestFile(require.resolve('./avg_pct_fired'));
|
||||
loadTestFile(require.resolve('./avg_pct_no_data'));
|
||||
loadTestFile(require.resolve('./avg_us_fired'));
|
||||
loadTestFile(require.resolve('./avg_ticks_fired'));
|
||||
loadTestFile(require.resolve('./custom_eq_avg_bytes_fired'));
|
||||
loadTestFile(require.resolve('./documents_count_fired'));
|
||||
loadTestFile(require.resolve('./group_by_fired'));
|
||||
|
|
|
@ -942,14 +942,16 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
ruleId,
|
||||
expectedStatus,
|
||||
roleAuthc,
|
||||
spaceId,
|
||||
}: {
|
||||
ruleId: string;
|
||||
expectedStatus: string;
|
||||
roleAuthc: RoleCredentials;
|
||||
spaceId?: string;
|
||||
}) {
|
||||
return await retry.tryForTime(retryTimeout, async () => {
|
||||
const response = await supertestWithoutAuth
|
||||
.get(`/api/alerting/rule/${ruleId}`)
|
||||
.get(`${spaceId ? '/s/' + spaceId : ''}/api/alerting/rule/${ruleId}`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader())
|
||||
.timeout(requestTimeout);
|
||||
|
@ -1034,13 +1036,15 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
name,
|
||||
indexName,
|
||||
roleAuthc,
|
||||
spaceId,
|
||||
}: {
|
||||
name: string;
|
||||
indexName: string;
|
||||
roleAuthc: RoleCredentials;
|
||||
spaceId?: string;
|
||||
}) {
|
||||
const { body } = await supertestWithoutAuth
|
||||
.post(`/api/actions/connector`)
|
||||
.post(`${spaceId ? '/s/' + spaceId : ''}/api/actions/connector`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader())
|
||||
.send({
|
||||
|
@ -1063,6 +1067,7 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
schedule,
|
||||
consumer,
|
||||
roleAuthc,
|
||||
spaceId,
|
||||
}: {
|
||||
ruleTypeId: string;
|
||||
name: string;
|
||||
|
@ -1080,9 +1085,10 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
schedule?: { interval: string };
|
||||
consumer: string;
|
||||
roleAuthc: RoleCredentials;
|
||||
spaceId?: string;
|
||||
}) {
|
||||
const { body } = await supertestWithoutAuth
|
||||
.post(`/api/alerting/rule`)
|
||||
.post(`${spaceId ? '/s/' + spaceId : ''}/api/alerting/rule`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader())
|
||||
.send({
|
||||
|
@ -1118,17 +1124,17 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
});
|
||||
},
|
||||
|
||||
async findInRules(roleAuthc: RoleCredentials, ruleId: string) {
|
||||
async findInRules(roleAuthc: RoleCredentials, ruleId: string, spaceId?: string) {
|
||||
const response = await supertestWithoutAuth
|
||||
.get('/api/alerting/rules/_find')
|
||||
.get(`${spaceId ? '/s/' + spaceId : ''}/api/alerting/rules/_find`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader());
|
||||
return response.body.data.find((obj: any) => obj.id === ruleId);
|
||||
},
|
||||
|
||||
async searchRules(roleAuthc: RoleCredentials, filter: string) {
|
||||
async searchRules(roleAuthc: RoleCredentials, filter: string, spaceId?: string) {
|
||||
return supertestWithoutAuth
|
||||
.get('/api/alerting/rules/_find')
|
||||
.get(`${spaceId ? '/s/' + spaceId : ''}/api/alerting/rules/_find`)
|
||||
.query({ filter })
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader());
|
||||
|
|
|
@ -18,14 +18,16 @@ export function DataViewApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
id,
|
||||
name,
|
||||
title,
|
||||
spaceId,
|
||||
}: {
|
||||
roleAuthc: RoleCredentials;
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
spaceId?: string;
|
||||
}) {
|
||||
const { body } = await supertestWithoutAuth
|
||||
.post(`/api/content_management/rpc/create`)
|
||||
.post(`${spaceId ? '/s/' + spaceId : ''}/api/content_management/rpc/create`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader())
|
||||
.set(samlAuth.getCommonRequestHeader())
|
||||
|
@ -48,9 +50,17 @@ export function DataViewApiProvider({ getService }: DeploymentAgnosticFtrProvide
|
|||
return body;
|
||||
},
|
||||
|
||||
async delete({ roleAuthc, id }: { roleAuthc: RoleCredentials; id: string }) {
|
||||
async delete({
|
||||
roleAuthc,
|
||||
id,
|
||||
spaceId,
|
||||
}: {
|
||||
roleAuthc: RoleCredentials;
|
||||
id: string;
|
||||
spaceId?: string;
|
||||
}) {
|
||||
const { body } = await supertestWithoutAuth
|
||||
.post(`/api/content_management/rpc/delete`)
|
||||
.post(`${spaceId ? '/s/' + spaceId : ''}/api/content_management/rpc/delete`)
|
||||
.set(roleAuthc.apiKeyHeader)
|
||||
.set(samlAuth.getInternalRequestHeader())
|
||||
.set(samlAuth.getCommonRequestHeader())
|
||||
|
|
|
@ -26,4 +26,5 @@ export const deploymentAgnosticServices = _.pick(apiIntegrationServices, [
|
|||
'retry',
|
||||
'security',
|
||||
'usageAPI',
|
||||
'spaces',
|
||||
]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue