Skip to content

Commit

Permalink
[ML] api integration tests for get anomaly detectors (#65828) (#66002)
Browse files Browse the repository at this point in the history
  • Loading branch information
darnautov authored May 11, 2020
1 parent aaa30ad commit 96b073c
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 0 deletions.
222 changes: 222 additions & 0 deletions x-pack/test/api_integration/apis/ml/anomaly_detectors/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/machine_learning/security_common';

const COMMON_HEADERS = {
'kbn-xsrf': 'some-xsrf-token',
};

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

const jobId = `fq_single_${Date.now()}`;

async function createJobs() {
const mockJobConfigs = [
{
job_id: `${jobId}_1`,
description:
'Single metric job based on the farequote dataset with 30m bucketspan and mean(responsetime)',
groups: ['automated', 'farequote', 'single-metric'],
analysis_config: {
bucket_span: '30m',
detectors: [{ function: 'mean', field_name: 'responsetime' }],
influencers: [],
summary_count_field_name: 'doc_count',
},
data_description: { time_field: '@timestamp' },
analysis_limits: { model_memory_limit: '11MB' },
model_plot_config: { enabled: true },
},
{
job_id: `${jobId}_2`,
description:
'Another single metric job based on the farequote dataset with 30m bucketspan and mean(responsetime)',
groups: ['automated', 'farequote', 'single-metric'],
analysis_config: {
bucket_span: '30m',
detectors: [{ function: 'mean', field_name: 'responsetime' }],
influencers: [],
summary_count_field_name: 'doc_count',
},
data_description: { time_field: '@timestamp' },
analysis_limits: { model_memory_limit: '11MB' },
model_plot_config: { enabled: false },
},
];

for (const jobConfig of mockJobConfigs) {
await ml.api.createAnomalyDetectionJob(jobConfig);
}
}

describe('GET anomaly_detectors', () => {
before(async () => {
await esArchiver.loadIfNeeded('ml/farequote');
await ml.testResources.setKibanaTimeZoneToUTC();

await createJobs();
});

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

describe('GetAnomalyDetectors', () => {
it('should fetch all anomaly detector jobs', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(2);
expect(body.jobs.length).to.eql(2);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
});

it('should not allow to retrieve jobs for the user without required permissions', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_HEADERS)
.expect(404);

expect(body.error).to.eql('Not Found');
expect(body.message).to.eql('Not Found');
});
});

describe('GetAnomalyDetectorsById', () => {
it('should fetch single anomaly detector job by id', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(1);
expect(body.jobs.length).to.eql(1);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
});

it('should fetch anomaly detector jobs based on provided ids', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(2);
expect(body.jobs.length).to.eql(2);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
});

it('should not allow to retrieve a job for the user without required permissions', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_HEADERS)
.expect(404);

expect(body.error).to.eql('Not Found');
expect(body.message).to.eql('Not Found');
});
});

describe('GetAnomalyDetectorsStats', () => {
it('should fetch jobs stats', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(2);
expect(body.jobs.length).to.eql(2);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
expect(body.jobs[0]).to.keys(
'timing_stats',
'state',
'forecasts_stats',
'model_size_stats',
'data_counts'
);
expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
});

it('should not allow to retrieve jobs stats for the user without required permissions', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_HEADERS)
.expect(404);

expect(body.error).to.eql('Not Found');
expect(body.message).to.eql('Not Found');
});
});

describe('GetAnomalyDetectorsStatsById', () => {
it('should fetch single job stats', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(1);
expect(body.jobs.length).to.eql(1);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
expect(body.jobs[0]).to.keys(
'timing_stats',
'state',
'forecasts_stats',
'model_size_stats',
'data_counts'
);
});

it('should fetch multiple jobs stats based on provided ids', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_HEADERS)
.expect(200);

expect(body.count).to.eql(2);
expect(body.jobs.length).to.eql(2);
expect(body.jobs[0].job_id).to.eql(`${jobId}_1`);
expect(body.jobs[0]).to.keys(
'timing_stats',
'state',
'forecasts_stats',
'model_size_stats',
'data_counts'
);
expect(body.jobs[1].job_id).to.eql(`${jobId}_2`);
});

it('should not allow to retrieve a job stats for the user without required permissions', async () => {
const { body } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_HEADERS)
.expect(404);

expect(body.error).to.eql('Not Found');
expect(body.message).to.eql('Not Found');
});
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
export default function({ loadTestFile }: FtrProviderContext) {
describe('anomaly detectors', function() {
loadTestFile(require.resolve('./create'));
loadTestFile(require.resolve('./get'));
});
}

0 comments on commit 96b073c

Please sign in to comment.