mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.6] [ML] Explain Log Rate Spikes: Additional functional tests with artificial logs dataset (#145763) (#146038)
# Backport This will backport the following commits from `main` to `8.6`: - [[ML] Explain Log Rate Spikes: Additional functional tests with artificial logs dataset (#145763)](https://github.com/elastic/kibana/pull/145763) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Walter Rafelsberger","email":"walter.rafelsberger@elastic.co"},"sourceCommit":{"committedDate":"2022-11-22T17:28:54Z","message":"[ML] Explain Log Rate Spikes: Additional functional tests with artificial logs dataset (#145763)\n\nAdditional functional tests with artificial logs dataset.\r\n\r\nThis generates an artificial logs dataset with the purpose of asserting\r\nthe case where grouping needs to identify 2 non-overlapping groups. The\r\nprimary use case of the test is to track possible regressions related to\r\nwhen trying to improve `frequent_items` aggregation settings and the\r\ncustom grouping code.","sha":"c45f55660584381d385e11817d4285e3e24eb546","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":[":ml","release_note:skip","Feature:ML/AIOps","v8.6.0","v8.7.0"],"number":145763,"url":"https://github.com/elastic/kibana/pull/145763","mergeCommit":{"message":"[ML] Explain Log Rate Spikes: Additional functional tests with artificial logs dataset (#145763)\n\nAdditional functional tests with artificial logs dataset.\r\n\r\nThis generates an artificial logs dataset with the purpose of asserting\r\nthe case where grouping needs to identify 2 non-overlapping groups. The\r\nprimary use case of the test is to track possible regressions related to\r\nwhen trying to improve `frequent_items` aggregation settings and the\r\ncustom grouping code.","sha":"c45f55660584381d385e11817d4285e3e24eb546"}},"sourceBranch":"main","suggestedTargetBranches":["8.6"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/145763","number":145763,"mergeCommit":{"message":"[ML] Explain Log Rate Spikes: Additional functional tests with artificial logs dataset (#145763)\n\nAdditional functional tests with artificial logs dataset.\r\n\r\nThis generates an artificial logs dataset with the purpose of asserting\r\nthe case where grouping needs to identify 2 non-overlapping groups. The\r\nprimary use case of the test is to track possible regressions related to\r\nwhen trying to improve `frequent_items` aggregation settings and the\r\ncustom grouping code.","sha":"c45f55660584381d385e11817d4285e3e24eb546"}}]}] BACKPORT--> Co-authored-by: Walter Rafelsberger <walter.rafelsberger@elastic.co>
This commit is contained in:
parent
2a14c23678
commit
010bb24b87
7 changed files with 405 additions and 37 deletions
|
@ -8,7 +8,7 @@
|
|||
import expect from '@kbn/expect';
|
||||
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import type { TestData } from './types';
|
||||
import type { TestDataEsArchive } from './types';
|
||||
import { farequoteDataViewTestData } from './test_data';
|
||||
|
||||
const ES_INDEX = 'ft_farequote';
|
||||
|
@ -23,14 +23,14 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
// aiops / Explain Log Rate Spikes lives in the ML UI so we need some related services.
|
||||
const ml = getService('ml');
|
||||
|
||||
function runTests(testData: TestData) {
|
||||
function runTests(testData: TestDataEsArchive) {
|
||||
it(`${testData.suiteTitle} loads the source data in explain log rate spikes`, async () => {
|
||||
await elasticChart.setNewChartUiDebugFlag(true);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} loads the saved search selection page`
|
||||
);
|
||||
await aiops.explainLogRateSpikes.navigateToIndexPatternSelection();
|
||||
await aiops.explainLogRateSpikesPage.navigateToIndexPatternSelection();
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} loads the explain log rate spikes page`
|
||||
|
@ -42,10 +42,10 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
|
||||
it(`${testData.suiteTitle} displays index details`, async () => {
|
||||
await ml.testExecution.logTestStep(`${testData.suiteTitle} displays the time range step`);
|
||||
await aiops.explainLogRateSpikes.assertTimeRangeSelectorSectionExists();
|
||||
await aiops.explainLogRateSpikesPage.assertTimeRangeSelectorSectionExists();
|
||||
|
||||
await ml.testExecution.logTestStep(`${testData.suiteTitle} loads data for full time range`);
|
||||
await aiops.explainLogRateSpikes.clickUseFullDataButton(
|
||||
await aiops.explainLogRateSpikesPage.clickUseFullDataButton(
|
||||
testData.expected.totalDocCountFormatted
|
||||
);
|
||||
await headerPage.waitUntilLoadingHasFinished();
|
||||
|
@ -53,53 +53,53 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} displays elements in the doc count panel correctly`
|
||||
);
|
||||
await aiops.explainLogRateSpikes.assertTotalDocCountHeaderExists();
|
||||
await aiops.explainLogRateSpikes.assertTotalDocCountChartExists();
|
||||
await aiops.explainLogRateSpikesPage.assertTotalDocCountHeaderExists();
|
||||
await aiops.explainLogRateSpikesPage.assertTotalDocCountChartExists();
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} displays elements in the page correctly`
|
||||
);
|
||||
await aiops.explainLogRateSpikes.assertSearchPanelExists();
|
||||
await aiops.explainLogRateSpikesPage.assertSearchPanelExists();
|
||||
|
||||
await ml.testExecution.logTestStep('displays empty prompt');
|
||||
await aiops.explainLogRateSpikes.assertNoWindowParametersEmptyPromptExists();
|
||||
await aiops.explainLogRateSpikesPage.assertNoWindowParametersEmptyPromptExists();
|
||||
|
||||
await ml.testExecution.logTestStep('clicks the document count chart to start analysis');
|
||||
await aiops.explainLogRateSpikes.clickDocumentCountChart();
|
||||
await aiops.explainLogRateSpikes.assertAnalysisSectionExists();
|
||||
await aiops.explainLogRateSpikesPage.clickDocumentCountChart(testData.chartClickCoordinates);
|
||||
await aiops.explainLogRateSpikesPage.assertAnalysisSectionExists();
|
||||
|
||||
await ml.testExecution.logTestStep('displays the no results found prompt');
|
||||
await aiops.explainLogRateSpikes.assertNoResultsFoundEmptyPromptExists();
|
||||
await aiops.explainLogRateSpikesPage.assertNoResultsFoundEmptyPromptExists();
|
||||
|
||||
await ml.testExecution.logTestStep('adjusts the brushes to get analysis results');
|
||||
await aiops.explainLogRateSpikes.assertRerunAnalysisButtonExists(false);
|
||||
await aiops.explainLogRateSpikesPage.assertRerunAnalysisButtonExists(false);
|
||||
|
||||
// Get the current width of the deviation brush for later comparison.
|
||||
const brushSelectionWidthBefore = await aiops.explainLogRateSpikes.getBrushSelectionWidth(
|
||||
const brushSelectionWidthBefore = await aiops.explainLogRateSpikesPage.getBrushSelectionWidth(
|
||||
'aiopsBrushDeviation'
|
||||
);
|
||||
|
||||
// Get the px values for the timestamp we want to move the brush to.
|
||||
const { targetPx, intervalPx } = await aiops.explainLogRateSpikes.getPxForTimestamp(
|
||||
testData.brushTargetTimestamp
|
||||
const { targetPx, intervalPx } = await aiops.explainLogRateSpikesPage.getPxForTimestamp(
|
||||
testData.brushDeviationTargetTimestamp
|
||||
);
|
||||
|
||||
// Adjust the right brush handle
|
||||
await aiops.explainLogRateSpikes.adjustBrushHandler(
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushDeviation',
|
||||
'handle--e',
|
||||
targetPx + intervalPx
|
||||
);
|
||||
|
||||
// Adjust the left brush handle
|
||||
await aiops.explainLogRateSpikes.adjustBrushHandler(
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushDeviation',
|
||||
'handle--w',
|
||||
targetPx
|
||||
);
|
||||
|
||||
// Get the new brush selection width for later comparison.
|
||||
const brushSelectionWidthAfter = await aiops.explainLogRateSpikes.getBrushSelectionWidth(
|
||||
const brushSelectionWidthAfter = await aiops.explainLogRateSpikesPage.getBrushSelectionWidth(
|
||||
'aiopsBrushDeviation'
|
||||
);
|
||||
|
||||
|
@ -110,18 +110,18 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
expect(brushSelectionWidthBefore).not.to.be(brushSelectionWidthAfter);
|
||||
expect(brushSelectionWidthAfter).not.to.be.greaterThan(intervalPx * 2);
|
||||
|
||||
await aiops.explainLogRateSpikes.assertRerunAnalysisButtonExists(true);
|
||||
await aiops.explainLogRateSpikesPage.assertRerunAnalysisButtonExists(true);
|
||||
|
||||
await ml.testExecution.logTestStep('rerun the analysis with adjusted settings');
|
||||
|
||||
await aiops.explainLogRateSpikes.clickRerunAnalysisButton(true);
|
||||
await aiops.explainLogRateSpikes.assertProgressTitle('Progress: 100% — Done.');
|
||||
await aiops.explainLogRateSpikesPage.clickRerunAnalysisButton(true);
|
||||
await aiops.explainLogRateSpikesPage.assertProgressTitle('Progress: 100% — Done.');
|
||||
|
||||
// The group switch should be disabled by default
|
||||
await aiops.explainLogRateSpikes.assertSpikeAnalysisGroupSwitchExists(false);
|
||||
await aiops.explainLogRateSpikesPage.assertSpikeAnalysisGroupSwitchExists(false);
|
||||
|
||||
// Enabled grouping
|
||||
await aiops.explainLogRateSpikes.clickSpikeAnalysisGroupSwitch(false);
|
||||
await aiops.explainLogRateSpikesPage.clickSpikeAnalysisGroupSwitch(false);
|
||||
|
||||
await aiops.explainLogRateSpikesAnalysisGroupsTable.assertSpikeAnalysisTableExists();
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import type { TestDataGenerated } from './types';
|
||||
import { artificialLogDataViewTestData } from './test_data';
|
||||
|
||||
export default function ({ getPageObject, getService }: FtrProviderContext) {
|
||||
const es = getService('es');
|
||||
const headerPage = getPageObject('header');
|
||||
const elasticChart = getService('elasticChart');
|
||||
const aiops = getService('aiops');
|
||||
const log = getService('log');
|
||||
|
||||
// aiops / Explain Log Rate Spikes lives in the ML UI so we need some related services.
|
||||
const ml = getService('ml');
|
||||
|
||||
function runTests(testData: TestDataGenerated) {
|
||||
it(`${testData.suiteTitle} loads the source data in explain log rate spikes`, async () => {
|
||||
await elasticChart.setNewChartUiDebugFlag(true);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} loads the saved search selection page`
|
||||
);
|
||||
await aiops.explainLogRateSpikesPage.navigateToIndexPatternSelection();
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} loads the explain log rate spikes page`
|
||||
);
|
||||
await ml.jobSourceSelection.selectSourceForExplainLogRateSpikes(
|
||||
testData.sourceIndexOrSavedSearch
|
||||
);
|
||||
});
|
||||
|
||||
it(`${testData.suiteTitle} displays index details`, async () => {
|
||||
await ml.testExecution.logTestStep(`${testData.suiteTitle} displays the time range step`);
|
||||
await aiops.explainLogRateSpikesPage.assertTimeRangeSelectorSectionExists();
|
||||
|
||||
await ml.testExecution.logTestStep(`${testData.suiteTitle} loads data for full time range`);
|
||||
await aiops.explainLogRateSpikesPage.clickUseFullDataButton(
|
||||
testData.expected.totalDocCountFormatted
|
||||
);
|
||||
await headerPage.waitUntilLoadingHasFinished();
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} displays elements in the doc count panel correctly`
|
||||
);
|
||||
await aiops.explainLogRateSpikesPage.assertTotalDocCountHeaderExists();
|
||||
await aiops.explainLogRateSpikesPage.assertTotalDocCountChartExists();
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
`${testData.suiteTitle} displays elements in the page correctly`
|
||||
);
|
||||
await aiops.explainLogRateSpikesPage.assertSearchPanelExists();
|
||||
|
||||
await ml.testExecution.logTestStep('displays empty prompt');
|
||||
await aiops.explainLogRateSpikesPage.assertNoWindowParametersEmptyPromptExists();
|
||||
|
||||
await ml.testExecution.logTestStep('clicks the document count chart to start analysis');
|
||||
await aiops.explainLogRateSpikesPage.clickDocumentCountChart(testData.chartClickCoordinates);
|
||||
await aiops.explainLogRateSpikesPage.assertAnalysisSectionExists();
|
||||
|
||||
await ml.testExecution.logTestStep('displays the no results found prompt');
|
||||
await aiops.explainLogRateSpikesPage.assertNoResultsFoundEmptyPromptExists();
|
||||
|
||||
await ml.testExecution.logTestStep('adjusts the brushes to get analysis results');
|
||||
await aiops.explainLogRateSpikesPage.assertRerunAnalysisButtonExists(false);
|
||||
|
||||
// Get the current width of the deviation brush for later comparison.
|
||||
const brushSelectionWidthBefore = await aiops.explainLogRateSpikesPage.getBrushSelectionWidth(
|
||||
'aiopsBrushDeviation'
|
||||
);
|
||||
|
||||
// Get the px values for the timestamp we want to move the brush to.
|
||||
const { targetPx, intervalPx } = await aiops.explainLogRateSpikesPage.getPxForTimestamp(
|
||||
testData.brushDeviationTargetTimestamp
|
||||
);
|
||||
|
||||
// Adjust the right brush handle
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushDeviation',
|
||||
'handle--e',
|
||||
targetPx + intervalPx * testData.brushIntervalFactor
|
||||
);
|
||||
|
||||
// Adjust the left brush handle
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushDeviation',
|
||||
'handle--w',
|
||||
targetPx - intervalPx * testData.brushIntervalFactor
|
||||
);
|
||||
|
||||
if (testData.brushBaselineTargetTimestamp) {
|
||||
// Get the px values for the timestamp we want to move the brush to.
|
||||
const { targetPx: targetBaselinePx } =
|
||||
await aiops.explainLogRateSpikesPage.getPxForTimestamp(
|
||||
testData.brushBaselineTargetTimestamp
|
||||
);
|
||||
|
||||
// Adjust the right brush handle
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushBaseline',
|
||||
'handle--e',
|
||||
targetBaselinePx + intervalPx * testData.brushIntervalFactor
|
||||
);
|
||||
|
||||
// Adjust the left brush handle
|
||||
await aiops.explainLogRateSpikesPage.adjustBrushHandler(
|
||||
'aiopsBrushBaseline',
|
||||
'handle--w',
|
||||
targetBaselinePx - intervalPx * testData.brushIntervalFactor
|
||||
);
|
||||
}
|
||||
// Get the new brush selection width for later comparison.
|
||||
const brushSelectionWidthAfter = await aiops.explainLogRateSpikesPage.getBrushSelectionWidth(
|
||||
'aiopsBrushDeviation'
|
||||
);
|
||||
|
||||
// Assert the adjusted brush: The selection width should have changed and
|
||||
// we test if the selection is smaller than two bucket intervals.
|
||||
// Finally, the adjusted brush should trigger
|
||||
// a warning on the "Rerun analysis" button.
|
||||
expect(brushSelectionWidthBefore).not.to.be(brushSelectionWidthAfter);
|
||||
expect(brushSelectionWidthAfter).not.to.be.greaterThan(intervalPx * 21);
|
||||
|
||||
await aiops.explainLogRateSpikesPage.assertRerunAnalysisButtonExists(true);
|
||||
|
||||
await ml.testExecution.logTestStep('rerun the analysis with adjusted settings');
|
||||
|
||||
await aiops.explainLogRateSpikesPage.clickRerunAnalysisButton(true);
|
||||
await aiops.explainLogRateSpikesPage.assertProgressTitle('Progress: 100% — Done.');
|
||||
|
||||
// The group switch should be disabled by default
|
||||
await aiops.explainLogRateSpikesPage.assertSpikeAnalysisGroupSwitchExists(false);
|
||||
|
||||
// Enabled grouping
|
||||
await aiops.explainLogRateSpikesPage.clickSpikeAnalysisGroupSwitch(false);
|
||||
|
||||
await aiops.explainLogRateSpikesAnalysisGroupsTable.assertSpikeAnalysisTableExists();
|
||||
|
||||
const analysisGroupsTable =
|
||||
await aiops.explainLogRateSpikesAnalysisGroupsTable.parseAnalysisTable();
|
||||
expect(analysisGroupsTable).to.be.eql(testData.expected.analysisGroupsTable);
|
||||
|
||||
await ml.testExecution.logTestStep('expand table row');
|
||||
await aiops.explainLogRateSpikesAnalysisGroupsTable.assertExpandRowButtonExists();
|
||||
await aiops.explainLogRateSpikesAnalysisGroupsTable.expandRow();
|
||||
|
||||
const analysisTable = await aiops.explainLogRateSpikesAnalysisTable.parseAnalysisTable();
|
||||
expect(analysisTable).to.be.eql(testData.expected.analysisTable);
|
||||
});
|
||||
}
|
||||
|
||||
describe('explain log rate spikes - artificial log data', function () {
|
||||
this.tags(['aiops']);
|
||||
|
||||
before(async () => {
|
||||
try {
|
||||
await es.indices.delete({ index: artificialLogDataViewTestData.sourceIndexOrSavedSearch });
|
||||
} catch (e) {
|
||||
log.error(
|
||||
`Error deleting index '${artificialLogDataViewTestData.sourceIndexOrSavedSearch}' in before() callback`
|
||||
);
|
||||
}
|
||||
// Create index with mapping
|
||||
await es.indices.create({
|
||||
index: artificialLogDataViewTestData.sourceIndexOrSavedSearch,
|
||||
mappings: {
|
||||
properties: {
|
||||
user: { type: 'keyword' },
|
||||
response_code: { type: 'keyword' },
|
||||
url: { type: 'keyword' },
|
||||
version: { type: 'keyword' },
|
||||
'@timestamp': { type: 'date' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await es.bulk({
|
||||
refresh: 'wait_for',
|
||||
body: artificialLogDataViewTestData.bulkBody,
|
||||
});
|
||||
|
||||
await ml.testResources.createIndexPatternIfNeeded(
|
||||
artificialLogDataViewTestData.sourceIndexOrSavedSearch,
|
||||
'@timestamp'
|
||||
);
|
||||
|
||||
await ml.testResources.setKibanaTimeZoneToUTC();
|
||||
|
||||
await ml.securityUI.loginAsMlPowerUser();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await elasticChart.setNewChartUiDebugFlag(false);
|
||||
await ml.testResources.deleteIndexPatternByTitle(
|
||||
artificialLogDataViewTestData.sourceIndexOrSavedSearch
|
||||
);
|
||||
try {
|
||||
await es.indices.delete({ index: artificialLogDataViewTestData.sourceIndexOrSavedSearch });
|
||||
} catch (e) {
|
||||
log.error(
|
||||
`Error deleting index '${artificialLogDataViewTestData.sourceIndexOrSavedSearch}' in after() callback`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
describe('with artificial logs', function () {
|
||||
// Run tests on full farequote index.
|
||||
it(`${artificialLogDataViewTestData.suiteTitle} loads the explain log rate spikes page`, async () => {
|
||||
// Start navigation from the base of the ML app.
|
||||
await ml.navigation.navigateToMl();
|
||||
await elasticChart.setNewChartUiDebugFlag(true);
|
||||
});
|
||||
|
||||
runTests(artificialLogDataViewTestData);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -33,6 +33,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
await ml.testResources.resetKibanaTimeZone();
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./explain_log_rate_spikes'));
|
||||
loadTestFile(require.resolve('./explain_log_rate_spikes_farequote'));
|
||||
loadTestFile(require.resolve('./explain_log_rate_spikes_logs'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,13 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { TestData } from './types';
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
export const farequoteDataViewTestData: TestData = {
|
||||
import type { GeneratedDoc, TestDataEsArchive, TestDataGenerated } from './types';
|
||||
|
||||
export const farequoteDataViewTestData: TestDataEsArchive = {
|
||||
suiteTitle: 'farequote index pattern',
|
||||
isSavedSearch: false,
|
||||
sourceIndexOrSavedSearch: 'ft_farequote',
|
||||
brushTargetTimestamp: 1455033600000,
|
||||
brushDeviationTargetTimestamp: 1455033600000,
|
||||
brushIntervalFactor: 1,
|
||||
chartClickCoordinates: [0, 0],
|
||||
expected: {
|
||||
totalDocCountFormatted: '86,374',
|
||||
analysisGroupsTable: [
|
||||
|
@ -32,3 +36,113 @@ export const farequoteDataViewTestData: TestData = {
|
|||
],
|
||||
},
|
||||
};
|
||||
|
||||
const REFERENCE_TS = 1669018354793;
|
||||
const DAY_MS = 86400000;
|
||||
const ES_INDEX = 'aiops_frequent_items_test';
|
||||
|
||||
const DEVIATION_TS = REFERENCE_TS - DAY_MS * 2;
|
||||
const BASELINE_TS = DEVIATION_TS - DAY_MS * 1;
|
||||
|
||||
export const artificialLogDataViewTestData: TestDataGenerated = {
|
||||
suiteTitle: 'artificial index pattern',
|
||||
isSavedSearch: false,
|
||||
sourceIndexOrSavedSearch: 'aiops_frequent_items_test',
|
||||
brushBaselineTargetTimestamp: BASELINE_TS + DAY_MS / 2,
|
||||
brushDeviationTargetTimestamp: DEVIATION_TS + DAY_MS / 2,
|
||||
brushIntervalFactor: 10,
|
||||
chartClickCoordinates: [-200, 30],
|
||||
bulkBody: getArtificialLogsBulkBody(),
|
||||
expected: {
|
||||
totalDocCountFormatted: '8,400',
|
||||
analysisGroupsTable: [
|
||||
{ group: 'user: Peter', docCount: '2081' },
|
||||
{ group: 'response_code: 500url: login.php', docCount: '834' },
|
||||
],
|
||||
analysisTable: [
|
||||
{
|
||||
fieldName: 'user',
|
||||
fieldValue: 'Peter',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '2.78e-22',
|
||||
impact: 'High',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function getArtificialLogsBulkBody() {
|
||||
const bulkBody: estypes.BulkRequest<GeneratedDoc, GeneratedDoc>['body'] = [];
|
||||
const action = { index: { _index: ES_INDEX } };
|
||||
let tsOffset = 0;
|
||||
|
||||
// Creates docs evenly spread across baseline and deviation time frame
|
||||
[BASELINE_TS, DEVIATION_TS].forEach((ts) => {
|
||||
['Peter', 'Paul', 'Mary'].forEach((user) => {
|
||||
['200', '404', '500'].forEach((responseCode) => {
|
||||
['login.php', 'user.php', 'home.php'].forEach((url) => {
|
||||
// Don't add docs that match the exact pattern of the filter we want to base the test queries on
|
||||
if (
|
||||
!(
|
||||
user === 'Peter' &&
|
||||
responseCode === '500' &&
|
||||
(url === 'home.php' || url === 'login.php')
|
||||
)
|
||||
) {
|
||||
tsOffset = 0;
|
||||
[...Array(100)].forEach(() => {
|
||||
tsOffset += DAY_MS / 100;
|
||||
const doc: GeneratedDoc = {
|
||||
user,
|
||||
response_code: responseCode,
|
||||
url,
|
||||
version: 'v1.0.0',
|
||||
'@timestamp': ts + tsOffset,
|
||||
};
|
||||
|
||||
bulkBody.push(action);
|
||||
bulkBody.push(doc);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Now let's add items to the dataset to make some specific significant terms being returned as results
|
||||
['200', '404'].forEach((responseCode) => {
|
||||
['login.php', 'user.php', 'home.php'].forEach((url) => {
|
||||
tsOffset = 0;
|
||||
[...Array(300)].forEach(() => {
|
||||
tsOffset += DAY_MS / 300;
|
||||
bulkBody.push(action);
|
||||
bulkBody.push({
|
||||
user: 'Peter',
|
||||
response_code: responseCode,
|
||||
url,
|
||||
version: 'v1.0.0',
|
||||
'@timestamp': DEVIATION_TS + tsOffset,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
['Paul', 'Mary'].forEach((user) => {
|
||||
['login.php', 'home.php'].forEach((url) => {
|
||||
tsOffset = 0;
|
||||
[...Array(400)].forEach(() => {
|
||||
tsOffset += DAY_MS / 400;
|
||||
bulkBody.push(action);
|
||||
bulkBody.push({
|
||||
user,
|
||||
response_code: '500',
|
||||
url,
|
||||
version: 'v1.0.0',
|
||||
'@timestamp': DEVIATION_TS + tsOffset,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return bulkBody;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export interface TestData {
|
||||
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
export interface TestDataEsArchive {
|
||||
suiteTitle: string;
|
||||
isSavedSearch?: boolean;
|
||||
sourceIndexOrSavedSearch: string;
|
||||
rowsPerPage?: 10 | 25 | 50;
|
||||
brushTargetTimestamp: number;
|
||||
brushBaselineTargetTimestamp?: number;
|
||||
brushDeviationTargetTimestamp: number;
|
||||
brushIntervalFactor: number;
|
||||
chartClickCoordinates: [number, number];
|
||||
expected: {
|
||||
totalDocCountFormatted: string;
|
||||
analysisGroupsTable: Array<{ group: string; docCount: string }>;
|
||||
|
@ -23,3 +28,15 @@ export interface TestData {
|
|||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GeneratedDoc {
|
||||
user: string;
|
||||
response_code: string;
|
||||
url: string;
|
||||
version: string;
|
||||
'@timestamp': number;
|
||||
}
|
||||
|
||||
export interface TestDataGenerated extends TestDataEsArchive {
|
||||
bulkBody: estypes.BulkRequest<GeneratedDoc, GeneratedDoc>['body'];
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import expect from '@kbn/expect';
|
|||
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export function ExplainLogRateSpikesProvider({ getService }: FtrProviderContext) {
|
||||
export function ExplainLogRateSpikesPageProvider({ getService }: FtrProviderContext) {
|
||||
const browser = getService('browser');
|
||||
const elasticChart = getService('elasticChart');
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
@ -64,11 +64,15 @@ export function ExplainLogRateSpikesProvider({ getService }: FtrProviderContext)
|
|||
await testSubjects.existOrFail(`aiopsNoResultsFoundEmptyPrompt`);
|
||||
},
|
||||
|
||||
async clickDocumentCountChart() {
|
||||
async clickDocumentCountChart(chartClickCoordinates: [number, number]) {
|
||||
await elasticChart.waitForRenderComplete();
|
||||
const el = await elasticChart.getCanvas();
|
||||
|
||||
await browser.getActions().move({ x: 0, y: 0, origin: el._webElement }).click().perform();
|
||||
await browser
|
||||
.getActions()
|
||||
.move({ x: chartClickCoordinates[0], y: chartClickCoordinates[1], origin: el._webElement })
|
||||
.click()
|
||||
.perform();
|
||||
|
||||
await this.assertHistogramBrushesExist();
|
||||
},
|
||||
|
@ -154,7 +158,14 @@ export function ExplainLogRateSpikesProvider({ getService }: FtrProviderContext)
|
|||
// Get the total count of bars and index of a bar for a given timestamp in the charts debug data.
|
||||
const bars = chartDebugData?.bars?.[0].bars ?? [];
|
||||
const barsCount = bars.length;
|
||||
const targetDeviationBarIndex = bars.findIndex((b) => b.x === timestamp);
|
||||
|
||||
const closestTimestamp = bars
|
||||
.map((d) => d.x)
|
||||
.reduce(function (p, c) {
|
||||
return Math.abs(c - timestamp) < Math.abs(p - timestamp) ? c : p;
|
||||
});
|
||||
|
||||
const targetDeviationBarIndex = bars.findIndex((b) => b.x === closestTimestamp);
|
||||
|
||||
// The pixel location based on the given timestamp, calculated by taking the share of the index value
|
||||
// over the total count of bars, normalized by the wrapping element's width.
|
|
@ -7,18 +7,18 @@
|
|||
|
||||
import type { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
import { ExplainLogRateSpikesProvider } from './explain_log_rate_spikes';
|
||||
import { ExplainLogRateSpikesPageProvider } from './explain_log_rate_spikes_page';
|
||||
import { ExplainLogRateSpikesAnalysisTableProvider } from './explain_log_rate_spikes_analysis_table';
|
||||
import { ExplainLogRateSpikesAnalysisGroupsTableProvider } from './explain_log_rate_spikes_analysis_groups_table';
|
||||
|
||||
export function AiopsProvider(context: FtrProviderContext) {
|
||||
const explainLogRateSpikes = ExplainLogRateSpikesProvider(context);
|
||||
const explainLogRateSpikesPage = ExplainLogRateSpikesPageProvider(context);
|
||||
const explainLogRateSpikesAnalysisTable = ExplainLogRateSpikesAnalysisTableProvider(context);
|
||||
const explainLogRateSpikesAnalysisGroupsTable =
|
||||
ExplainLogRateSpikesAnalysisGroupsTableProvider(context);
|
||||
|
||||
return {
|
||||
explainLogRateSpikes,
|
||||
explainLogRateSpikesPage,
|
||||
explainLogRateSpikesAnalysisTable,
|
||||
explainLogRateSpikesAnalysisGroupsTable,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue