mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[SLO] api integration tests stateful (#173236)
## Summary Adds tests for basic SLO api routes, including: 1. Find slos 2. Get slo by id 3. Get slo definitions 4. Get slo instances 5. Create slo 6. Delete slo 7. Update slo 8. Reset slo The create slo tests include some basic assertions that the resulting calculated SLO is correct. These tests do not cover: 1. SLOs in spaces 2. SLO permissions model Passed flaky test runner for 200 iterations: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4595#_ --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: shahzad31 <shahzad31comp@gmail.com> Co-authored-by: Kevin Delemme <kdelemme@gmail.com>
This commit is contained in:
parent
5d55ab930c
commit
96bfb638ed
16 changed files with 1942 additions and 2 deletions
|
@ -214,6 +214,7 @@ enabled:
|
|||
- x-pack/test/api_integration/apis/stats/config.ts
|
||||
- x-pack/test/api_integration/apis/status/config.ts
|
||||
- x-pack/test/api_integration/apis/synthetics/config.ts
|
||||
- x-pack/test/api_integration/apis/slos/config.ts
|
||||
- x-pack/test/api_integration/apis/telemetry/config.ts
|
||||
- x-pack/test/api_integration/apis/transform/config.ts
|
||||
- x-pack/test/api_integration/apis/upgrade_assistant/config.ts
|
||||
|
@ -515,4 +516,4 @@ enabled:
|
|||
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_read/configs/serverless.config.ts
|
||||
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_read/configs/ess.config.ts
|
||||
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_bulk_actions/configs/ess.config.ts
|
||||
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_bulk_actions/configs/serverless.config.ts
|
||||
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_bulk_actions/configs/serverless.config.ts
|
|
@ -21,6 +21,19 @@ const generateNetworkData = lodash.memoize(() => {
|
|||
return networkDataCount;
|
||||
});
|
||||
|
||||
let currentStatic = 0;
|
||||
|
||||
const staticBetween = (end = 1, step = 0.1) => {
|
||||
{
|
||||
if (currentStatic + step > end) {
|
||||
currentStatic = 0;
|
||||
} else {
|
||||
currentStatic = currentStatic + step;
|
||||
}
|
||||
return currentStatic;
|
||||
}
|
||||
};
|
||||
|
||||
export const generateEvent = (index: number, timestamp: Moment, interval: number) => {
|
||||
const groupIndex = createGroupIndex(index);
|
||||
return [
|
||||
|
@ -142,13 +155,14 @@ export const generateEvent = (index: number, timestamp: Moment, interval: number
|
|||
},
|
||||
},
|
||||
user: {
|
||||
pct: randomBetween(1, 4),
|
||||
pct: staticBetween(1, 1),
|
||||
},
|
||||
system: {
|
||||
pct: randomBetween(1, 4),
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: [`${randomBetween(1, 4, 1)}`],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
|
29
x-pack/test/api_integration/apis/slos/config.ts
Normal file
29
x-pack/test/api_integration/apis/slos/config.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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('.')],
|
||||
// overriding default timeouts from packages/kbn-test/src/functional_test_runner/lib/config/schema.ts
|
||||
// so we can easily adjust them for serverless where needed
|
||||
timeouts: {
|
||||
find: 10 * 1000,
|
||||
try: 120 * 1000,
|
||||
waitFor: 20 * 1000,
|
||||
esRequestTimeout: 30 * 1000,
|
||||
kibanaReportCompletion: 60 * 1000,
|
||||
kibanaStabilize: 15 * 1000,
|
||||
navigateStatusPageCheck: 250,
|
||||
waitForExists: 2500,
|
||||
},
|
||||
};
|
||||
}
|
273
x-pack/test/api_integration/apis/slos/create_slo.ts
Normal file
273
x-pack/test/api_integration/apis/slos/create_slo.ts
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* 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 type { CreateSLOInput } from '@kbn/slo-schema';
|
||||
import { SO_SLO_TYPE } from '@kbn/observability-plugin/server/saved_objects';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { sloData } from './fixtures/create_slo';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('Create SLOs', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const slo = getService('slo');
|
||||
|
||||
let createSLOInput: CreateSLOInput;
|
||||
|
||||
before(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
createSLOInput = sloData;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
it('creates a new slo and transforms', async () => {
|
||||
const apiResponse = await supertestAPI
|
||||
.post('/api/observability/slos')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('x-elastic-internal-origin', 'foo')
|
||||
.send(createSLOInput)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).property('id');
|
||||
|
||||
const { id } = apiResponse.body;
|
||||
|
||||
const savedObject = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
expect(savedObject.saved_objects.length).eql(1);
|
||||
|
||||
expect(savedObject.saved_objects[0].attributes).eql({
|
||||
budgetingMethod: 'occurrences',
|
||||
updatedAt: savedObject.saved_objects[0].attributes.updatedAt,
|
||||
createdAt: savedObject.saved_objects[0].attributes.createdAt,
|
||||
description: 'Fixture for api integration tests',
|
||||
enabled: true,
|
||||
groupBy: 'tags',
|
||||
id,
|
||||
indicator: {
|
||||
params: {
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
index: 'kbn-data-forge*',
|
||||
timestampField: '@timestamp',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
},
|
||||
type: 'sli.kql.custom',
|
||||
},
|
||||
name: 'Test SLO for api integration',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
},
|
||||
revision: 1,
|
||||
settings: {
|
||||
frequency: '1m',
|
||||
syncDelay: '1m',
|
||||
},
|
||||
tags: ['test'],
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
version: 2,
|
||||
});
|
||||
|
||||
const rollUpTransformResponse = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect roll up transform to be created
|
||||
expect(rollUpTransformResponse.body).eql({
|
||||
count: 1,
|
||||
transforms: [
|
||||
{
|
||||
id: `slo-${id}-1`,
|
||||
authorization: { roles: ['superuser'] },
|
||||
version: '10.0.0',
|
||||
create_time: rollUpTransformResponse.body.transforms[0].create_time,
|
||||
source: {
|
||||
index: ['kbn-data-forge*'],
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{ range: { '@timestamp': { gte: 'now-7d/d' } } },
|
||||
{
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
match: {
|
||||
'system.network.name': 'eth1',
|
||||
},
|
||||
},
|
||||
],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime_mappings: {
|
||||
'slo.id': {
|
||||
type: 'keyword',
|
||||
script: { source: `emit('${id}')` },
|
||||
},
|
||||
'slo.revision': { type: 'long', script: { source: 'emit(1)' } },
|
||||
},
|
||||
},
|
||||
dest: {
|
||||
index: '.slo-observability.sli-v3',
|
||||
pipeline: '.slo-observability.sli.pipeline-v3',
|
||||
},
|
||||
frequency: '1m',
|
||||
sync: { time: { field: '@timestamp', delay: '1m' } },
|
||||
pivot: {
|
||||
group_by: {
|
||||
'slo.id': { terms: { field: 'slo.id' } },
|
||||
'slo.revision': { terms: { field: 'slo.revision' } },
|
||||
'slo.instanceId': { terms: { field: 'tags' } },
|
||||
'slo.groupings.tags': { terms: { field: 'tags' } },
|
||||
'@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } },
|
||||
},
|
||||
aggregations: {
|
||||
'slo.numerator': {
|
||||
filter: {
|
||||
bool: {
|
||||
should: [{ range: { 'container.cpu.user.pct': { lt: '1' } } }],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
'slo.denominator': {
|
||||
filter: {
|
||||
bool: {
|
||||
should: [{ exists: { field: 'container.cpu.user.pct' } }],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
description: `Rolled-up SLI data for SLO: Test SLO for api integration [id: ${id}, revision: 1]`,
|
||||
settings: { deduce_mappings: false, unattended: true },
|
||||
_meta: { version: 3, managed: true, managed_by: 'observability' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const summaryTransform = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect summary transform to be created
|
||||
expect(summaryTransform.body).eql({
|
||||
count: 1,
|
||||
transforms: [
|
||||
{
|
||||
id: `slo-summary-${id}-1`,
|
||||
authorization: { roles: ['superuser'] },
|
||||
version: '10.0.0',
|
||||
create_time: summaryTransform.body.transforms[0].create_time,
|
||||
source: {
|
||||
index: ['.slo-observability.sli-v3*'],
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{ range: { '@timestamp': { gte: 'now-7d/m', lte: 'now/m' } } },
|
||||
{ term: { 'slo.id': id } },
|
||||
{ term: { 'slo.revision': 1 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
dest: {
|
||||
index: '.slo-observability.summary-v3',
|
||||
pipeline: `.slo-observability.summary.pipeline-${id}-1`,
|
||||
},
|
||||
frequency: '1m',
|
||||
sync: { time: { field: 'event.ingested', delay: '65s' } },
|
||||
pivot: {
|
||||
group_by: {
|
||||
'slo.id': { terms: { field: 'slo.id' } },
|
||||
'slo.revision': { terms: { field: 'slo.revision' } },
|
||||
'slo.instanceId': { terms: { field: 'slo.instanceId' } },
|
||||
'slo.groupings.tags': {
|
||||
terms: { field: 'slo.groupings.tags' },
|
||||
},
|
||||
'service.name': { terms: { field: 'service.name', missing_bucket: true } },
|
||||
'service.environment': {
|
||||
terms: { field: 'service.environment', missing_bucket: true },
|
||||
},
|
||||
'transaction.name': { terms: { field: 'transaction.name', missing_bucket: true } },
|
||||
'transaction.type': { terms: { field: 'transaction.type', missing_bucket: true } },
|
||||
},
|
||||
aggregations: {
|
||||
goodEvents: { sum: { field: 'slo.numerator' } },
|
||||
totalEvents: { sum: { field: 'slo.denominator' } },
|
||||
sliValue: {
|
||||
bucket_script: {
|
||||
buckets_path: { goodEvents: 'goodEvents', totalEvents: 'totalEvents' },
|
||||
script:
|
||||
'if (params.totalEvents == 0) { return -1 } else if (params.goodEvents >= params.totalEvents) { return 1 } else { return params.goodEvents / params.totalEvents }',
|
||||
},
|
||||
},
|
||||
errorBudgetInitial: { bucket_script: { buckets_path: {}, script: '1 - 0.99' } },
|
||||
errorBudgetConsumed: {
|
||||
bucket_script: {
|
||||
buckets_path: {
|
||||
sliValue: 'sliValue',
|
||||
errorBudgetInitial: 'errorBudgetInitial',
|
||||
},
|
||||
script:
|
||||
'if (params.sliValue == -1) { return 0 } else { return (1 - params.sliValue) / params.errorBudgetInitial }',
|
||||
},
|
||||
},
|
||||
errorBudgetRemaining: {
|
||||
bucket_script: {
|
||||
buckets_path: { errorBudgetConsumed: 'errorBudgetConsumed' },
|
||||
script: '1 - params.errorBudgetConsumed',
|
||||
},
|
||||
},
|
||||
statusCode: {
|
||||
bucket_script: {
|
||||
buckets_path: {
|
||||
sliValue: 'sliValue',
|
||||
errorBudgetRemaining: 'errorBudgetRemaining',
|
||||
},
|
||||
script: {
|
||||
source:
|
||||
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= 0.99) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
|
||||
},
|
||||
},
|
||||
},
|
||||
latestSliTimestamp: { max: { field: '@timestamp' } },
|
||||
},
|
||||
},
|
||||
description: `Summarise the rollup data of SLO: Test SLO for api integration [id: ${id}, revision: 1].`,
|
||||
settings: { deduce_mappings: false, unattended: true },
|
||||
_meta: { version: 3, managed: true, managed_by: 'observability' },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
130
x-pack/test/api_integration/apis/slos/delete_slo.ts
Normal file
130
x-pack/test/api_integration/apis/slos/delete_slo.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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 { cleanup } from '@kbn/infra-forge';
|
||||
import expect from '@kbn/expect';
|
||||
import type { CreateSLOInput } from '@kbn/slo-schema';
|
||||
import { SO_SLO_TYPE } from '@kbn/observability-plugin/server/saved_objects';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { sloData } from './fixtures/create_slo';
|
||||
import { loadTestData } from './helper/load_test_data';
|
||||
import { SloEsClient } from './helper/es';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('Delete SLOs', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esClient = getService('es');
|
||||
const logger = getService('log');
|
||||
const slo = getService('slo');
|
||||
const retry = getService('retry');
|
||||
const sloEsClient = new SloEsClient(esClient);
|
||||
|
||||
let createSLOInput: CreateSLOInput;
|
||||
|
||||
before(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
loadTestData(getService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
createSLOInput = sloData;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await cleanup({ esClient, logger });
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
});
|
||||
|
||||
it('deletes new slo saved object and transforms', async () => {
|
||||
const id = await slo.create(createSLOInput);
|
||||
|
||||
const savedObject = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
expect(savedObject.saved_objects.length).eql(1);
|
||||
|
||||
expect(savedObject.saved_objects[0].attributes.id).eql(id);
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
// expect summary and rollup data to exist
|
||||
const sloSummaryResponse = await sloEsClient.getSLOSummaryDataById(id);
|
||||
const sloRollupResponse = await sloEsClient.getSLORollupDataById(id);
|
||||
|
||||
expect(sloSummaryResponse.hits.hits.length > 0).eql(true);
|
||||
expect(sloRollupResponse.hits.hits.length > 0).eql(true);
|
||||
|
||||
const rollUpTransformResponse = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect roll up transform to be created
|
||||
expect(rollUpTransformResponse.body.transforms[0].id).eql(`slo-${id}-1`);
|
||||
|
||||
const summaryTransform = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect summary transform to be created
|
||||
expect(summaryTransform.body.transforms[0].id).eql(`slo-summary-${id}-1`);
|
||||
|
||||
await supertestAPI
|
||||
.delete(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
});
|
||||
|
||||
// await retry.tryForTime(150 * 1000, async () => {
|
||||
const savedObjectAfterDelete = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
// SO should now be deleted
|
||||
expect(savedObjectAfterDelete.saved_objects.length).eql(0);
|
||||
|
||||
// roll up transform should be deleted
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
// summary transform should be deleted
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
// expect summary and rollup documents to be deleted
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
const sloSummaryResponseAfterDeletion = await sloEsClient.getSLOSummaryDataById(id);
|
||||
const sloRollupResponseAfterDeletion = await sloEsClient.getSLORollupDataById(id);
|
||||
expect(sloSummaryResponseAfterDeletion.hits.hits.length).eql(0);
|
||||
// sometimes the ingest pipeline ingests one extra document after the transform is stopped
|
||||
expect(sloRollupResponseAfterDeletion.hits.hits.length <= 1).eql(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
33
x-pack/test/api_integration/apis/slos/fixtures/create_slo.ts
Normal file
33
x-pack/test/api_integration/apis/slos/fixtures/create_slo.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { CreateSLOInput } from '@kbn/slo-schema';
|
||||
|
||||
export const sloData: CreateSLOInput = {
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'occurrences',
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
objective: {
|
||||
target: 0.99,
|
||||
},
|
||||
tags: ['test'],
|
||||
groupBy: 'tags',
|
||||
};
|
465
x-pack/test/api_integration/apis/slos/get_slo.ts
Normal file
465
x-pack/test/api_integration/apis/slos/get_slo.ts
Normal file
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* 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 { cleanup } from '@kbn/infra-forge';
|
||||
import expect from '@kbn/expect';
|
||||
import type { CreateSLOInput } from '@kbn/slo-schema';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { loadTestData } from './helper/load_test_data';
|
||||
import { SloEsClient } from './helper/es';
|
||||
import { sloData } from './fixtures/create_slo';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('Get SLOs', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
const esClient = getService('es');
|
||||
const logger = getService('log');
|
||||
const retry = getService('retry');
|
||||
const slo = getService('slo');
|
||||
const sloEsClient = new SloEsClient(esClient);
|
||||
|
||||
let createSLOInput: CreateSLOInput;
|
||||
|
||||
const createSLO = async (requestOverrides?: Record<string, any>) => {
|
||||
return await slo.create({
|
||||
...createSLOInput,
|
||||
...requestOverrides,
|
||||
});
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
await loadTestData(getService);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
createSLOInput = sloData;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await cleanup({ esClient, logger });
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
});
|
||||
|
||||
it('gets slo by id and calculates SLI - occurances rolling', async () => {
|
||||
const id = await createSLO({
|
||||
groupBy: '*',
|
||||
});
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
const getResponse = await supertestAPI
|
||||
.get(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(getResponse.body).eql({
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: `system.network.name: eth1`,
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'occurrences',
|
||||
timeWindow: { duration: '7d', type: 'rolling' },
|
||||
objective: { target: 0.99 },
|
||||
tags: ['test'],
|
||||
groupBy: '*',
|
||||
id,
|
||||
settings: { syncDelay: '1m', frequency: '1m' },
|
||||
revision: 1,
|
||||
enabled: true,
|
||||
createdAt: getResponse.body.createdAt,
|
||||
updatedAt: getResponse.body.updatedAt,
|
||||
version: 2,
|
||||
instanceId: '*',
|
||||
summary: {
|
||||
sliValue: 0.5,
|
||||
errorBudget: {
|
||||
initial: 0.01,
|
||||
consumed: 50,
|
||||
remaining: -49,
|
||||
isEstimated: false,
|
||||
},
|
||||
status: 'VIOLATED',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('gets slo by id and calculates SLI - occurences calendarAligned', async () => {
|
||||
const id = await createSLO({
|
||||
groupBy: '*',
|
||||
timeWindow: {
|
||||
duration: '1w',
|
||||
type: 'calendarAligned',
|
||||
},
|
||||
});
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
const getResponse = await supertestAPI
|
||||
.get(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect summary transform to be created
|
||||
expect(getResponse.body).eql({
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: `system.network.name: eth1`,
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'occurrences',
|
||||
timeWindow: { duration: '1w', type: 'calendarAligned' },
|
||||
objective: { target: 0.99 },
|
||||
tags: ['test'],
|
||||
groupBy: '*',
|
||||
id,
|
||||
settings: { syncDelay: '1m', frequency: '1m' },
|
||||
revision: 1,
|
||||
enabled: true,
|
||||
createdAt: getResponse.body.createdAt,
|
||||
updatedAt: getResponse.body.updatedAt,
|
||||
version: 2,
|
||||
instanceId: '*',
|
||||
summary: {
|
||||
sliValue: 0.5,
|
||||
errorBudget: {
|
||||
initial: 0.01,
|
||||
consumed: 50,
|
||||
remaining: -49,
|
||||
isEstimated: true,
|
||||
},
|
||||
status: 'VIOLATED',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('gets slo by id and calculates SLI - timeslices rolling', async () => {
|
||||
const id = await createSLO({
|
||||
groupBy: '*',
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
budgetingMethod: 'timeslices',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
timesliceTarget: 0.95,
|
||||
timesliceWindow: '1m',
|
||||
},
|
||||
});
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
const getResponse = await supertestAPI
|
||||
.get(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect summary transform to be created
|
||||
expect(getResponse.body).eql({
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: `system.network.name: eth1`,
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'timeslices',
|
||||
timeWindow: { duration: '7d', type: 'rolling' },
|
||||
objective: {
|
||||
target: 0.99,
|
||||
timesliceTarget: 0.95,
|
||||
timesliceWindow: '1m',
|
||||
},
|
||||
tags: ['test'],
|
||||
groupBy: '*',
|
||||
id,
|
||||
settings: { syncDelay: '1m', frequency: '1m' },
|
||||
revision: 1,
|
||||
enabled: true,
|
||||
createdAt: getResponse.body.createdAt,
|
||||
updatedAt: getResponse.body.updatedAt,
|
||||
version: 2,
|
||||
instanceId: '*',
|
||||
summary: {
|
||||
sliValue: 0.5,
|
||||
errorBudget: {
|
||||
initial: 0.01,
|
||||
consumed: 50,
|
||||
remaining: -49,
|
||||
isEstimated: false,
|
||||
},
|
||||
status: 'VIOLATED',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('gets slo by id and calculates SLI - timeslices calendarAligned', async () => {
|
||||
const id = await createSLO({
|
||||
groupBy: '*',
|
||||
timeWindow: {
|
||||
duration: '1w',
|
||||
type: 'calendarAligned',
|
||||
},
|
||||
budgetingMethod: 'timeslices',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
timesliceTarget: 0.95,
|
||||
timesliceWindow: '10m',
|
||||
},
|
||||
});
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
const getResponse = await supertestAPI
|
||||
.get(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(getResponse.body).eql({
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: `system.network.name: eth1`,
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'timeslices',
|
||||
timeWindow: { duration: '1w', type: 'calendarAligned' },
|
||||
objective: {
|
||||
target: 0.99,
|
||||
timesliceTarget: 0.95,
|
||||
timesliceWindow: '10m',
|
||||
},
|
||||
tags: ['test'],
|
||||
groupBy: '*',
|
||||
id,
|
||||
settings: { syncDelay: '1m', frequency: '1m' },
|
||||
revision: 1,
|
||||
enabled: true,
|
||||
createdAt: getResponse.body.createdAt,
|
||||
updatedAt: getResponse.body.updatedAt,
|
||||
version: 2,
|
||||
instanceId: '*',
|
||||
summary: {
|
||||
sliValue: 0,
|
||||
errorBudget: {
|
||||
initial: 0.01,
|
||||
consumed: 0.198413,
|
||||
remaining: 0.801587,
|
||||
isEstimated: false,
|
||||
},
|
||||
status: 'DEGRADING',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('gets slos by query', async () => {
|
||||
const id = await createSLO();
|
||||
await createSLO({ name: 'test int' });
|
||||
|
||||
await retry.tryForTime(300 * 1000, async () => {
|
||||
const response = await supertestAPI
|
||||
.get(`/api/observability/slos`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.results.length).eql(2);
|
||||
|
||||
const searchResponse = await supertestAPI
|
||||
.get(`/api/observability/slos?kqlQuery=slo.name%3Aapi*`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse.body.results.length).eql(1);
|
||||
|
||||
const searchResponse2 = await supertestAPI
|
||||
.get(`/api/observability/slos?kqlQuery=slo.name%3Aint`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse2.body.results.length).eql(1);
|
||||
|
||||
const searchResponse3 = await supertestAPI
|
||||
.get(`/api/observability/slos?kqlQuery=slo.name%3Aint*`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse3.body.results.length).eql(2);
|
||||
|
||||
const searchResponse4 = await supertestAPI
|
||||
.get(`/api/observability/slos?kqlQuery=int*`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse4.body.results.length).eql(2);
|
||||
|
||||
const instanceResponse = await supertestAPI
|
||||
.get(`/internal/observability/slos/${id}/_instances`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect 3 instances to be created
|
||||
expect(instanceResponse.body.groupBy).eql('tags');
|
||||
expect(instanceResponse.body.instances.sort()).eql(['1', '2', '3']);
|
||||
});
|
||||
});
|
||||
|
||||
it('gets slo definitions', async () => {
|
||||
const id = await createSLO();
|
||||
const secondId = await createSLO({ name: 'test name int' });
|
||||
const response = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).eql({
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
results: [
|
||||
{
|
||||
budgetingMethod: 'occurrences',
|
||||
createdAt: response.body.results[0].createdAt,
|
||||
description: 'Fixture for api integration tests',
|
||||
enabled: true,
|
||||
groupBy: 'tags',
|
||||
id,
|
||||
indicator: {
|
||||
params: {
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
index: 'kbn-data-forge*',
|
||||
timestampField: '@timestamp',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
},
|
||||
type: 'sli.kql.custom',
|
||||
},
|
||||
name: 'Test SLO for api integration',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
},
|
||||
revision: 1,
|
||||
settings: {
|
||||
frequency: '1m',
|
||||
syncDelay: '1m',
|
||||
},
|
||||
tags: ['test'],
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
updatedAt: response.body.results[0].updatedAt,
|
||||
version: 2,
|
||||
},
|
||||
{
|
||||
budgetingMethod: 'occurrences',
|
||||
createdAt: response.body.results[1].createdAt,
|
||||
description: 'Fixture for api integration tests',
|
||||
enabled: true,
|
||||
groupBy: 'tags',
|
||||
id: secondId,
|
||||
indicator: {
|
||||
params: {
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
index: 'kbn-data-forge*',
|
||||
timestampField: '@timestamp',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
},
|
||||
type: 'sli.kql.custom',
|
||||
},
|
||||
name: 'test name int',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
},
|
||||
revision: 1,
|
||||
settings: {
|
||||
frequency: '1m',
|
||||
syncDelay: '1m',
|
||||
},
|
||||
tags: ['test'],
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
updatedAt: response.body.results[1].updatedAt,
|
||||
version: 2,
|
||||
},
|
||||
],
|
||||
total: 2,
|
||||
});
|
||||
|
||||
// can search by name
|
||||
const searchResponse = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions?search=api`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse.body.total).eql(1);
|
||||
|
||||
const searchResponse2 = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions?search=int`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse2.body.total).eql(1);
|
||||
|
||||
const searchResponse3 = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions?search=int*`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(searchResponse3.body.total).eql(2);
|
||||
});
|
||||
});
|
||||
}
|
64
x-pack/test/api_integration/apis/slos/helper/es.ts
Normal file
64
x-pack/test/api_integration/apis/slos/helper/es.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 { Client } from '@elastic/elasticsearch';
|
||||
import {
|
||||
SLO_DESTINATION_INDEX_PATTERN,
|
||||
SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
|
||||
} from '@kbn/observability-plugin/common/slo/constants';
|
||||
|
||||
export class SloEsClient {
|
||||
constructor(private esClient: Client) {}
|
||||
|
||||
public async getSLOSummaryDataById(id: string) {
|
||||
return await this.esClient.search({
|
||||
index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: { 'slo.id': id },
|
||||
},
|
||||
{
|
||||
term: { isTempDoc: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async getSLORollupDataById(id: string) {
|
||||
return await this.esClient.search({
|
||||
index: SLO_DESTINATION_INDEX_PATTERN,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: { 'slo.id': id },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async deleteTestSourceData() {
|
||||
try {
|
||||
await this.esClient.deleteByQuery({
|
||||
index: 'kbn-data-forge-fake_hosts*',
|
||||
query: { term: { 'system.network.name': 'eth1' } },
|
||||
});
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('SLO api integration test data not found');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 { generate } from '@kbn/infra-forge';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export async function loadTestData(getService: FtrProviderContext['getService']) {
|
||||
const DATE_VIEW = 'kbn-data-forge-fake_hosts';
|
||||
const DATA_VIEW_ID = 'data-view-id';
|
||||
const dataViewApi = getService('dataViewApi');
|
||||
const esClient = getService('es');
|
||||
const logger = getService('log');
|
||||
|
||||
await generate({ esClient, lookback: 'now-16m', logger });
|
||||
await dataViewApi.create({
|
||||
name: DATE_VIEW,
|
||||
id: DATA_VIEW_ID,
|
||||
title: DATE_VIEW,
|
||||
});
|
||||
}
|
18
x-pack/test/api_integration/apis/slos/index.ts
Normal file
18
x-pack/test/api_integration/apis/slos/index.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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('SLO API Tests', () => {
|
||||
loadTestFile(require.resolve('./create_slo'));
|
||||
loadTestFile(require.resolve('./delete_slo'));
|
||||
loadTestFile(require.resolve('./get_slo'));
|
||||
loadTestFile(require.resolve('./update_slo'));
|
||||
loadTestFile(require.resolve('./reset_slo'));
|
||||
});
|
||||
}
|
105
x-pack/test/api_integration/apis/slos/reset_slo.ts
Normal file
105
x-pack/test/api_integration/apis/slos/reset_slo.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 { cleanup } from '@kbn/infra-forge';
|
||||
import expect from '@kbn/expect';
|
||||
import { SO_SLO_TYPE } from '@kbn/observability-plugin/server/saved_objects';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { loadTestData } from './helper/load_test_data';
|
||||
import { SloEsClient } from './helper/es';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('Reset SLOs', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esClient = getService('es');
|
||||
const logger = getService('log');
|
||||
const slo = getService('slo');
|
||||
const sloEsClient = new SloEsClient(esClient);
|
||||
|
||||
before(async () => {
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
await slo.deleteAllSLOs();
|
||||
await loadTestData(getService);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await cleanup({ esClient, logger });
|
||||
await sloEsClient.deleteTestSourceData();
|
||||
});
|
||||
|
||||
it('updates the SO and transforms', async () => {
|
||||
// create mock old SLO
|
||||
const id = 'bdaeccdd-dc63-4138-a1d5-92c075f88087';
|
||||
await kibanaServer.savedObjects.clean({
|
||||
types: [SO_SLO_TYPE],
|
||||
});
|
||||
await kibanaServer.savedObjects.create({
|
||||
type: SO_SLO_TYPE,
|
||||
overwrite: true,
|
||||
id,
|
||||
attributes: {
|
||||
name: 'Test SLO for api integration',
|
||||
description: 'Fixture for api integration tests',
|
||||
indicator: {
|
||||
type: 'sli.kql.custom',
|
||||
params: {
|
||||
index: 'kbn-data-forge*',
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
timestampField: '@timestamp',
|
||||
},
|
||||
},
|
||||
budgetingMethod: 'occurrences',
|
||||
timeWindow: { duration: '7d', type: 'rolling' },
|
||||
objective: { target: 0.99 },
|
||||
tags: ['test'],
|
||||
groupBy: '*',
|
||||
id,
|
||||
settings: {
|
||||
syncDelay: '1m',
|
||||
frequency: '1m',
|
||||
},
|
||||
revision: 1,
|
||||
enabled: true,
|
||||
createdAt: '2023-12-14T01:12:35.638Z',
|
||||
updatedAt: '2023-12-14T01:12:35.638Z',
|
||||
version: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const responseBeforeReset = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(responseBeforeReset.body.results[0].version).eql(1);
|
||||
|
||||
await supertestAPI
|
||||
.post(`/api/observability/slos/${id}/_reset`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
const responseAfterReset = await supertestAPI
|
||||
.get(`/api/observability/slos/_definitions`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(responseAfterReset.body.results[0].version).eql(2);
|
||||
});
|
||||
});
|
||||
}
|
677
x-pack/test/api_integration/apis/slos/update_slo.ts
Normal file
677
x-pack/test/api_integration/apis/slos/update_slo.ts
Normal file
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* 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 { cleanup } from '@kbn/infra-forge';
|
||||
import expect from '@kbn/expect';
|
||||
import type { CreateSLOInput } from '@kbn/slo-schema';
|
||||
import { SO_SLO_TYPE } from '@kbn/observability-plugin/server/saved_objects';
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { loadTestData } from './helper/load_test_data';
|
||||
import { sloData } from './fixtures/create_slo';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('Update SLOs', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestAPI = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esClient = getService('es');
|
||||
const logger = getService('log');
|
||||
const slo = getService('slo');
|
||||
|
||||
let createSLOInput: CreateSLOInput;
|
||||
|
||||
before(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
await loadTestData(getService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
createSLOInput = sloData;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await slo.deleteAllSLOs();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await cleanup({ esClient, logger });
|
||||
});
|
||||
|
||||
it('updates the SO and transforms', async () => {
|
||||
const apiResponse = await supertestAPI
|
||||
.post('/api/observability/slos')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(createSLOInput)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).property('id');
|
||||
|
||||
const { id } = apiResponse.body;
|
||||
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...createSLOInput,
|
||||
groupBy: 'hosts',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const savedObject = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
expect(savedObject.saved_objects.length).eql(1);
|
||||
|
||||
expect(savedObject.saved_objects[0].attributes).eql({
|
||||
budgetingMethod: 'occurrences',
|
||||
updatedAt: savedObject.saved_objects[0].attributes.updatedAt,
|
||||
createdAt: savedObject.saved_objects[0].attributes.createdAt,
|
||||
description: 'Fixture for api integration tests',
|
||||
enabled: true,
|
||||
groupBy: 'hosts',
|
||||
id,
|
||||
indicator: {
|
||||
params: {
|
||||
filter: 'system.network.name: eth1',
|
||||
good: 'container.cpu.user.pct < 1',
|
||||
index: 'kbn-data-forge*',
|
||||
timestampField: '@timestamp',
|
||||
total: 'container.cpu.user.pct: *',
|
||||
},
|
||||
type: 'sli.kql.custom',
|
||||
},
|
||||
name: 'Test SLO for api integration',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
},
|
||||
revision: 2,
|
||||
settings: {
|
||||
frequency: '1m',
|
||||
syncDelay: '1m',
|
||||
},
|
||||
tags: ['test'],
|
||||
timeWindow: {
|
||||
duration: '7d',
|
||||
type: 'rolling',
|
||||
},
|
||||
version: 2,
|
||||
});
|
||||
|
||||
const rollUpTransformResponse = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect roll up transform to be created
|
||||
expect(rollUpTransformResponse.body).eql({
|
||||
count: 1,
|
||||
transforms: [
|
||||
{
|
||||
id: `slo-${id}-2`,
|
||||
authorization: { roles: ['superuser'] },
|
||||
version: '10.0.0',
|
||||
create_time: rollUpTransformResponse.body.transforms[0].create_time,
|
||||
source: {
|
||||
index: ['kbn-data-forge*'],
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{ range: { '@timestamp': { gte: 'now-7d/d' } } },
|
||||
{
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
match: {
|
||||
'system.network.name': 'eth1',
|
||||
},
|
||||
},
|
||||
],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime_mappings: {
|
||||
'slo.id': {
|
||||
type: 'keyword',
|
||||
script: { source: `emit('${id}')` },
|
||||
},
|
||||
'slo.revision': { type: 'long', script: { source: 'emit(2)' } },
|
||||
},
|
||||
},
|
||||
dest: {
|
||||
index: '.slo-observability.sli-v3',
|
||||
pipeline: '.slo-observability.sli.pipeline-v3',
|
||||
},
|
||||
frequency: '1m',
|
||||
sync: { time: { field: '@timestamp', delay: '1m' } },
|
||||
pivot: {
|
||||
group_by: {
|
||||
'slo.id': { terms: { field: 'slo.id' } },
|
||||
'slo.revision': { terms: { field: 'slo.revision' } },
|
||||
'slo.instanceId': { terms: { field: 'hosts' } },
|
||||
'slo.groupings.hosts': { terms: { field: 'hosts' } },
|
||||
'@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } },
|
||||
},
|
||||
aggregations: {
|
||||
'slo.numerator': {
|
||||
filter: {
|
||||
bool: {
|
||||
should: [{ range: { 'container.cpu.user.pct': { lt: '1' } } }],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
'slo.denominator': {
|
||||
filter: {
|
||||
bool: {
|
||||
should: [{ exists: { field: 'container.cpu.user.pct' } }],
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
description: `Rolled-up SLI data for SLO: Test SLO for api integration [id: ${id}, revision: 2]`,
|
||||
settings: { deduce_mappings: false, unattended: true },
|
||||
_meta: { version: 3, managed: true, managed_by: 'observability' },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const summaryTransform = await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// expect summary transform to be created
|
||||
expect(summaryTransform.body).eql({
|
||||
count: 1,
|
||||
transforms: [
|
||||
{
|
||||
id: `slo-summary-${id}-2`,
|
||||
authorization: { roles: ['superuser'] },
|
||||
version: '10.0.0',
|
||||
create_time: summaryTransform.body.transforms[0].create_time,
|
||||
source: {
|
||||
index: ['.slo-observability.sli-v3*'],
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{ range: { '@timestamp': { gte: 'now-7d/m', lte: 'now/m' } } },
|
||||
{ term: { 'slo.id': id } },
|
||||
{ term: { 'slo.revision': 2 } },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
dest: {
|
||||
index: '.slo-observability.summary-v3',
|
||||
pipeline: `.slo-observability.summary.pipeline-${id}-2`,
|
||||
},
|
||||
frequency: '1m',
|
||||
sync: { time: { field: 'event.ingested', delay: '65s' } },
|
||||
pivot: {
|
||||
group_by: {
|
||||
'slo.id': { terms: { field: 'slo.id' } },
|
||||
'slo.revision': { terms: { field: 'slo.revision' } },
|
||||
'slo.instanceId': { terms: { field: 'slo.instanceId' } },
|
||||
'slo.groupings.hosts': {
|
||||
terms: { field: 'slo.groupings.hosts' },
|
||||
},
|
||||
'service.name': { terms: { field: 'service.name', missing_bucket: true } },
|
||||
'service.environment': {
|
||||
terms: { field: 'service.environment', missing_bucket: true },
|
||||
},
|
||||
'transaction.name': { terms: { field: 'transaction.name', missing_bucket: true } },
|
||||
'transaction.type': { terms: { field: 'transaction.type', missing_bucket: true } },
|
||||
},
|
||||
aggregations: {
|
||||
goodEvents: { sum: { field: 'slo.numerator' } },
|
||||
totalEvents: { sum: { field: 'slo.denominator' } },
|
||||
sliValue: {
|
||||
bucket_script: {
|
||||
buckets_path: { goodEvents: 'goodEvents', totalEvents: 'totalEvents' },
|
||||
script:
|
||||
'if (params.totalEvents == 0) { return -1 } else if (params.goodEvents >= params.totalEvents) { return 1 } else { return params.goodEvents / params.totalEvents }',
|
||||
},
|
||||
},
|
||||
errorBudgetInitial: { bucket_script: { buckets_path: {}, script: '1 - 0.99' } },
|
||||
errorBudgetConsumed: {
|
||||
bucket_script: {
|
||||
buckets_path: {
|
||||
sliValue: 'sliValue',
|
||||
errorBudgetInitial: 'errorBudgetInitial',
|
||||
},
|
||||
script:
|
||||
'if (params.sliValue == -1) { return 0 } else { return (1 - params.sliValue) / params.errorBudgetInitial }',
|
||||
},
|
||||
},
|
||||
errorBudgetRemaining: {
|
||||
bucket_script: {
|
||||
buckets_path: { errorBudgetConsumed: 'errorBudgetConsumed' },
|
||||
script: '1 - params.errorBudgetConsumed',
|
||||
},
|
||||
},
|
||||
statusCode: {
|
||||
bucket_script: {
|
||||
buckets_path: {
|
||||
sliValue: 'sliValue',
|
||||
errorBudgetRemaining: 'errorBudgetRemaining',
|
||||
},
|
||||
script: {
|
||||
source:
|
||||
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= 0.99) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
|
||||
},
|
||||
},
|
||||
},
|
||||
latestSliTimestamp: { max: { field: '@timestamp' } },
|
||||
},
|
||||
},
|
||||
description: `Summarise the rollup data of SLO: Test SLO for api integration [id: ${id}, revision: 2].`,
|
||||
settings: { deduce_mappings: false, unattended: true },
|
||||
_meta: { version: 3, managed: true, managed_by: 'observability' },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('updates an existing slo and does not update transforms when relevant fields are changed', async () => {
|
||||
const request = createSLOInput;
|
||||
|
||||
const apiResponse = await supertestAPI
|
||||
.post('/api/observability/slos')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(request)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).property('id');
|
||||
|
||||
const { id } = apiResponse.body;
|
||||
|
||||
const savedObject = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
expect(savedObject.saved_objects.length).eql(1);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change name
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
name: 'test name',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change description
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
description: 'test description',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change tags
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
tags: ['testTag'],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('updates an existing slo and updates transforms when relevant fields are changed', async () => {
|
||||
const request = createSLOInput;
|
||||
|
||||
const apiResponse = await supertestAPI
|
||||
.post('/api/observability/slos')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(request)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).property('id');
|
||||
|
||||
const { id } = apiResponse.body;
|
||||
|
||||
const savedObject = await kibanaServer.savedObjects.find({
|
||||
type: SO_SLO_TYPE,
|
||||
});
|
||||
|
||||
expect(savedObject.saved_objects.length).eql(1);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change group by
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
groupBy: 'hosts',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-1`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change indicator
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
indicator: {
|
||||
...request.indicator,
|
||||
params: {
|
||||
...request.indicator.params,
|
||||
index: 'test-index-*',
|
||||
},
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-2`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-3`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-3`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change time window
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
timeWindow: {
|
||||
...request.timeWindow,
|
||||
duration: '7d',
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-3`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-3`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-4`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-4`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change objective
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
objective: {
|
||||
target: 0.97,
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-4`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-4`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-5`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-5`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change budgetingMethod
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
budgetingMethod: 'timeslices',
|
||||
objective: {
|
||||
target: 0.99,
|
||||
timesliceTarget: 0.95,
|
||||
timesliceWindow: '1m',
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-5`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-5`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-6`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-6`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
// change settings
|
||||
await supertestAPI
|
||||
.put(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
...request,
|
||||
settings: {
|
||||
frequency: '2m',
|
||||
syncDelay: '5m',
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-6`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-6`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-${id}-7`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
await supertestAPI
|
||||
.get(`/internal/transform/transforms/slo-summary-${id}-7`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send()
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
}
|
52
x-pack/test/api_integration/services/data_view_api.ts
Normal file
52
x-pack/test/api_integration/services/data_view_api.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 function DataViewApiProvider({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
return {
|
||||
async create({ id, name, title }: { id: string; name: string; title: string }) {
|
||||
const { body } = await supertest
|
||||
.post(`/api/content_management/rpc/create`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo')
|
||||
.send({
|
||||
contentTypeId: 'index-pattern',
|
||||
data: {
|
||||
fieldAttrs: '{}',
|
||||
title,
|
||||
timeFieldName: '@timestamp',
|
||||
sourceFilters: '[]',
|
||||
fields: '[]',
|
||||
fieldFormatMap: '{}',
|
||||
typeMeta: '{}',
|
||||
runtimeFieldMap: '{}',
|
||||
name,
|
||||
},
|
||||
options: { id },
|
||||
version: 1,
|
||||
});
|
||||
return body;
|
||||
},
|
||||
|
||||
async delete({ id }: { id: string }) {
|
||||
const { body } = await supertest
|
||||
.post(`/api/content_management/rpc/delete`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.set('x-elastic-internal-origin', 'foo')
|
||||
.send({
|
||||
contentTypeId: 'index-pattern',
|
||||
id,
|
||||
options: { force: true },
|
||||
version: 1,
|
||||
});
|
||||
return body;
|
||||
},
|
||||
};
|
||||
}
|
|
@ -22,6 +22,8 @@ import { IngestManagerProvider } from '../../common/services/ingest_manager';
|
|||
import { TransformProvider } from './transform';
|
||||
import { IngestPipelinesProvider } from './ingest_pipelines';
|
||||
import { IndexManagementProvider } from './index_management';
|
||||
import { DataViewApiProvider } from './data_view_api';
|
||||
import { SloApiProvider } from './slo';
|
||||
|
||||
export const services = {
|
||||
...commonServices,
|
||||
|
@ -30,6 +32,7 @@ export const services = {
|
|||
supertest: kibanaApiIntegrationServices.supertest,
|
||||
|
||||
aiops: AiopsProvider,
|
||||
dataViewApi: DataViewApiProvider,
|
||||
esSupertestWithoutAuth: EsSupertestWithoutAuthProvider,
|
||||
infraOpsSourceConfiguration: InfraOpsSourceConfigurationProvider,
|
||||
supertestWithoutAuth: SupertestWithoutAuthProvider,
|
||||
|
@ -39,4 +42,5 @@ export const services = {
|
|||
transform: TransformProvider,
|
||||
ingestPipelines: IngestPipelinesProvider,
|
||||
indexManagement: IndexManagementProvider,
|
||||
slo: SloApiProvider,
|
||||
};
|
||||
|
|
51
x-pack/test/api_integration/services/slo.ts
Normal file
51
x-pack/test/api_integration/services/slo.ts
Normal file
|
@ -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 { CreateSLOInput, FindSLODefinitionsResponse } from '@kbn/slo-schema';
|
||||
import { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
export function SloApiProvider({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
return {
|
||||
async create(params: CreateSLOInput) {
|
||||
const slo = await supertest
|
||||
.post('/api/observability/slos')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(params)
|
||||
.expect(200);
|
||||
|
||||
const { id } = slo.body;
|
||||
|
||||
const reqBody = [{ id: `slo-${id}-1` }, { id: `slo-summary-${id}-1` }];
|
||||
await supertest
|
||||
.post(`/internal/transform/schedule_now_transforms`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('elastic-api-version', '1')
|
||||
.send(reqBody)
|
||||
.expect(200);
|
||||
|
||||
return id;
|
||||
},
|
||||
async deleteAllSLOs() {
|
||||
const response = await supertest
|
||||
.get(`/api/observability/slos/_definitions`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(200);
|
||||
await Promise.all(
|
||||
(response.body as FindSLODefinitionsResponse).results.map(({ id }) => {
|
||||
return supertest
|
||||
.delete(`/api/observability/slos/${id}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send()
|
||||
.expect(204);
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
|
@ -164,6 +164,7 @@
|
|||
"@kbn/io-ts-utils",
|
||||
"@kbn/log-explorer-plugin",
|
||||
"@kbn/security-plugin-types-common",
|
||||
"@kbn/slo-schema",
|
||||
"@kbn/typed-react-router-config",
|
||||
"@kbn/ftr-common-functional-ui-services",
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue