Skip to content

Commit

Permalink
Merge branch 'main' into 179399_inactive_unenrollment_timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Aug 19, 2024
2 parents ca81433 + 1f1a359 commit 2de2dc9
Show file tree
Hide file tree
Showing 74 changed files with 1,113 additions and 393 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@
"deepmerge": "^4.2.2",
"del": "^6.1.0",
"diff": "^5.1.0",
"elastic-apm-node": "^4.7.2",
"elastic-apm-node": "^4.7.3",
"email-addresses": "^5.0.0",
"eventsource-parser": "^1.1.1",
"execa": "^5.1.1",
Expand Down
33 changes: 18 additions & 15 deletions x-pack/plugins/integration_assistant/server/util/samples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,25 @@ function isEmptyValue(value: unknown): boolean {

function merge(target: Record<string, any>, source: Record<string, any>): Record<string, unknown> {
for (const [key, sourceValue] of Object.entries(source)) {
const targetValue = target[key];
if (Array.isArray(sourceValue)) {
// Directly assign arrays
target[key] = sourceValue;
} else if (
typeof sourceValue === 'object' &&
sourceValue !== null &&
!Array.isArray(targetValue)
) {
if (typeof targetValue !== 'object' || isEmptyValue(targetValue)) {
target[key] = merge({}, sourceValue);
} else {
target[key] = merge(targetValue, sourceValue);
if (key !== '__proto__' && key !== 'constructor') {
if (Object.prototype.hasOwnProperty.call(target, key)) {
const targetValue = target[key];
if (Array.isArray(sourceValue)) {
target[key] = sourceValue;
} else if (
typeof sourceValue === 'object' &&
sourceValue !== null &&
typeof targetValue === 'object' &&
targetValue !== null &&
!Array.isArray(targetValue)
) {
target[key] = merge(targetValue, sourceValue);
} else if (isEmptyValue(targetValue) && !isEmptyValue(sourceValue)) {
target[key] = sourceValue;
}
} else if (!isEmptyValue(sourceValue)) {
target[key] = sourceValue;
}
} else if (!(key in target) || (isEmptyValue(targetValue) && !isEmptyValue(sourceValue))) {
target[key] = sourceValue;
}
}
return target;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,43 @@

import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common/parse_technical_fields';
import { ALERT_RULE_PARAMETERS, TIMESTAMP } from '@kbn/rule-data-utils';
import rison from '@kbn/rison';
import {
getInventoryViewInAppUrl,
flatAlertRuleParams,
getMetricsViewInAppUrl,
} from './alert_link';
import {
InventoryLocator,
AssetDetailsLocator,
InventoryLocatorParams,
AssetDetailsLocatorParams,
} from '@kbn/observability-shared-plugin/common';

jest.mock('@kbn/observability-shared-plugin/common');

const mockInventoryLocator = {
getRedirectUrl: jest
.fn()
.mockImplementation(
(params: InventoryLocatorParams) =>
`/inventory-mock?receivedParams=${rison.encodeUnknown(params)}`
),
} as unknown as jest.Mocked<InventoryLocator>;

const mockAssetDetailsLocator = {
getRedirectUrl: jest
.fn()
.mockImplementation(
({ assetId, assetType, assetDetails }: AssetDetailsLocatorParams) =>
`/node-mock/${assetType}/${assetId}?receivedParams=${rison.encodeUnknown(assetDetails)}`
),
} as unknown as jest.Mocked<AssetDetailsLocator>;

describe('Inventory Threshold Rule', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('flatAlertRuleParams', () => {
it('flat ALERT_RULE_PARAMETERS', () => {
expect(
Expand Down Expand Up @@ -85,9 +115,14 @@ describe('Inventory Threshold Rule', () => {
[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.aggregation`]: ['avg'],
[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.field`]: ['system.cpu.user.pct'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl(fields);
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockInventoryLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/inventory?customMetric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&metric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&nodeType=h&timestamp=1640995200000'
"/inventory-mock?receivedParams=(customMetric:'(aggregation:avg,field:system.cpu.user.pct,id:alert-custom-metric,type:custom)',metric:'(aggregation:avg,field:system.cpu.user.pct,id:alert-custom-metric,type:custom)',nodeType:host,timestamp:1640995200000)"
);
});
it('should work with non-custom metrics', () => {
Expand All @@ -96,22 +131,50 @@ describe('Inventory Threshold Rule', () => {
[`${ALERT_RULE_PARAMETERS}.nodeType`]: 'host',
[`${ALERT_RULE_PARAMETERS}.criteria.metric`]: ['cpu'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl(fields);
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockInventoryLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/inventory?customMetric=&metric=%28type%3Acpu%29&nodeType=h&timestamp=1640995200000'
"/inventory-mock?receivedParams=(customMetric:'',metric:'(type:cpu)',nodeType:host,timestamp:1640995200000)"
);
});

it('should point to host-details when host.name is present', () => {
it('should point to asset details when nodeType is host and host.name is present', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
[`${ALERT_RULE_PARAMETERS}.nodeType`]: 'kubernetes',
[`${ALERT_RULE_PARAMETERS}.nodeType`]: 'host',
[`${ALERT_RULE_PARAMETERS}.criteria.metric`]: ['cpu'],
[`host.name`]: ['my-host'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl(fields);
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockAssetDetailsLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/host-detail/my-host?from=1640995200000&to=1640996100000'
"/node-mock/host/my-host?receivedParams=(alertMetric:cpu,dateRange:(from:'2022-01-01T00:00:00.000Z',to:'2022-01-01T00:15:00.000Z'))"
);
});

it('should point to asset details when nodeType is container and container.id is present', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
[`${ALERT_RULE_PARAMETERS}.nodeType`]: 'container',
[`${ALERT_RULE_PARAMETERS}.criteria.metric`]: ['cpu'],
[`container.id`]: ['my-container'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockAssetDetailsLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
"/node-mock/container/my-container?receivedParams=(alertMetric:cpu,dateRange:(from:'2022-01-01T00:00:00.000Z',to:'2022-01-01T00:15:00.000Z'))"
);
});

Expand Down Expand Up @@ -140,9 +203,14 @@ describe('Inventory Threshold Rule', () => {
_id: 'eaa439aa-a4bb-4e7c-b7f8-fbe532ca7366',
_index: '.internal.alerts-observability.metrics.alerts-default-000001',
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl(fields);
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockInventoryLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/inventory?customMetric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&metric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&nodeType=host&timestamp=1640995200000'
"/inventory-mock?receivedParams=(customMetric:'(aggregation:avg,field:system.cpu.user.pct,id:alert-custom-metric,type:custom)',metric:'(aggregation:avg,field:system.cpu.user.pct,id:alert-custom-metric,type:custom)',nodeType:host,timestamp:1640995200000)"
);
});

Expand All @@ -165,32 +233,75 @@ describe('Inventory Threshold Rule', () => {
_id: 'eaa439aa-a4bb-4e7c-b7f8-fbe532ca7366',
_index: '.internal.alerts-observability.metrics.alerts-default-000001',
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getInventoryViewInAppUrl(fields);
const url = getInventoryViewInAppUrl({
fields,
inventoryLocator: mockInventoryLocator,
assetDetailsLocator: mockAssetDetailsLocator,
});
expect(mockInventoryLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/inventory?customMetric=&metric=%28type%3Acpu%29&nodeType=host&timestamp=1640995200000'
"/inventory-mock?receivedParams=(customMetric:'',metric:'(type:cpu)',nodeType:host,timestamp:1640995200000)"
);
});
});
});

describe('Metrics Rule', () => {
afterEach(() => {
jest.clearAllMocks();
});

describe('getMetricsViewInAppUrl', () => {
it('should point to host-details when host.name is present', () => {
it('should point to host details when host.name is present', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
[`host.name`]: ['my-host'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getMetricsViewInAppUrl(fields);
const url = getMetricsViewInAppUrl({
fields,
assetDetailsLocator: mockAssetDetailsLocator,
groupBy: ['host.name'],
});
expect(mockAssetDetailsLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
"/node-mock/host/my-host?receivedParams=(dateRange:(from:'2022-01-01T00:00:00.000Z',to:'2022-01-01T00:15:00.000Z'))"
);
});

it('should point to container details when host.name is present', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
[`container.id`]: ['my-host-5xyz'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getMetricsViewInAppUrl({
fields,
assetDetailsLocator: mockAssetDetailsLocator,
groupBy: ['container.id'],
});
expect(mockAssetDetailsLocator.getRedirectUrl).toHaveBeenCalledTimes(1);
expect(url).toEqual(
'/app/metrics/link-to/host-detail/my-host?from=1640995200000&to=1640996100000'
"/node-mock/container/my-host-5xyz?receivedParams=(dateRange:(from:'2022-01-01T00:00:00.000Z',to:'2022-01-01T00:15:00.000Z'))"
);
});

it('should point to metrics when group by field is not supported by the asset details', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
[`host.name`]: ['my-host'],
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getMetricsViewInAppUrl({
fields,
assetDetailsLocator: mockAssetDetailsLocator,
groupBy: ['kubernetes.pod.name'],
});
expect(url).toEqual('/app/metrics/explorer');
});

it('should point to metrics explorer', () => {
const fields = {
[TIMESTAMP]: '2022-01-01T00:00:00.000Z',
} as unknown as ParsedTechnicalFields & Record<string, any>;
const url = getMetricsViewInAppUrl(fields);
const url = getMetricsViewInAppUrl({ fields });
expect(url).toEqual('/app/metrics/explorer');
});
});
Expand Down
Loading

0 comments on commit 2de2dc9

Please sign in to comment.