Skip to content

Commit

Permalink
Merge branch 'main' into fix-rewrite-agent-targeting
Browse files Browse the repository at this point in the history
  • Loading branch information
delanni committed Mar 12, 2024
2 parents d838f7c + ddc82a2 commit 06b611c
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* 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 { synthtrace } from '../../../synthtrace';
import { generateData } from './generate_data';

function deleteAllRules() {
cy.log('Delete all rules');
cy.request({
log: false,
method: 'GET',
url: '/api/alerting/rules/_find',
auth: { user: 'editor', pass: 'changeme' },
}).then(({ body }) => {
if (body.data.length > 0) {
cy.log(`Deleting rules`);
}

body.data.map(({ id }: { id: string }) => {
cy.request({
headers: { 'kbn-xsrf': 'true' },
log: false,
method: 'DELETE',
url: `/api/alerting/rule/${id}`,
auth: { user: 'editor', pass: 'changeme' },
});
});
});
}

describe('Alerts', () => {
beforeEach(() => {
deleteAllRules();
});

after(() => {
deleteAllRules();
});

before(() => {
const start = Date.now() - 1000 * 60 * 10;
const end = Date.now() + 1000 * 60 * 5;

synthtrace.index(
generateData({
from: new Date(start).getTime(),
to: new Date(end).getTime(),
})
);
});

after(() => {
synthtrace.clean();
});

describe('when rendered from Service view in APM app', () => {
const ruleName = 'Error count threshold';
const confirmModalButtonSelector =
'.euiModal button[data-test-subj=confirmModalConfirmButton]';

it('alerts table is rendered correctly', () => {
cy.loginAsEditorUser();

// Create a rule in APM
cy.visitKibana('/app/apm/services');
cy.contains('Alerts and rules').click();
cy.contains('Create error count rule').click();

// Check for the existence of these elements to make sure the form
// has loaded.
cy.contains('for the last');
cy.contains('Actions');
cy.contains('Save').should('not.be.disabled');

// Update "Is above" to "0"
cy.contains('is above').click();
cy.getByTestSubj('apmIsAboveFieldFieldNumber').clear();
cy.contains('is above 0 errors');

// Save, with no actions
cy.contains('Save').click();
cy.get(confirmModalButtonSelector).click();

cy.contains(`Created rule "${ruleName}`);

// Check that the "Alerts" table is loaded
cy.wait(2000);
cy.visitKibana('/app/apm/services/opbeans-java/alerts');
cy.getByTestSubj('o11yGetRenderCellValueLink')
.first()
.click({ force: true });
cy.getByTestSubj('alertsFlyout').should('exist');
cy.contains('Overview');
cy.contains('Status');
cy.contains('Active');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 { apm, timerange } from '@kbn/apm-synthtrace-client';

export function generateData({ from, to }: { from: number; to: number }) {
const range = timerange(from, to);

const opbeansJava = apm
.service({
name: 'opbeans-java',
environment: 'production',
agentName: 'java',
})
.instance('opbeans-java-prod-1')
.podId('opbeans-java-prod-1-pod');

const opbeansNode = apm
.service({
name: 'opbeans-node',
environment: 'production',
agentName: 'nodejs',
})
.instance('opbeans-node-prod-1');

return range
.interval('2m')
.rate(1)
.generator((timestamp, index) => [
opbeansJava
.transaction({ transactionName: 'GET /apple 🍎 ' })
.timestamp(timestamp)
.duration(1000)
.success()
.errors(
opbeansJava
.error({ message: `Error ${index}`, type: `exception ${index}` })
.timestamp(timestamp)
),
opbeansNode
.transaction({ transactionName: 'GET /banana 🍌' })
.timestamp(timestamp)
.duration(500)
.success(),
]);
}
3 changes: 2 additions & 1 deletion x-pack/plugins/observability_solution/apm/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"usageCollection",
"customIntegrations", // Move this to requiredPlugins after completely migrating from the Tutorials Home App
"licenseManagement",
"profilingDataAccess"
"profilingDataAccess",
"cases"
],
"requiredBundles": [
"fleet",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { cloneDeep } from 'lodash';
import React, { memo, useMemo, useCallback, useState, useEffect } from 'react';
import deepEqual from 'fast-deep-equal';

Expand Down Expand Up @@ -63,7 +64,6 @@ export const QueryBar = memo<QueryBarComponentProps>(
}) => {
const { data } = useKibana().services;
const [dataView, setDataView] = useState<DataView>();
const [searchBarFilters, setSearchBarFilters] = useState<Filter[]>(filters);
const onQuerySubmit = useCallback(
(payload: { dateRange: TimeRange; query?: Query | AggregateQuery }) => {
if (payload.query != null && !deepEqual(payload.query, filterQuery)) {
Expand Down Expand Up @@ -129,14 +129,6 @@ export const QueryBar = memo<QueryBarComponentProps>(
const createDataView = async () => {
dv = await data.dataViews.create({ id: indexPattern.title, title: indexPattern.title });
setDataView(dv);

/**
* We update filters and set new data view id to make sure that SearchBar does not show data view picker
* More details in https://github.com/elastic/kibana/issues/174026
*/
const updatedFilters = [...filters];
updatedFilters.forEach((filter) => (filter.meta.index = indexPattern.title));
setSearchBarFilters(updatedFilters);
};
createDataView();
}
Expand All @@ -145,7 +137,21 @@ export const QueryBar = memo<QueryBarComponentProps>(
data.dataViews.clearInstanceCache(dv?.id);
}
};
}, [data.dataViews, filters, indexPattern, isEsql]);
}, [data.dataViews, indexPattern, isEsql]);

const searchBarFilters = useMemo(() => {
if (isDataView(indexPattern) || isEsql) {
return filters;
}

/**
* We update filters and set new data view id to make sure that SearchBar does not show data view picker
* More details in https://github.com/elastic/kibana/issues/174026
*/
const updatedFilters = cloneDeep(filters);
updatedFilters.forEach((filter) => (filter.meta.index = indexPattern.title));
return updatedFilters;
}, [filters, indexPattern, isEsql]);

const timeHistory = useMemo(() => new TimeHistory(new Storage(localStorage)), []);
const arrDataView = useMemo(() => (dataView != null ? [dataView] : []), [dataView]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@

import { getNewRule } from '../../../../objects/rule';
import { RULE_NAME_HEADER } from '../../../../screens/rule_details';
import { GLOBAL_SEARCH_BAR_FILTER_ITEM } from '../../../../screens/search_bar';

import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common';
import {
fillScheduleRuleAndContinue,
fillAboutRuleMinimumAndContinue,
fillDefineCustomRuleAndContinue,
createRuleWithoutEnabling,
fillDefineCustomRule,
openAddFilterPopover,
} from '../../../../tasks/create_new_rule';
import { login } from '../../../../tasks/login';
import { visit } from '../../../../tasks/navigation';
import { fillAddFilterForm } from '../../../../tasks/search_bar';
import { CREATE_RULE_URL } from '../../../../urls/navigation';

describe('Create custom query rule', { tags: ['@ess', '@serverless'] }, () => {
Expand All @@ -42,5 +46,17 @@ describe('Create custom query rule', { tags: ['@ess', '@serverless'] }, () => {
cy.log('Asserting we have a new rule created');
cy.get(RULE_NAME_HEADER).should('contain', rule.name);
});

it('Adds filter on define step', () => {
visit(CREATE_RULE_URL);
fillDefineCustomRule(rule);
openAddFilterPopover();
fillAddFilterForm({
key: 'host.name',
operator: 'exists',
});
// Check that newly added filter exists
cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should('have.text', 'host.name: exists');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
DATA_VIEW_DETAILS,
EDIT_RULE_SETTINGS_LINK,
} from '../../../../screens/rule_details';
import { GLOBAL_SEARCH_BAR_FILTER_ITEM } from '../../../../screens/search_bar';

import {
getRulesManagementTableRows,
Expand All @@ -61,15 +62,18 @@ import {
createAndEnableRule,
createRuleWithoutEnabling,
fillAboutRuleAndContinue,
fillDefineCustomRule,
fillDefineCustomRuleAndContinue,
fillScheduleRuleAndContinue,
openAddFilterPopover,
waitForAlertsToPopulate,
} from '../../../../tasks/create_new_rule';

import { login } from '../../../../tasks/login';
import { visit } from '../../../../tasks/navigation';
import { openRuleManagementPageViaBreadcrumbs } from '../../../../tasks/rules_management';
import { getDetails, waitForTheRuleToBeExecuted } from '../../../../tasks/rule_details';
import { fillAddFilterForm } from '../../../../tasks/search_bar';

import { CREATE_RULE_URL } from '../../../../urls/navigation';

Expand Down Expand Up @@ -176,5 +180,17 @@ describe('Custom query rules', { tags: ['@ess', '@serverless'] }, () => {

cy.get(RULE_NAME_HEADER).should('contain', 'Edit rule settings');
});

it('Adds filter on define step', () => {
visit(CREATE_RULE_URL);
fillDefineCustomRule(rule);
openAddFilterPopover();
fillAddFilterForm({
key: 'host.name',
operator: 'exists',
});
// Check that newly added filter exists
cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should('have.text', 'host.name: exists');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export const CUSTOM_QUERY_INPUT = '[data-test-subj="queryInput"]';

export const CUSTOM_QUERY_BAR = '[data-test-subj="detectionEngineStepDefineRuleQueryBar"]';

export const QUERY_BAR_ADD_FILTER =
'[data-test-subj="detectionEngineStepDefineRuleQueryBar"] [data-test-subj="addFilter"]';

export const THREAT_MAPPING_COMBO_BOX_INPUT =
'[data-test-subj="threatMatchInput"] [data-test-subj="fieldAutocompleteComboBox"]';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ import {
RULE_INDICES,
ALERTS_INDEX_BUTTON,
INVESTIGATIONS_INPUT,
QUERY_BAR_ADD_FILTER,
} from '../screens/create_new_rule';
import {
INDEX_SELECTOR,
Expand Down Expand Up @@ -408,14 +409,18 @@ export const removeAlertsIndex = () => {
});
};

export const fillDefineCustomRuleAndContinue = (rule: QueryRuleCreateProps) => {
export const fillDefineCustomRule = (rule: QueryRuleCreateProps) => {
if (rule.data_view_id !== undefined) {
cy.get(DATA_VIEW_OPTION).click();
cy.get(DATA_VIEW_COMBO_BOX).type(`${rule.data_view_id}{enter}`);
}
cy.get(CUSTOM_QUERY_INPUT)
.first()
.type(rule.query || '');
};

export const fillDefineCustomRuleAndContinue = (rule: QueryRuleCreateProps) => {
fillDefineCustomRule(rule);
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
};

Expand Down Expand Up @@ -878,3 +883,7 @@ export const uncheckLoadQueryDynamically = () => {
cy.get(LOAD_QUERY_DYNAMICALLY_CHECKBOX).click({ force: true });
cy.get(LOAD_QUERY_DYNAMICALLY_CHECKBOX).should('not.be.checked');
};

export const openAddFilterPopover = () => {
cy.get(QUERY_BAR_ADD_FILTER).click();
};

0 comments on commit 06b611c

Please sign in to comment.