Skip to content

Commit

Permalink
[ML] Enable Trained models functional tests (elastic#173517)
Browse files Browse the repository at this point in the history
## Summary

Closes elastic#168899
Closes elastic#168492
Closes elastic#156243

Enables Trained models functional tests

### Checklist

- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
(https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4664)

(cherry picked from commit b5cd85c)
  • Loading branch information
darnautov committed Dec 22, 2023
1 parent 84f9679 commit 7da5f63
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const DeploymentSetup: FC<DeploymentSetupProps> = ({
id,
label: id,
value,
'data-test-subj': `mlModelsStartDeploymentModalThreadsPerAllocation_${id}`,
};
}),
[maxSingleMlNodeProcessors]
Expand Down Expand Up @@ -215,6 +216,7 @@ export const DeploymentSetup: FC<DeploymentSetupProps> = ({
defaultMessage: 'low',
}
),
'data-test-subj': 'mlModelsStartDeploymentModalLowPriority',
},
{
id: 'normal',
Expand All @@ -225,6 +227,7 @@ export const DeploymentSetup: FC<DeploymentSetupProps> = ({
defaultMessage: 'normal',
}
),
'data-test-subj': 'mlModelsStartDeploymentModalNormalPriority',
},
]}
data-test-subj={'mlModelsStartDeploymentModalPriority'}
Expand Down
255 changes: 134 additions & 121 deletions x-pack/test/functional/apps/ml/short_tests/model_management/model_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export default function ({ getService }: FtrProviderContext) {
id: model.name,
}));

// FLAKY: https://github.com/elastic/kibana/issues/165084
describe.skip('trained models', function () {
describe('trained models', function () {
// 'Created at' will be different on each run,
// so we will just assert that the value is in the expected timestamp format.
const builtInModelData = {
Expand Down Expand Up @@ -112,12 +111,6 @@ export default function ({ getService }: FtrProviderContext) {
await ml.api.cleanMlIndices();
await ml.api.deleteIndices(modelWithPipelineAndDestIndexExpectedValues.index);

await ml.api.deleteIngestPipeline(modelWithoutPipelineDataExpectedValues.name, false);
await ml.api.deleteIngestPipeline(
modelWithoutPipelineDataExpectedValues.duplicateName,
false
);

// Need to delete index before ingest pipeline, else it will give error
await ml.api.deleteIngestPipeline(modelWithPipelineAndDestIndex.modelId);
await ml.testResources.deleteDataViewByTitle(
Expand Down Expand Up @@ -188,122 +181,141 @@ export default function ({ getService }: FtrProviderContext) {
await ml.trainedModelsTable.assertPipelinesTabContent(false);
});

it('deploys the trained model with default values', async () => {
await ml.testExecution.logTestStep('should display the trained model in the table');
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
await ml.testExecution.logTestStep(
'should show collapsed actions menu for the model in the table'
);
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep('should show deploy action for the model in the table');
await ml.trainedModelsTable.assertModelDeployActionButtonEnabled(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep('should open the deploy model flyout');
await ml.trainedModelsTable.clickDeployAction(modelWithoutPipelineData.modelId);
await ml.testExecution.logTestStep('should complete the deploy model Details step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutDetails({
name: modelWithoutPipelineDataExpectedValues.name,
description: modelWithoutPipelineDataExpectedValues.description,
// If no metadata is provided, the target field will default to empty string
targetField: '',
// FLAKY: https://github.com/elastic/kibana/issues/165084
describe.skip('DFA model deployment', () => {
after(async () => {
await ml.api.deleteIngestPipeline(modelWithoutPipelineDataExpectedValues.name, false);
await ml.api.deleteIngestPipeline(
modelWithoutPipelineDataExpectedValues.duplicateName,
false
);
});
await ml.testExecution.logTestStep('should complete the deploy model Pipeline Config step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutPipelineConfig({
inferenceConfig: modelWithoutPipelineDataExpectedValues.inferenceConfig,
fieldMap: modelWithoutPipelineDataExpectedValues.fieldMap,
});
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline On Failure step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutOnFailure(
getDefaultOnFailureConfiguration()
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline Create pipeline step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutCreateStep({
description: modelWithoutPipelineDataExpectedValues.description,
processors: [
{
inference: {
model_id: modelWithoutPipelineData.modelId,
ignore_failure: false,
inference_config: modelWithoutPipelineDataExpectedValues.inferenceConfig,
on_failure: getDefaultOnFailureConfiguration(),
},
},
],
});
});

it('deploys the trained model with custom values', async () => {
await ml.testExecution.logTestStep('should display the trained model in the table');
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
await ml.testExecution.logTestStep(
'should not show collapsed actions menu for the model in the table'
);
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep('should show deploy action for the model in the table');
await ml.trainedModelsTable.assertModelDeployActionButtonExists(
modelWithoutPipelineData.modelId,
false
);
await ml.testExecution.logTestStep('should open the deploy model flyout');
await ml.trainedModelsTable.clickDeployAction(modelWithoutPipelineData.modelId);
await ml.testExecution.logTestStep('should complete the deploy model Details step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutDetails(
{
name: modelWithoutPipelineDataExpectedValues.duplicateName,
description: modelWithoutPipelineDataExpectedValues.duplicateDescription,
targetField: 'myTargetField',
},
true
);
await ml.testExecution.logTestStep('should complete the deploy model Pipeline Config step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutPipelineConfig(
{
it.skip('deploys the trained model with default values', async () => {
await ml.testExecution.logTestStep('should display the trained model in the table');
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
await ml.testExecution.logTestStep(
'should show collapsed actions menu for the model in the table'
);
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep(
'should show deploy action for the model in the table'
);
await ml.trainedModelsTable.assertModelDeployActionButtonEnabled(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep('should open the deploy model flyout');
await ml.trainedModelsTable.clickDeployAction(modelWithoutPipelineData.modelId);
await ml.testExecution.logTestStep('should complete the deploy model Details step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutDetails({
name: modelWithoutPipelineDataExpectedValues.name,
description: modelWithoutPipelineDataExpectedValues.description,
// If no metadata is provided, the target field will default to empty string
targetField: '',
});
await ml.testExecution.logTestStep(
'should complete the deploy model Pipeline Config step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutPipelineConfig({
inferenceConfig: modelWithoutPipelineDataExpectedValues.inferenceConfig,
editedInferenceConfig: modelWithoutPipelineDataExpectedValues.editedInferenceConfig,
fieldMap: modelWithoutPipelineDataExpectedValues.fieldMap,
editedFieldMap: modelWithoutPipelineDataExpectedValues.editedFieldMap,
},
true
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline On Failure step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutOnFailure(
getDefaultOnFailureConfiguration(),
true
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline Create pipeline step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutCreateStep({
description: modelWithoutPipelineDataExpectedValues.duplicateDescription,
processors: [
{
inference: {
field_map: {
incoming_field: 'old_field',
});
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline On Failure step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutOnFailure(
getDefaultOnFailureConfiguration()
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline Create pipeline step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutCreateStep({
description: modelWithoutPipelineDataExpectedValues.description,
processors: [
{
inference: {
model_id: modelWithoutPipelineData.modelId,
ignore_failure: false,
inference_config: modelWithoutPipelineDataExpectedValues.inferenceConfig,
on_failure: getDefaultOnFailureConfiguration(),
},
ignore_failure: true,
if: "ctx?.network?.name == 'Guest'",
model_id: modelWithoutPipelineData.modelId,
inference_config: modelWithoutPipelineDataExpectedValues.inferenceConfigDuplicate,
tag: 'tag',
target_field: 'myTargetField',
},
],
});
});

it.skip('deploys the trained model with custom values', async () => {
await ml.testExecution.logTestStep('should display the trained model in the table');
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
await ml.testExecution.logTestStep(
'should not show collapsed actions menu for the model in the table'
);
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
modelWithoutPipelineData.modelId,
true
);
await ml.testExecution.logTestStep(
'should show deploy action for the model in the table'
);
await ml.trainedModelsTable.assertModelDeployActionButtonExists(
modelWithoutPipelineData.modelId,
false
);
await ml.testExecution.logTestStep('should open the deploy model flyout');
await ml.trainedModelsTable.clickDeployAction(modelWithoutPipelineData.modelId);
await ml.testExecution.logTestStep('should complete the deploy model Details step');
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutDetails(
{
name: modelWithoutPipelineDataExpectedValues.duplicateName,
description: modelWithoutPipelineDataExpectedValues.duplicateDescription,
targetField: 'myTargetField',
},
true
);
await ml.testExecution.logTestStep(
'should complete the deploy model Pipeline Config step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutPipelineConfig(
{
inferenceConfig: modelWithoutPipelineDataExpectedValues.inferenceConfig,
editedInferenceConfig: modelWithoutPipelineDataExpectedValues.editedInferenceConfig,
fieldMap: modelWithoutPipelineDataExpectedValues.fieldMap,
editedFieldMap: modelWithoutPipelineDataExpectedValues.editedFieldMap,
},
],
true
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline On Failure step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutOnFailure(
getDefaultOnFailureConfiguration(),
true
);
await ml.testExecution.logTestStep(
'should complete the deploy model pipeline Create pipeline step'
);
await ml.deployDFAModelFlyout.completeTrainedModelsInferenceFlyoutCreateStep({
description: modelWithoutPipelineDataExpectedValues.duplicateDescription,
processors: [
{
inference: {
field_map: {
incoming_field: 'old_field',
},
ignore_failure: true,
if: "ctx?.network?.name == 'Guest'",
model_id: modelWithoutPipelineData.modelId,
inference_config: modelWithoutPipelineDataExpectedValues.inferenceConfigDuplicate,
tag: 'tag',
target_field: 'myTargetField',
},
},
],
});
});
});

Expand Down Expand Up @@ -418,7 +430,7 @@ export default function ({ getService }: FtrProviderContext) {
);
});

it('navigates to data drift', async () => {
it.skip('navigates to data drift', async () => {
await ml.testExecution.logTestStep('should show the model map in the expanded row');
await ml.trainedModelsTable.ensureRowIsExpanded(modelWithPipelineAndDestIndex.modelId);
await ml.trainedModelsTable.assertModelsMapTabContent();
Expand Down Expand Up @@ -450,8 +462,7 @@ export default function ({ getService }: FtrProviderContext) {
await ml.navigation.navigateToTrainedModels();
});

// FLAKY: https://github.com/elastic/kibana/issues/168899
describe.skip('with imported models', function () {
describe('with imported models', function () {
before(async () => {
await ml.navigation.navigateToTrainedModels();
});
Expand All @@ -475,8 +486,10 @@ export default function ({ getService }: FtrProviderContext) {
});

it(`stops deployment of the imported model ${model.id}`, async () => {
// Wait for the model to be deployed before stopping it.
await ml.testExecution.logTestStep('should have a Deployed state');
await ml.trainedModelsTable.assertModelState(model.id, 'Deployed');
await ml.trainedModelsTable.stopDeployment(model.id);
await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled(model.id, true);
});

it(`deletes the imported model ${model.id}`, async () => {
Expand Down
14 changes: 10 additions & 4 deletions x-pack/test/functional/services/ml/common_ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,21 @@ export function MachineLearningCommonUIProvider({
});
},

async selectButtonGroupValue(inputTestSubj: string, value: string) {
async selectButtonGroupValue(inputTestSubj: string, value: string, valueTestSubj?: string) {
await retry.tryForTime(5000, async () => {
// The input element can not be clicked directly.
// Instead, we need to click the corresponding label

const fieldSetElement = await testSubjects.find(inputTestSubj);
let labelElement: WebElementWrapper;

const labelElement = await fieldSetElement.findByCssSelector(`label[title="${value}"]`);
await labelElement.click();
if (valueTestSubj) {
await testSubjects.click(valueTestSubj);
labelElement = await testSubjects.find(valueTestSubj);
} else {
const fieldSetElement = await testSubjects.find(inputTestSubj);
labelElement = await fieldSetElement.findByCssSelector(`label[title="${value}"]`);
await labelElement.click();
}

const labelClasses = await labelElement.getAttribute('class');
expect(labelClasses).to.contain(
Expand Down
Loading

0 comments on commit 7da5f63

Please sign in to comment.