mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.16`: - [[ML] Memory usage: Functional tests (#197415)](https://github.com/elastic/kibana/pull/197415) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Robert Jaszczurek","email":"92210485+rbrtj@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-10-25T11:39:38Z","message":"[ML] Memory usage: Functional tests (#197415)\n\n## Summary\r\n\r\nFunctional tests for `memory usage` page in ML.","sha":"479280c0b74747056634421c9b9e05f94a3c7e07","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["non-issue",":ml","release_note:skip","v9.0.0","Team:ML","v8.16.0","backport:version","v8.17.0"],"title":"[ML] Memory usage: Functional tests","number":197415,"url":"https://github.com/elastic/kibana/pull/197415","mergeCommit":{"message":"[ML] Memory usage: Functional tests (#197415)\n\n## Summary\r\n\r\nFunctional tests for `memory usage` page in ML.","sha":"479280c0b74747056634421c9b9e05f94a3c7e07"}},"sourceBranch":"main","suggestedTargetBranches":["8.16","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197415","number":197415,"mergeCommit":{"message":"[ML] Memory usage: Functional tests (#197415)\n\n## Summary\r\n\r\nFunctional tests for `memory usage` page in ML.","sha":"479280c0b74747056634421c9b9e05f94a3c7e07"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com>
This commit is contained in:
parent
b8d7ad76f1
commit
af2cd0c47d
12 changed files with 251 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
|
|
@ -185,6 +185,7 @@ export const NodesList: FC<NodesListProps> = ({ compactView = false }) => {
|
|||
},
|
||||
box: {
|
||||
incremental: true,
|
||||
'data-test-subj': 'mlNodesTableSearchInput',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ export const nodesListRouteFactory = (
|
|||
},
|
||||
],
|
||||
enableDatePicker: true,
|
||||
'data-test-subj': 'mlPageMemoryUsage',
|
||||
});
|
||||
|
||||
const PageWrapper: FC = () => {
|
||||
|
|
20
x-pack/test/functional/apps/ml/memory_usage/config.ts
Normal file
20
x-pack/test/functional/apps/ml/memory_usage/config.ts
Normal file
|
@ -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
x-pack/test/functional/apps/ml/memory_usage/index.ts
Normal file
33
x-pack/test/functional/apps/ml/memory_usage/index.ts
Normal file
|
@ -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'));
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -244,5 +246,6 @@ export function MachineLearningProvider(context: FtrProviderContext) {
|
|||
trainedModelsFlyout,
|
||||
deployDFAModelFlyout,
|
||||
trainedModelsTable,
|
||||
memoryUsage,
|
||||
};
|
||||
}
|
||||
|
|
107
x-pack/test/functional/services/ml/memory_usage.ts
Normal file
107
x-pack/test/functional/services/ml/memory_usage.ts
Normal file
|
@ -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');
|
||||
},
|
||||
};
|
||||
}
|
|
@ -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');
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue