Prototype of kibana data scenarios

This commit is contained in:
weiwang 2023-02-26 23:47:03 -05:00
parent 8eb73eab9f
commit f1d380c99b
15 changed files with 960 additions and 0 deletions

View file

@ -64,6 +64,9 @@ disabled:
- x-pack/test/plugin_api_perf/config.js
- x-pack/test/screenshot_creation/config.ts
- x-pack/test/fleet_packages/config.ts
- x-pack/test/api_integration/apis/aiops/data_scenarios/config.ts
- x-pack/test/api_integration/apis/ml/data_scenarios/config.ts
- x-pack/test/api_integration/apis/transform/data_scenarios/config.ts
# Scalability testing config that we run in its own pipeline
- x-pack/test/scalability/config.ts

View file

@ -0,0 +1,4 @@
# AIOps Labs API integration tests - Data scenario
Note the tests in this data_scenarios folder are not intended to run on CI.
They need datasets not available within Kibana CI.

View file

@ -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 { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../../config.ts'));
return {
...baseIntegrationTestsConfig.getAll(),
testFiles: [require.resolve('.')],
};
}

View file

@ -0,0 +1,323 @@
/*
* 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 fetch from 'node-fetch';
import { format as formatUrl } from 'url';
import expect from '@kbn/expect';
import { getWindowParameters } from '@kbn/aiops-utils';
import type { ApiExplainLogRateSpikes } from '@kbn/aiops-plugin/common/api';
import type { FtrProviderContext } from '../../../ftr_provider_context';
import { parseStream } from './parse_stream';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const config = getService('config');
const kibanaServerUrl = formatUrl(config.get('servers.kibana'));
const clickTime = 1640097150000;
const minTime = 1640077200000;
const maxTime = 1640112300000;
const { baselineMin, baselineMax, deviationMin, deviationMax } = getWindowParameters(
clickTime,
minTime,
maxTime
);
const requestBody: ApiExplainLogRateSpikes['body'] = {
baselineMax,
baselineMin,
deviationMax,
deviationMin,
start: minTime,
end: maxTime,
index: 'cluster-apm-filebeat-6.8.6-aws-eu-west-1-2021.12.21*',
searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}',
timeFieldName: '@timestamp',
};
const expected = {
chunksLength: 179,
actionsLength: 178,
noIndexChunksLength: 4,
noIndexActionsLength: 3,
changePointFilter: 'add_change_points',
histogramFilter: 'add_change_points_histogram',
errorFilter: 'add_error',
changePointsLength: 47,
changePoints: [
{
fieldName: 'beat.hostname.keyword',
fieldValue: 'ip-172-27-97-204',
doc_count: 12631,
bg_count: 30175,
},
{
fieldName: 'beat.name.keyword',
fieldValue: 'i-0852e3f99b6c512fd',
doc_count: 12631,
bg_count: 30175,
},
{
fieldName: 'docker.container.id.keyword',
fieldValue: 'aa5a7e792e226ccc4f7bbf34dc0e999e17b4f561fd36fbf746365bad5a8112f7',
doc_count: 12629,
bg_count: 30167,
},
{
fieldName: 'docker.container.id.keyword',
fieldValue: 'dc1e531f6598b1f828fc1ccc1939cfc1fceeebd23378fab8f1ba2e8133e53b21',
doc_count: 2220,
bg_count: 4072,
},
{
fieldName: 'docker.container.image.keyword',
fieldValue: 'docker.elastic.co/cloud-assets/apm:7.13.1-0',
doc_count: 2222,
bg_count: 4126,
},
{
fieldName: 'docker.container.image.keyword',
fieldValue: 'docker.elastic.co/cloud-assets/apm:7.9.0-0',
doc_count: 1505,
bg_count: 2166,
},
{
fieldName: 'docker.container.image.keyword',
fieldValue: 'docker.elastic.co/cloud-assets/apm:7.15.2-0',
doc_count: 14777,
bg_count: 37298,
},
{
fieldName: 'docker.container.labels.co.elastic.cloud.allocator.cluster_id.keyword',
fieldValue: 'eb3713439fcd4fdfa60e355f0e57afc0',
doc_count: 12629,
bg_count: 30167,
},
{
fieldName: 'docker.container.labels.co.elastic.cloud.allocator.cluster_id.keyword',
fieldValue: 'ab8b9d3989c54817a1cb4184b2ef6b41',
doc_count: 2295,
bg_count: 3998,
},
{
fieldName: 'docker.container.labels.co.elastic.cloud.allocator.cluster_id.keyword',
fieldValue: '596808a16dec4fc39413bf34b0a70240',
doc_count: 1505,
bg_count: 2166,
},
],
histogramLength: 20,
};
describe('POST /internal/aiops/explain_log_rate_spikes EXTENDED EXAMPLES', () => {
async function requestWithoutStreaming(body: ApiExplainLogRateSpikes['body']) {
const resp = await supertest
.post(`/internal/aiops/explain_log_rate_spikes`)
.set('kbn-xsrf', 'kibana')
.send(body)
.expect(200);
// compression is on by default so if the request body is undefined
// the response header should include "gzip" and otherwise be "undefined"
if (body.compressResponse === undefined) {
expect(resp.header['content-encoding']).to.be('gzip');
} else if (body.compressResponse === false) {
expect(resp.header['content-encoding']).to.be(undefined);
}
expect(Buffer.isBuffer(resp.body)).to.be(true);
const chunks: string[] = resp.body.toString().split('\n');
expect(chunks.length).to.eql(
expected.chunksLength,
`Expected 'chunks.length' to be ${expected.chunksLength}, got ${chunks.length}.`
);
const lastChunk = chunks.pop();
expect(lastChunk).to.eql('', `Expected 'lastChunk' to be empty string, got '${lastChunk}'.`);
let data: any[] = [];
expect(() => {
data = chunks.map((c) => JSON.parse(c));
}).not.to.throwError();
expect(data.length).to.eql(
expected.actionsLength,
`Expected 'data.length' to be ${expected.actionsLength}, got ${data.length}.`
);
data.forEach((d) => {
expect(typeof d.type).to.be('string');
});
const addChangePointsActions = data.filter((d) => d.type === expected.changePointFilter);
expect(addChangePointsActions.length).to.greaterThan(0);
const changePoints = addChangePointsActions
.flatMap((d) => d.payload)
.sort(function (a, b) {
if (a.fieldName === b.fieldName) {
return b.fieldValue - a.fieldValue;
}
return a.fieldName > b.fieldName ? 1 : -1;
});
expect(changePoints.length).to.eql(
expected.changePointsLength,
`Expected 'changePoints.length' to be ${expected.changePointsLength}, got ${changePoints.length}.`
);
// changePoints.forEach((cp, index) => {
// const ecp = expected.changePoints[index];
// expect(cp.fieldName).to.equal(ecp.fieldName);
// expect(cp.fieldValue).to.equal(ecp.fieldValue);
// expect(cp.doc_count).to.equal(ecp.doc_count);
// expect(cp.bg_count).to.equal(ecp.bg_count);
// });
const histogramActions = data.filter((d) => d.type === expected.histogramFilter);
const histograms = histogramActions.flatMap((d) => d.payload);
// for each change point we should get a histogram
expect(histogramActions.length).to.be(changePoints.length);
// each histogram should have a length of 20 items.
histograms.forEach((h, index) => {
expect(h.histogram.length).to.be(20);
});
}
it('should return full data without streaming with compression with flushFix', async () => {
await requestWithoutStreaming(requestBody);
});
it('should return full data without streaming with compression without flushFix', async () => {
await requestWithoutStreaming({ ...requestBody, flushFix: false });
});
it('should return full data without streaming without compression with flushFix', async () => {
await requestWithoutStreaming({ ...requestBody, compressResponse: false });
});
it('should return full data without streaming without compression without flushFix', async () => {
await requestWithoutStreaming({ ...requestBody, compressResponse: false, flushFix: false });
});
async function requestWithStreaming(body: ApiExplainLogRateSpikes['body']) {
const resp = await fetch(`${kibanaServerUrl}/internal/aiops/explain_log_rate_spikes`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'kbn-xsrf': 'stream',
},
body: JSON.stringify(body),
});
// compression is on by default so if the request body is undefined
// the response header should include "gzip" and otherwise be "null"
if (body.compressResponse === undefined) {
expect(resp.headers.get('content-encoding')).to.be('gzip');
} else if (body.compressResponse === false) {
expect(resp.headers.get('content-encoding')).to.be(null);
}
expect(resp.ok).to.be(true);
expect(resp.status).to.be(200);
const stream = resp.body;
expect(stream).not.to.be(null);
if (stream !== null) {
const data: any[] = [];
let chunkCounter = 0;
const parseStreamCallback = (c: number) => (chunkCounter = c);
for await (const action of parseStream(stream, parseStreamCallback)) {
expect(action.type).not.to.be('error');
data.push(action);
}
// If streaming works correctly we should receive more than one chunk.
expect(chunkCounter).to.be.greaterThan(1);
expect(data.length).to.eql(
expected.actionsLength,
`Expected 'data.length' to be ${expected.actionsLength}, got ${data.length}.`
);
const addChangePointsActions = data.filter((d) => d.type === expected.changePointFilter);
expect(addChangePointsActions.length).to.greaterThan(0);
const changePoints = addChangePointsActions
.flatMap((d) => d.payload)
.sort(function (a, b) {
if (a.fieldName === b.fieldName) {
return b.fieldValue - a.fieldValue;
}
return a.fieldName > b.fieldName ? 1 : -1;
});
expect(changePoints.length).to.eql(
expected.changePointsLength,
`Expected 'changePoints.length' to be ${expected.changePointsLength}, got ${changePoints.length}.`
);
// Check only up to 10 changePoints even if there's more
changePoints.slice(0, 9).forEach((cp, index) => {
const ecp = expected.changePoints.find(
(d) => d.fieldName === cp.fieldName && d.fieldValue === cp.fieldValue
);
expect(ecp).not.to.eql(
undefined,
`Expected changePoint width 'fieldName:${cp.fieldName}'/'fieldValue:${cp.fieldValue}' to not be undefined`
);
if (ecp !== undefined) {
expect(cp.doc_count).to.eql(
ecp.doc_count,
`Expected 'doc_count' to be ${ecp.doc_count}, got ${cp.doc_count}.`
);
expect(cp.bg_count).to.eql(
ecp.bg_count,
`Expected 'bg_count' to be ${ecp.bg_count}, got ${cp.bg_count}.`
);
}
});
const histogramActions = data.filter((d) => d.type === expected.histogramFilter);
const histograms = histogramActions.flatMap((d) => d.payload);
// for each change point we should get a histogram
expect(histogramActions.length).to.be(changePoints.length);
// each histogram should have a length of 20 items.
histograms.forEach((h, index) => {
expect(h.histogram.length).to.be(20);
});
}
}
it('should return data in chunks with streaming with compression with flushFix', async () => {
await requestWithStreaming(requestBody);
});
it('should return data in chunks with streaming with compression without flushFix', async () => {
await requestWithStreaming({ ...requestBody, flushFix: false });
});
it('should return data in chunks with streaming without compression with flushFix', async () => {
await requestWithStreaming({ ...requestBody, compressResponse: false });
});
it('should return data in chunks with streaming without compression without flushFix', async () => {
await requestWithStreaming({ ...requestBody, compressResponse: false, flushFix: false });
});
});
};

View 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 { AIOPS_ENABLED } from '@kbn/aiops-plugin/common';
import type { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('AIOps', function () {
this.tags(['aiops']);
if (AIOPS_ENABLED) {
loadTestFile(require.resolve('./explain_log_rate_spikes_extended'));
}
});
}

View file

@ -0,0 +1,37 @@
/*
* 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.
*/
export async function* parseStream(
stream: NodeJS.ReadableStream,
callback?: (chunkCounter: number) => void
) {
let partial = '';
let chunkCounter = 0;
try {
for await (const value of stream) {
chunkCounter++;
const full = `${partial}${value}`;
const parts = full.split('\n');
const last = parts.pop();
partial = last ?? '';
const actions = parts.map((p) => JSON.parse(p));
for (const action of actions) {
yield action;
}
}
} catch (error) {
yield { type: 'error', payload: error.toString() };
}
if (typeof callback === 'function') {
callback(chunkCounter);
}
}

