mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ML] reset_jobs api tests (#150880)
Adds tests for the `reset_jobs` endpoint. What's tested: - jobs are reset and the processed records counts are correct reduced to 0 - User annotations are correctly deleted after reset, if the endpoint is told to do so.
This commit is contained in:
parent
fe4239abe0
commit
67f01ed27d
3 changed files with 158 additions and 0 deletions
|
@ -24,5 +24,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./stop_datafeeds_spaces'));
|
||||
loadTestFile(require.resolve('./get_groups'));
|
||||
loadTestFile(require.resolve('./jobs'));
|
||||
loadTestFile(require.resolve('./reset'));
|
||||
});
|
||||
}
|
||||
|
|
136
x-pack/test/api_integration/apis/ml/jobs/reset.ts
Normal file
136
x-pack/test/api_integration/apis/ml/jobs/reset.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 { ANNOTATION_TYPE } from '@kbn/ml-plugin/common/constants/annotations';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
|
||||
import { USER } from '../../../../functional/services/ml/security_common';
|
||||
import { MULTI_METRIC_JOB_CONFIG, SINGLE_METRIC_JOB_CONFIG, DATAFEED_CONFIG } from './common_jobs';
|
||||
|
||||
export default ({ getService }: FtrProviderContext) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const supertest = getService('supertestWithoutAuth');
|
||||
const ml = getService('ml');
|
||||
|
||||
const testSetupJobConfigs = [SINGLE_METRIC_JOB_CONFIG, MULTI_METRIC_JOB_CONFIG];
|
||||
|
||||
async function runResetJobsRequest(
|
||||
user: USER,
|
||||
requestBody: object,
|
||||
expectedResponsecode: number
|
||||
): Promise<any> {
|
||||
const { body, status } = await supertest
|
||||
.post('/api/ml/jobs/reset_jobs')
|
||||
.auth(user, ml.securityCommon.getPasswordForUser(user))
|
||||
.set(COMMON_REQUEST_HEADERS)
|
||||
.send(requestBody);
|
||||
ml.api.assertResponseStatusCode(expectedResponsecode, status, body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
async function createAnnotation(jobId: string, annotation: string) {
|
||||
await ml.api.indexAnnotation({
|
||||
timestamp: 1549756524346,
|
||||
end_timestamp: 1549766472273,
|
||||
annotation,
|
||||
job_id: jobId,
|
||||
type: ANNOTATION_TYPE.ANNOTATION,
|
||||
detector_index: 0,
|
||||
event: 'user',
|
||||
});
|
||||
}
|
||||
|
||||
const expectedResetResponseBody = {
|
||||
[SINGLE_METRIC_JOB_CONFIG.job_id]: { reset: true, task: 'cannot be predicted' },
|
||||
[MULTI_METRIC_JOB_CONFIG.job_id]: { reset: true, task: 'cannot be predicted' },
|
||||
};
|
||||
|
||||
describe('reset_jobs', function () {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote');
|
||||
await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp');
|
||||
await ml.testResources.setKibanaTimeZoneToUTC();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.testResources.deleteIndexPatternByTitle('ft_farequote');
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
for (const job of testSetupJobConfigs) {
|
||||
const jobId = job.job_id;
|
||||
const datafeedId = `datafeed-${jobId}`;
|
||||
await ml.api.createAndRunAnomalyDetectionLookbackJob(job, {
|
||||
...DATAFEED_CONFIG,
|
||||
datafeed_id: datafeedId,
|
||||
job_id: jobId,
|
||||
});
|
||||
|
||||
await createAnnotation(jobId, 'test test test');
|
||||
await ml.api.assertAnnotationsCount(jobId, 2);
|
||||
await ml.api.waitForADJobRecordCount(jobId, 86274);
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
for (const job of testSetupJobConfigs) {
|
||||
await ml.api.deleteAnomalyDetectionJobES(job.job_id);
|
||||
}
|
||||
await ml.api.cleanMlIndices();
|
||||
});
|
||||
|
||||
it('succeeds for ML Poweruser and keeps user annotations', async () => {
|
||||
const jobIds = testSetupJobConfigs.map((c) => c.job_id);
|
||||
const body = await runResetJobsRequest(USER.ML_POWERUSER, { jobIds }, 200);
|
||||
|
||||
const expectedRspJobIds = Object.keys(expectedResetResponseBody).sort((a, b) =>
|
||||
a.localeCompare(b)
|
||||
);
|
||||
const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b));
|
||||
expect(actualRspJobIds).to.eql(expectedRspJobIds);
|
||||
|
||||
for (const id of jobIds) {
|
||||
expect(body[id].reset).to.eql(expectedResetResponseBody[id].reset);
|
||||
// processed record counts are reset to 0
|
||||
await ml.api.waitForADJobRecordCount(id, 0);
|
||||
// user annotations are not deleted
|
||||
await ml.api.assertAnnotationsCount(id, 1);
|
||||
}
|
||||
});
|
||||
|
||||
it('succeeds for ML Poweruser and deletes user annotations', async () => {
|
||||
const jobIds = testSetupJobConfigs.map((c) => c.job_id);
|
||||
const body = await runResetJobsRequest(
|
||||
USER.ML_POWERUSER,
|
||||
{ jobIds, deleteUserAnnotations: true },
|
||||
200
|
||||
);
|
||||
|
||||
const expectedRspJobIds = Object.keys(expectedResetResponseBody).sort((a, b) =>
|
||||
a.localeCompare(b)
|
||||
);
|
||||
const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b));
|
||||
expect(actualRspJobIds).to.eql(expectedRspJobIds);
|
||||
|
||||
for (const id of jobIds) {
|
||||
expect(body[id].reset).to.eql(expectedResetResponseBody[id].reset);
|
||||
// processed record counts are reset to 0
|
||||
await ml.api.waitForADJobRecordCount(id, 0);
|
||||
// user annotations are deleted
|
||||
await ml.api.assertAnnotationsCount(id, 0);
|
||||
}
|
||||
});
|
||||
|
||||
it('fails for ML viewer', async () => {
|
||||
const jobIds = testSetupJobConfigs.map((c) => c.job_id);
|
||||
await runResetJobsRequest(USER.ML_VIEWER, { jobIds }, 403);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -986,6 +986,27 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) {
|
|||
);
|
||||
},
|
||||
|
||||
async waitForADJobRecordCount(
|
||||
jobId: string,
|
||||
expectedCount: number,
|
||||
timeout: number = 2 * 60 * 1000
|
||||
) {
|
||||
await retry.waitForWithTimeout(
|
||||
`job ${jobId} record count to be ${expectedCount}`,
|
||||
timeout,
|
||||
async () => {
|
||||
const count = await this.getADJobRecordCount(jobId);
|
||||
if (count === expectedCount) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
`expected job ${jobId} record count to be ${expectedCount} but got ${count}`
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
async getFilter(filterId: string, expectedCode = 200) {
|
||||
const response = await esSupertest.get(`/_ml/filters/${filterId}`);
|
||||
this.assertResponseStatusCode(expectedCode, response.status, response.body);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue