Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Add integration tests for trained_models API #104819

Merged
merged 14 commits into from
Jul 9, 2021
1 change: 1 addition & 0 deletions x-pack/test/api_integration/apis/ml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./results'));
loadTestFile(require.resolve('./saved_objects'));
loadTestFile(require.resolve('./system'));
loadTestFile(require.resolve('./trained_models'));
});
}
67 changes: 67 additions & 0 deletions x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';

export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
const ml = getService('ml');

describe('DELETE trained_models', () => {
before(async () => {
await ml.testResources.setKibanaTimeZoneToUTC();
await ml.api.createdTestTrainedModels('regression', 2);
});

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

it('deletes trained model by id', async () => {
const { body: deleteResponseBody } = await supertest
.delete(`/api/ml/trained_models/dfa_regression_model_n_0`)
peteharverson marked this conversation as resolved.
Show resolved Hide resolved
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);

expect(deleteResponseBody).to.eql({ acknowledged: true });

// verify that model is actually deleted
await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_0`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(404);
});

it('returns 404 if requested trained model does not exist', async () => {
await supertest
.delete(`/api/ml/trained_models/not_existing_model`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(404);
});

it('does not allow to delete trained model if the user does not have required permissions', async () => {
await supertest
.delete(`/api/ml/trained_models/dfa_regression_model_n_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.expect(403);
qn895 marked this conversation as resolved.
Show resolved Hide resolved

// verify that model has not been deleted
await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_1`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);
});
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';

export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
const ml = getService('ml');

describe('GET trained_models/pipelines', () => {
let testModelIds: string[] = [];

before(async () => {
await ml.testResources.setKibanaTimeZoneToUTC();
testModelIds = await ml.api.createdTestTrainedModels('regression', 2, true);
});

after(async () => {
// delete all created ingest pipelines
await Promise.all(testModelIds.map((modelId) => ml.api.deleteIngestPipeline(modelId)));
await ml.api.cleanMlIndices();
});

it('returns trained model pipelines by id', async () => {
const { body } = await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_0/pipelines`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);

expect(body.length).to.eql(1);
expect(body[0].model_id).to.eql('dfa_regression_model_n_0');
expect(Object.keys(body[0].pipelines).length).to.eql(1);
});

it('return an error in case user does not have required permission', async () => {
darnautov marked this conversation as resolved.
Show resolved Hide resolved
await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_0/pipelines`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.expect(403);
});
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';

export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
const ml = getService('ml');

describe('GET trained_models/_stats', () => {
qn895 marked this conversation as resolved.
Show resolved Hide resolved
before(async () => {
await ml.testResources.setKibanaTimeZoneToUTC();
await ml.api.createdTestTrainedModels('regression', 2);
});

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

it('returns trained model stats by id', async () => {
const { body } = await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_0/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);

expect(body.count).to.eql(1);
expect(body.trained_model_stats[0].model_id).to.eql('dfa_regression_model_n_0');
});

it('returns 404 if requested trained model does not exist', async () => {
await supertest
.get(`/api/ml/trained_models/not_existing_model/_stats`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(404);
});

it('return an error for unauthorized user', async () => {
darnautov marked this conversation as resolved.
Show resolved Hide resolved
await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_0/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.expect(403);
});
});
};
88 changes: 88 additions & 0 deletions x-pack/test/api_integration/apis/ml/trained_models/get_models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* 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';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';

export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
const ml = getService('ml');

describe('GET trained_models', () => {
let testModelIds: string[] = [];

before(async () => {
await ml.testResources.setKibanaTimeZoneToUTC();
testModelIds = await ml.api.createdTestTrainedModels('regression', 5, true);
await ml.api.createModelAlias('dfa_regression_model_n_0', 'dfa_regression_model_alias');
await ml.api.createIngestPipeline('dfa_regression_model_alias');
});

after(async () => {
// delete created ingest pipelines
await Promise.all(
['dfa_regression_model_alias', ...testModelIds].map((modelId) =>
ml.api.deleteIngestPipeline(modelId)
)
);
await ml.api.cleanMlIndices();
});

it('returns all trained models with associated pipelines including aliases', async () => {
const { body } = await supertest
.get(`/api/ml/trained_models?with_pipelines=true`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);
// Created models + system model
expect(body.length).to.eql(6);

const sampleModel = body.find((v: any) => v.model_id === 'dfa_regression_model_n_0');
expect(Object.keys(sampleModel.pipelines).length).to.eql(2);
});

it('returns models without pipeline in case user does not have required permission', async () => {
const { body } = await supertest
.get(`/api/ml/trained_models?with_pipelines=true`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);
// Created models + system model
expect(body.length).to.eql(6);
const sampleModel = body.find((v: any) => v.model_id === 'dfa_regression_model_n_0');
expect(sampleModel.pipelines).to.eql(undefined);
});

it('returns trained model by id', async () => {
peteharverson marked this conversation as resolved.
Show resolved Hide resolved
const { body } = await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.expect(200);
expect(body.length).to.eql(1);
expect(body[0].model_id).to.eql('dfa_regression_model_n_1');
});

it('returns 404 if requested trained model does not exist', async () => {
await supertest
.get(`/api/ml/trained_models/not_existing_model`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.expect(404);
});

it('return an error for unauthorized user', async () => {
darnautov marked this conversation as resolved.
Show resolved Hide resolved
await supertest
.get(`/api/ml/trained_models/dfa_regression_model_n_1`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.expect(403);
});
});
};
17 changes: 17 additions & 0 deletions x-pack/test/api_integration/apis/ml/trained_models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 ({ loadTestFile }: FtrProviderContext) {
describe('trained models', function () {
loadTestFile(require.resolve('./get_models'));
loadTestFile(require.resolve('./get_model_stats'));
loadTestFile(require.resolve('./get_model_pipelines'));
loadTestFile(require.resolve('./delete_model'));
});
}
Loading