Skip to content

Commit

Permalink
adds workflow to go from explain log rate spikes to log pattern analy…
Browse files Browse the repository at this point in the history
…sis to functional tests
  • Loading branch information
walterra committed Apr 19, 2023
1 parent bbce6de commit c916436
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { EuiLink, EuiIcon, EuiText, EuiToolTip, type IconType } from '@elastic/e

interface TableActionButtonProps {
iconType: IconType;
dataTestSubjPostfix: string;
isDisabled: boolean;
label: string;
message?: string;
Expand All @@ -19,6 +20,7 @@ interface TableActionButtonProps {

export const TableActionButton: FC<TableActionButtonProps> = ({
iconType,
dataTestSubjPostfix,
isDisabled,
label,
message,
Expand All @@ -33,7 +35,7 @@ export const TableActionButton: FC<TableActionButtonProps> = ({

const unwrappedButton = !isDisabled ? (
<EuiLink
data-test-subj="aiopsTableActionButtonEnabled"
data-test-subj={`aiopsTableActionButton${dataTestSubjPostfix} enabled`}
onClick={onClick}
color={'text'}
aria-label={message}
Expand All @@ -42,7 +44,7 @@ export const TableActionButton: FC<TableActionButtonProps> = ({
</EuiLink>
) : (
<EuiText
data-test-subj="aiopsTableActionButtonDisabled"
data-test-subj={`aiopsTableActionButton${dataTestSubjPostfix} disabled`}
size="s"
color={'subdued'}
aria-label={message}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const useCopyToClipboardAction = (): TableItemAction => ({
<EuiCopy textToCopy={getTableItemAsKQL(tableItem)}>
{(copy) => (
<TableActionButton
dataTestSubjPostfix="CopyToClipboard"
iconType="copyClipboard"
isDisabled={false}
label={copyToClipboardButtonLabel}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const useViewInDiscoverAction = (dataViewId?: string): TableItemAction =>

return (
<TableActionButton
dataTestSubjPostfix="Discover"
iconType="discoverApp"
isDisabled={discoverUrlError !== undefined}
label={viewInDiscoverMessage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const useViewInLogPatternAnalysisAction = (dataViewId?: string): TableIte

return (
<TableActionButton
dataTestSubjPostfix="LogPatternAnalysis"
iconType="logstashQueue"
isDisabled={isDisabled}
label={viewInLogPatternAnalysisMessage}
Expand Down
26 changes: 25 additions & 1 deletion x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,28 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
);
}
}

if (testData.action !== undefined) {
await ml.testExecution.logTestStep('check all table row actions are present');
await aiops.explainLogRateSpikesAnalysisGroupsTable.assertRowActions(
testData.action.tableRowId
);

await ml.testExecution.logTestStep('click log pattern analysis action');
await aiops.explainLogRateSpikesAnalysisGroupsTable.clickRowAction(
testData.action.tableRowId,
testData.action.type
);

await ml.testExecution.logTestStep('check log pattern analysis page loaded correctly');
await aiops.logPatternAnalysisPageProvider.assertLogCategorizationPageExists();
await aiops.logPatternAnalysisPageProvider.assertTotalDocumentCount(
testData.action.expected.totalDocCount
);
await aiops.logPatternAnalysisPageProvider.assertQueryInput(
testData.action.expected.queryBar
);
}
});
}

Expand Down Expand Up @@ -242,7 +264,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {

after(async () => {
await elasticChart.setNewChartUiDebugFlag(false);
await ml.testResources.deleteIndexPatternByTitle(testData.sourceIndexOrSavedSearch);
if (testData.dataGenerator !== 'kibana_sample_data_logs') {
await ml.testResources.deleteIndexPatternByTitle(testData.sourceIndexOrSavedSearch);
}
await aiops.explainLogRateSpikesDataGenerator.removeGeneratedData(testData.dataGenerator);
});

Expand Down
9 changes: 9 additions & 0 deletions x-pack/test/functional/apps/aiops/test_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ export const kibanaLogsDataViewTestData: TestData = {
chartClickCoordinates: [235, 0],
fieldSelectorSearch: 'referer',
fieldSelectorApplyAvailable: true,
action: {
type: 'LogPatternAnalysis',
tableRowId: '488337254',
expected: {
queryBar:
'clientip:30.156.16.164 AND host.keyword:elastic-elastic-elastic.org AND ip:30.156.16.163 AND response.keyword:404 AND machine.os.keyword:win xp AND geo.dest:IN AND geo.srcdest:US\\:IN',
totalDocCount: '100',
},
},
expected: {
totalDocCountFormatted: '14,074',
analysisGroupsTable: [
Expand Down
10 changes: 10 additions & 0 deletions x-pack/test/functional/apps/aiops/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@

import { isPopulatedObject } from '@kbn/ml-is-populated-object';

interface TestDataTableActionLogPatternAnalysis {
type: 'LogPatternAnalysis';
tableRowId: string;
expected: {
queryBar: string;
totalDocCount: string;
};
}

interface TestDataExpectedWithSampleProbability {
totalDocCountFormatted: string;
sampleProbabilityFormatted: string;
Expand Down Expand Up @@ -46,5 +55,6 @@ export interface TestData {
fieldSelectorSearch: string;
fieldSelectorApplyAvailable: boolean;
query?: string;
action?: TestDataTableActionLogPatternAnalysis;
expected: TestDataExpectedWithSampleProbability | TestDataExpectedWithoutSampleProbability;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
* 2.0.
*/

import expect from '@kbn/expect';

import { FtrProviderContext } from '../../ftr_provider_context';

export function ExplainLogRateSpikesAnalysisGroupsTableProvider({
getService,
}: FtrProviderContext) {
const find = getService('find');
const testSubjects = getService('testSubjects');
const retry = getService('retry');
const browser = getService('browser');

return new (class AnalysisTable {
public async assertSpikeAnalysisTableExists() {
Expand Down Expand Up @@ -55,5 +60,50 @@ export function ExplainLogRateSpikesAnalysisGroupsTableProvider({

return rows;
}

public rowSelector(rowId: string, subSelector?: string) {
const row = `~aiopsSpikeAnalysisGroupsTable > ~row-${rowId}`;
return !subSelector ? row : `${row} > ${subSelector}`;
}

public async ensureActionsMenuOpen(rowId: string) {
await retry.tryForTime(30 * 1000, async () => {
await this.ensureActionsMenuClosed();

if (!(await find.existsByCssSelector('.euiContextMenuPanel', 1000))) {
await testSubjects.click(this.rowSelector(rowId, 'euiCollapsedItemActionsButton'));
expect(await find.existsByCssSelector('.euiContextMenuPanel', 1000)).to.eql(
true,
'Actions popover should exist'
);
}
});
}

public async ensureActionsMenuClosed() {
await retry.tryForTime(30 * 1000, async () => {
await browser.pressKeys(browser.keys.ESCAPE);
expect(await find.existsByCssSelector('.euiContextMenuPanel', 1000)).to.eql(
false,
'Actions popover should not exist'
);
});
}

public async assertRowActions(rowId: string) {
await this.ensureActionsMenuOpen(rowId);

await testSubjects.existOrFail('aiopsTableActionButtonCopyToClipboard enabled');
await testSubjects.existOrFail('aiopsTableActionButtonDiscover enabled');
await testSubjects.existOrFail('aiopsTableActionButtonLogPatternAnalysis enabled');

await this.ensureActionsMenuClosed();
}

public async clickRowAction(rowId: string, action: string) {
await this.ensureActionsMenuOpen(rowId);
await testSubjects.click(`aiopsTableActionButton${action} enabled`);
await testSubjects.missingOrFail(`aiopsTableActionButton${action} enabled`);
}
})();
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ export function ExplainLogRateSpikesDataGeneratorProvider({ getService }: FtrPro

public async removeGeneratedData(dataGenerator: string) {
switch (dataGenerator) {
case 'kibana_sample_data_logs':
// do not remove
break;

case 'farequote_with_spike':
await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote');
break;
Expand Down
3 changes: 3 additions & 0 deletions x-pack/test/functional/services/aiops/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@ 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';
import { ExplainLogRateSpikesDataGeneratorProvider } from './explain_log_rate_spikes_data_generator';
import { LogPatternAnalysisPageProvider } from './log_pattern_analysis_page';

export function AiopsProvider(context: FtrProviderContext) {
const explainLogRateSpikesPage = ExplainLogRateSpikesPageProvider(context);
const explainLogRateSpikesAnalysisTable = ExplainLogRateSpikesAnalysisTableProvider(context);
const explainLogRateSpikesAnalysisGroupsTable =
ExplainLogRateSpikesAnalysisGroupsTableProvider(context);
const explainLogRateSpikesDataGenerator = ExplainLogRateSpikesDataGeneratorProvider(context);
const logPatternAnalysisPageProvider = LogPatternAnalysisPageProvider(context);

return {
explainLogRateSpikesPage,
explainLogRateSpikesAnalysisTable,
explainLogRateSpikesAnalysisGroupsTable,
explainLogRateSpikesDataGenerator,
logPatternAnalysisPageProvider,
};
}
42 changes: 42 additions & 0 deletions x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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';

export function LogPatternAnalysisPageProvider({ getService, getPageObject }: FtrProviderContext) {
const retry = getService('retry');
const testSubjects = getService('testSubjects');

return {
async assertLogCategorizationPageExists() {
await retry.tryForTime(30 * 1000, async () => {
await testSubjects.existOrFail('aiopsLogCategorizationPage');
});
},

async assertQueryInput(expectedQueryString: string) {
const aiopsQueryInput = await testSubjects.find('aiopsQueryInput');
const actualQueryString = await aiopsQueryInput.getVisibleText();
expect(actualQueryString).to.eql(
expectedQueryString,
`Expected query bar text to be '${expectedQueryString}' (got '${actualQueryString}')`
);
},

async assertTotalDocumentCount(expectedFormattedTotalDocCount: string) {
await retry.tryForTime(5000, async () => {
const docCount = await testSubjects.getVisibleText('aiopsTotalDocCount');
expect(docCount).to.eql(
expectedFormattedTotalDocCount,
`Expected total document count to be '${expectedFormattedTotalDocCount}' (got '${docCount}')`
);
});
},
};
}

0 comments on commit c916436

Please sign in to comment.