View file

@ -0,0 +1,30 @@
/*
* 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 type { ApiExplainLogRateSpikes } from '@kbn/aiops-plugin/common/api';
import type { ChangePoint, ChangePointGroup } from '@kbn/ml-agg-utils';
export interface TestData {
testName: string;
esArchive?: string;
dataGenerator?: string;
requestBody: ApiExplainLogRateSpikes['body'];
expected: {
chunksLength: number;
actionsLength: number;
noIndexChunksLength: number;
noIndexActionsLength: number;
changePointFilter: 'add_change_points';
groupFilter: 'add_change_point_group';
groupHistogramFilter: 'add_change_point_group_histogram';
histogramFilter: 'add_change_points_histogram';
errorFilter: 'add_error';
changePoints: ChangePoint[];
groups: ChangePointGroup[];
histogramLength: number;
};
}

View file

@ -0,0 +1,4 @@
# ML API integration tests - Data scenario
Note the tests in this data_scenarios folder are not intended to run on CI.
They need datasets not available within Kibana CI.

View file

@ -0,0 +1,59 @@
/*
* 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 esArchiver = getService('esArchiver');
const esSupertest = getService('esSupertest');
const supertest = getService('supertestWithoutAuth');
const ml = getService('ml');
const testDataList = [
{
testTitleSuffix: 'with 1 field, 1 agg, no split',
user: USER.ML_POWERUSER,
requestBody: {
aggTypes: ['sum'],
duration: { start: 1325548800000, end: 1538092800000 },
fields: ['sale_dollars'],
index: 'iowa*',
query: { bool: { must: [{ match_all: {} }] } },
timeField: 'date',
},
expected: {
responseCode: 200,
responseBody: { name: '2d', ms: 172800000 },
},
},
];
describe('bucket span estimator', function () {
before(async () => {
await ml.testResources.setKibanaTimeZoneToUTC();
});
describe('with default settings', function () {
for (const testData of testDataList) {
it(`estimates the bucket span ${testData.testTitleSuffix}`, async () => {
const { body, status } = await supertest
.post('/api/ml/validate/estimate_bucket_span')
.auth(testData.user, ml.securityCommon.getPasswordForUser(testData.user))
.set(COMMON_REQUEST_HEADERS)
.send(testData.requestBody);
ml.api.assertResponseStatusCode(testData.expected.responseCode, status, body);
expect(body).to.eql(testData.expected.responseBody);
});
}
});
});
};

View file

@ -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 { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../../config.ts'));
return {
...baseIntegrationTestsConfig.getAll(),
testFiles: [require.resolve('.')],
};
}

View file

@ -0,0 +1,36 @@
/*
* 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 esArchiver = getService('esArchiver');
const ml = getService('ml');
describe('Machine Learning', function () {
this.tags(['ml']);
before(async () => {
await ml.securityCommon.createMlRoles();
await ml.securityCommon.createMlUsers();
// ML saved objects (e.g. lang_ident_model_1) might have lost the * space
// assignment when privious test suites loaded and unloaded the .kibana index.
// We're making sure that it's in the expected state again.
await ml.api.initSavedObjects();
});
after(async () => {
await ml.securityCommon.cleanMlUsers();
await ml.securityCommon.cleanMlRoles();
await ml.testResources.resetKibanaTimeZone();
});
loadTestFile(require.resolve('./bucket_span_estimator'));
});
}

View file

@ -0,0 +1,5 @@
# Transform API integration tests - Data scenario
Note the tests in this data_scenarios folder are not intended to run on CI.
They need datasets not available within Kibana CI.

View file

@ -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 { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../../config.ts'));
return {
...baseIntegrationTestsConfig.getAll(),
testFiles: [require.resolve('.')],
};
}

View file

@ -0,0 +1,357 @@
/*
* 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 { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/transform/security_common';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
const transform = getService('transform');
const testData = {
user: USER.TRANSFORM_POWERUSER,
requestBody: {
query: { bool: { must: [{ match_all: {} }] } },
"fields": [
{
"fieldName": "bottle_volume_ml",
"type": "number"
},
{
"fieldName": "city",
"type": "string"
},
{
"fieldName": "date",
"type": "date"
}
],
"samplerShardSize": 5000,
},
expected: {
responseCode: 200,
responseBody: [
{
"data": [
{
"key": 0,
"doc_count": 4971
},
{
"key": 471.05263157894734,
"doc_count": 17445
},
{
"key": 942.1052631578947,
"doc_count": 5023
},
{
"key": 1413.157894736842,
"doc_count": 7174
},
{
"key": 1884.2105263157894,
"doc_count": 2
},
{
"key": 2355.2631578947367,
"doc_count": 7
},
{
"key": 2826.315789473684,
"doc_count": 375
},
{
"key": 3297.368421052631,
"doc_count": 0
},
{
"key": 3768.4210526315787,
"doc_count": 0
},
{
"key": 4239.473684210526,
"doc_count": 0
},
{
"key": 4710.526315789473,
"doc_count": 0
},
{
"key": 5181.578947368421,
"doc_count": 0
},
{
"key": 5652.631578947368,
"doc_count": 2
},
{
"key": 6123.684210526316,
"doc_count": 0
},
{
"key": 6594.736842105262,
"doc_count": 0
},
{
"key": 7065.78947368421,
"doc_count": 0
},
{
"key": 7536.8421052631575,
"doc_count": 0
},
{
"key": 8007.894736842105,
"doc_count": 0
},
{
"key": 8478.947368421052,
"doc_count": 0
},
{
"key": 8950,
"doc_count": 1
}
],
"interval": 471.05263157894734,
"stats": [
50,
9000
],
"type": "numeric",
"id": "bottle_volume_ml"
},
{
"type": "ordinal",
"cardinality": 378,
"data": [
{
"key": "des moines",
"doc_count": 3471
},
{
"key": "cedar rapids",
"doc_count": 1907
},
{
"key": "davenport",
"doc_count": 1414
},
{
"key": "sioux city",
"doc_count": 1347
},
{
"key": "council bluffs",
"doc_count": 1184
},
{
"key": "ames",
"doc_count": 1147
},
{
"key": "west des moines",
"doc_count": 996
},
{
"key": "iowa city",
"doc_count": 952
},
{
"key": "waterloo",
"doc_count": 880
},
{
"key": "mason city",
"doc_count": 748
},
{
"key": "dubuque",
"doc_count": 605
},
{
"key": "ankeny",
"doc_count": 577
},
{
"key": "cedar falls",
"doc_count": 571
},
{
"key": "muscatine",
"doc_count": 515
},
{
"key": "coralville",
"doc_count": 465
},
{
"key": "marshalltown",
"doc_count": 399
},
{
"key": "newton",
"doc_count": 378
},
{
"key": "fort dodge",
"doc_count": 339
},
{
"key": "urbandale",
"doc_count": 337
},
{
"key": "clinton",
"doc_count": 313
}
],
"id": "city"
},
{
"data": [
{
"key_as_string": "11/07/2011",
"key": 1320692210526.3157,
"doc_count": 857
},
{
"key_as_string": "03/08/2012",
"key": 1331173894736.842,
"doc_count": 1680
},
{
"key_as_string": "07/07/2012",
"key": 1341655578947.3684,
"doc_count": 1646
},
{
"key_as_string": "11/05/2012",
"key": 1352137263157.8948,
"doc_count": 1689
},
{
"key_as_string": "03/07/2013",
"key": 1362618947368.4211,
"doc_count": 1617
},
{
"key_as_string": "07/06/2013",
"key": 1373100631578.9473,
"doc_count": 1666
},
{
"key_as_string": "11/04/2013",
"key": 1383582315789.4736,
"doc_count": 1670
},
{
"key_as_string": "03/06/2014",
"key": 1394064000000,
"doc_count": 1585
},
{
"key_as_string": "07/05/2014",
"key": 1404545684210.5264,
"doc_count": 1691
},
{
"key_as_string": "11/03/2014",
"key": 1415027368421.0527,
"doc_count": 1760
},
{
"key_as_string": "03/04/2015",
"key": 1425509052631.5789,
"doc_count": 1893
},
{
"key_as_string": "07/04/2015",
"key": 1435990736842.1052,
"doc_count": 1830
},
{
"key_as_string": "11/02/2015",
"key": 1446472421052.6316,
"doc_count": 1076
},
{
"key_as_string": "03/02/2016",
"key": 1456954105263.158,
"doc_count": 1981
},
{
"key_as_string": "07/02/2016",
"key": 1467435789473.684,
"doc_count": 636
},
{
"key_as_string": "10/31/2016",
"key": 1477917473684.2104,
"doc_count": 6086
},
{
"key_as_string": "03/01/2017",
"key": 1488399157894.7368,
"doc_count": 159
},
{
"key_as_string": "07/01/2017",
"key": 1498880842105.2632,
"doc_count": 319
},
{
"key_as_string": "10/30/2017",
"key": 1509362526315.7896,
"doc_count": 2077
},
{
"key_as_string": "02/28/2018",
"key": 1519844210526.3157,
"doc_count": 3082
}
],
"interval": 10481684210.526316,
"stats": [
1325548800000,
1524700800000
],
"type": "numeric",
"id": "date"
}
],
},
};
describe('/api/transform/field_histograms', function () {
before(async () => {
await transform.testResources.setKibanaTimeZoneToUTC();
});
it('should return a field_histograms', async () => {
const { body, status } = await supertest
.post('/api/transform/field_histograms/iowa*')
.auth(
USER.TRANSFORM_POWERUSER,
transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER)
)
.set(COMMON_REQUEST_HEADERS)
.send(testData.requestBody);
transform.api.assertResponseStatusCode(200, status, body);
expect(body).to.eql(testData.expected.responseBody);
});
});
};

View file

@ -0,0 +1,31 @@
/*
* 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 esArchiver = getService('esArchiver');
const transform = getService('transform');
describe('transform', function () {
this.tags(['transform']);
before(async () => {
await transform.securityCommon.createTransformRoles();
await transform.securityCommon.createTransformUsers();
});
after(async () => {
await transform.securityCommon.cleanTransformUsers();
await transform.securityCommon.cleanTransformRoles();
await transform.testResources.resetKibanaTimeZone();
});
loadTestFile(require.resolve('./field_histograms'));
});
}