Skip to content

Commit

Permalink
[ML] Memory usage: Functional tests (elastic#197415)
Browse files Browse the repository at this point in the history
## Summary

Functional tests for `memory usage` page in ML.
  • Loading branch information
rbrtj authored Oct 25, 2024
1 parent 7732b8d commit 479280c
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 5 deletions.
1 change: 1 addition & 0 deletions .buildkite/ftr_platform_stateful_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ enabled:
- x-pack/test/functional/apps/ml/permissions/config.ts
- x-pack/test/functional/apps/ml/short_tests/config.ts
- x-pack/test/functional/apps/ml/stack_management_jobs/config.ts
- x-pack/test/functional/apps/ml/memory_usage/config.ts
- x-pack/test/functional/apps/monitoring/config.ts
- x-pack/test/functional/apps/painless_lab/config.ts
- x-pack/test/functional/apps/remote_clusters/config.ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => {
options={typeOptions}
selectedOptions={selectedOptions ?? []}
onChange={setSelectedOptions}
isClearable={false}
data-test-subj="mlJobTreeMapComboBox"
/>

<EuiSpacer size="s" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,18 @@ export const MemoryUsagePage: FC = () => {

{showNodeInfo ? (
<>
<EuiTabs>
<EuiTabs data-test-subj="mlMemoryUsageTabs">
<EuiTab
isSelected={selectedTab === TAB.NODES}
onClick={() => setSelectedTab(TAB.NODES)}
data-test-subj="mlMemoryUsageTab-nodes"
>
<FormattedMessage id="xpack.ml.memoryUsage.nodesTab" defaultMessage="Nodes" />
</EuiTab>
<EuiTab
isSelected={selectedTab === TAB.MEMORY_USAGE}
onClick={() => setSelectedTab(TAB.MEMORY_USAGE)}
data-test-subj="mlMemoryUsageTab-memory-usage"
>
<FormattedMessage id="xpack.ml.memoryUsage.memoryTab" defaultMessage="Memory usage" />
</EuiTab>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
<EuiTab
isSelected={selectedTab === TAB.DETAILS}
onClick={() => setSelectedTab(TAB.DETAILS)}
data-test-subj="mlNodesOverviewPanelDetailsTab"
>
<FormattedMessage
id="xpack.ml.trainedModels.nodesList.expandedRow.detailsTabTitle"
Expand All @@ -73,6 +74,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
<EuiTab
isSelected={selectedTab === TAB.MEMORY_USAGE}
onClick={() => setSelectedTab(TAB.MEMORY_USAGE)}
data-test-subj="mlNodesOverviewPanelMemoryTab"
>
<FormattedMessage
id="xpack.ml.trainedModels.nodesList.expandedRow.memoryTabTitle"
Expand All @@ -85,7 +87,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
<>
<EuiSpacer size="s" />
<EuiFlexGrid columns={2} gutterSize={'s'}>
<EuiFlexItem>
<EuiFlexItem data-test-subj="mlNodesTableRowDetailsPanel">
<EuiPanel hasShadow={false}>
<EuiTitle size={'xs'}>
<h5>
Expand All @@ -104,7 +106,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
</EuiPanel>
</EuiFlexItem>

<EuiFlexItem>
<EuiFlexItem data-test-subj="mlNodesTableRowDetailsAttributesPanel">
<EuiPanel hasShadow={false}>
<EuiTitle size={'xs'}>
<h5>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export const NodesList: FC<NodesListProps> = ({ compactView = false }) => {
},
box: {
incremental: true,
'data-test-subj': 'mlNodesTableSearchInput',
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const nodesListRouteFactory = (
},
],
enableDatePicker: true,
'data-test-subj': 'mlPageMemoryUsage',
});

const PageWrapper: FC = () => {
Expand Down
20 changes: 20 additions & 0 deletions x-pack/test/functional/apps/ml/memory_usage/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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 { FtrConfigProviderContext } from '@kbn/test';

export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js'));

return {
...functionalConfig.getAll(),
testFiles: [require.resolve('.')],
junit: {
reportName: 'Chrome X-Pack UI Functional Tests - ML memory_usage',
},
};
}
33 changes: 33 additions & 0 deletions x-pack/test/functional/apps/ml/memory_usage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getService, loadTestFile }: FtrProviderContext) {
const ml = getService('ml');

describe('machine learning - overview page', function () {
this.tags(['skipFirefox']);

before(async () => {
await ml.securityCommon.createMlRoles();
await ml.securityCommon.createMlUsers();
await ml.securityUI.loginAsMlPowerUser();
});

after(async () => {
await ml.securityUI.logout();

await ml.securityCommon.cleanMlUsers();
await ml.securityCommon.cleanMlRoles();

await ml.testResources.resetKibanaTimeZone();
});

loadTestFile(require.resolve('./memory_usage_page'));
});
}
72 changes: 72 additions & 0 deletions x-pack/test/functional/apps/ml/memory_usage/memory_usage_page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getService }: FtrProviderContext) {
const ml = getService('ml');
const esArchiver = getService('esArchiver');

const jobId = 'sample_job';

describe('ML memory usage page', function () {
this.tags(['ml']);

before(async () => {
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote');

const jobConfig = ml.commonConfig.getADFqSingleMetricJobConfig(jobId);

// Create and open AD job
await ml.api.createAnomalyDetectionJob(jobConfig);
await ml.api.openAnomalyDetectionJob(jobId);

await ml.navigation.navigateToMl();
await ml.navigation.navigateToMemoryUsage();
});

after(async () => {
await ml.api.closeAnomalyDetectionJob(jobId);
await ml.api.cleanMlIndices();
});

it('opens page with nodes tab selected', async () => {
await ml.memoryUsage.assertMemoryUsageTabIsSelected('nodes');
});

it('allows sorting', async () => {
await ml.memoryUsage.sortColumn('tableHeaderCell_name_1');
await ml.memoryUsage.assertColumnIsSorted('tableHeaderCell_name_1', 'descending');
});

it('allows searching for a node', async () => {
await ml.memoryUsage.searchForNode('ftr');
await ml.memoryUsage.assertRowCount(1);
});

it('expands node details and displays memory usage details', async () => {
await ml.memoryUsage.expandRow();
await ml.memoryUsage.assertNodeExpandedDetailsPanelsExist();
await ml.memoryUsage.selectNodeExpandedRowTab('mlNodesOverviewPanelMemoryTab');
await ml.memoryUsage.assertChartItemsSelectedByDefault();
await ml.memoryUsage.assertTreeChartExists();
});

it('clears selected chart items', async () => {
await ml.memoryUsage.clearSelectedChartItems();
await ml.memoryUsage.assertEmptyTreeChartExists();
});

it('selects memory usage tab and displays chart', async () => {
await ml.memoryUsage.selectTab('memory-usage');
await ml.memoryUsage.assertTreeChartExists();

await ml.memoryUsage.clearSelectedChartItems();
await ml.memoryUsage.assertEmptyTreeChartExists();
});
});
}
5 changes: 4 additions & 1 deletion x-pack/test/functional/services/ml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ import { MlTableServiceProvider } from './common_table_service';
import { MachineLearningFieldStatsFlyoutProvider } from './field_stats_flyout';
import { MachineLearningDataDriftProvider } from './data_drift';
import { TrainedModelsFlyoutProvider } from './add_trained_models_flyout';
import { MachineLearningMemoryUsageProvider } from './memory_usage';

export function MachineLearningProvider(context: FtrProviderContext) {
const commonAPI = MachineLearningCommonAPIProvider(context);
const commonUI = MachineLearningCommonUIProvider(context);
Expand Down Expand Up @@ -178,7 +180,7 @@ export function MachineLearningProvider(context: FtrProviderContext) {
const deployDFAModelFlyout = DeployDFAModelFlyoutProvider(context, commonUI);
const mlNodesPanel = MlNodesPanelProvider(context);
const notifications = NotificationsProvider(context, commonUI, tableService);

const memoryUsage = MachineLearningMemoryUsageProvider(context);
const cases = MachineLearningCasesProvider(context, swimLane, anomalyCharts);

return {
Expand Down Expand Up @@ -244,5 +246,6 @@ export function MachineLearningProvider(context: FtrProviderContext) {
trainedModelsFlyout,
deployDFAModelFlyout,
trainedModelsTable,
memoryUsage,
};
}
107 changes: 107 additions & 0 deletions x-pack/test/functional/services/ml/memory_usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* 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 { FtrProviderContext } from '../../ftr_provider_context';

export function MachineLearningMemoryUsageProvider({ getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const comboBox = getService('comboBox');

return {
async assertNodeExpandedDetailsPanelsExist() {
await testSubjects.existOrFail('mlNodesTableRowDetailsPanel');
await testSubjects.existOrFail('mlNodesTableRowDetailsAttributesPanel');
},

async assertTabIsSelected(tabName: string) {
await testSubjects.existOrFail(`mlNodesOverviewPanel ${tabName}Tab`);
},

async selectTab(tabName: string) {
await testSubjects.click(`mlMemoryUsageTab-${tabName}`);
},

async assertMemoryUsageTabsExist() {
await testSubjects.existOrFail('mlMemoryUsageTabs');
},

async assertMemoryUsageTabIsSelected(tabName: string) {
const isSelected = await testSubjects.getAttribute(
`mlMemoryUsageTab-${tabName}`,
'aria-selected'
);
expect(isSelected).to.eql('true');
},

async assertRowCount(expectedCount: number) {
const rowCount = await this.getRowCount();
expect(rowCount).to.eql(expectedCount);
},

async getAllRows() {
return await testSubjects.findAll('~mlNodesTableRow');
},

async expandRow() {
await testSubjects.click('mlNodesTableRowDetailsToggle');
},

async getRowCount() {
const rows = await this.getAllRows();
return rows.length;
},

async assertColumnHeaderExists(columnName: string) {
await testSubjects.existOrFail(columnName);
},

async assertColumnIsSorted(columnName: string, sortDirection: 'ascending' | 'descending') {
const sorted = await testSubjects.getAttribute(columnName, 'aria-sort');
expect(sorted).to.eql(sortDirection);
},

async sortColumn(columnName: string) {
await this.assertColumnHeaderExists(columnName);
await testSubjects.click(columnName);
},

async assertSearchBarExists() {
await testSubjects.existOrFail('mlNodesTableSearchInput');
},

async searchForNode(nodeId: string) {
await this.assertSearchBarExists();
await testSubjects.setValue('mlNodesTableSearchInput', nodeId);
},

async selectNodeExpandedRowTab(tabName: string) {
await testSubjects.click(tabName);
},

async clearSelectedChartItems() {
await comboBox.clear('~mlJobTreeMap > mlJobTreeMapComboBox');
},

async getSelectedChartItems() {
return await comboBox.getComboBoxSelectedOptions('~mlJobTreeMap > comboBoxInput');
},

async assertChartItemsSelectedByDefault() {
const selectedOptions = await this.getSelectedChartItems();
expect(selectedOptions.length).to.be.greaterThan(0);
},

async assertTreeChartExists() {
await testSubjects.existOrFail('mlJobTreeMap withData');
},

async assertEmptyTreeChartExists() {
await testSubjects.existOrFail('mlJobTreeMap empty');
},
};
}
4 changes: 4 additions & 0 deletions x-pack/test/functional/services/ml/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ export function MachineLearningNavigationProvider({
await this.navigateToArea('~mlMainTab & ~notifications', 'mlPageNotifications');
},

async navigateToMemoryUsage() {
await this.navigateToArea('~mlMainTab & ~nodesOverview', 'mlPageMemoryUsage');
},

async navigateToAnomalyDetection() {
await this.navigateToArea('~mlMainTab & ~anomalyDetection', 'mlPageJobManagement');
},
Expand Down

0 comments on commit 479280c

Please sign in to comment.