Skip to content

Commit

Permalink
chore(slo): Add tests for historical summary api (#183648)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdelemme authored May 17, 2024
1 parent daeb764 commit 36008b0
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 1 deletion.
130 changes: 130 additions & 0 deletions x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts
Original file line number Diff line number Diff line change
@@ -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 expect from '@kbn/expect';
import {
SLO_DESTINATION_INDEX_NAME,
SLO_DESTINATION_INDEX_PATTERN,
} from '@kbn/slo-plugin/common/constants';
import { ALL_VALUE } from '@kbn/slo-schema';
import moment from 'moment';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService }: FtrProviderContext) {
const esClient = getService('es');
const esDeleteAllIndices = getService('esDeleteAllIndices');
const sloApi = getService('slo');

const SLO_ID = 'slo-fake-1';
describe('fetch historical summary', () => {
before(async () => {
const now = moment().startOf('minute');
const curr = now.clone().subtract(30, 'days');
const end = now.clone().add(5, 'minutes');

const batchOperations = [];
while (curr.isSameOrBefore(end)) {
batchOperations.push([
{ index: { _index: SLO_DESTINATION_INDEX_NAME } },
{
'@timestamp': curr.toISOString(),
slo: {
id: SLO_ID,
revision: 1,
instanceId: ALL_VALUE,
numerator: 90,
denominator: 100,
isGoodSlice: 1,
groupings: {},
},
},
]);
curr.add(1, 'minute');
}

await esClient.bulk({
index: SLO_DESTINATION_INDEX_NAME,
operations: batchOperations.flat(),
refresh: 'wait_for',
});

await esClient.indices.refresh({ index: SLO_DESTINATION_INDEX_NAME });
});

after(async () => {
await esDeleteAllIndices(SLO_DESTINATION_INDEX_PATTERN);
});

it('computes the historical summary for a rolling occurrences SLO', async () => {
const response = await sloApi.fetchHistoricalSummary({
list: [
{
sloId: SLO_ID,
instanceId: ALL_VALUE,
timeWindow: {
duration: '7d',
type: 'rolling',
},
budgetingMethod: 'occurrences',
objective: {
target: 0.9,
},
groupBy: ALL_VALUE,
revision: 1,
},
],
});
expect(response[0].sloId).to.eql(SLO_ID);
expect(response[0].instanceId).to.eql(ALL_VALUE);
expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour
const last = response[0].data.pop();
expect(last?.errorBudget).to.eql({
consumed: 1,
initial: 0.1,
isEstimated: false,
remaining: 0,
});
expect(last?.sliValue).to.eql(0.9);
expect(last?.status).to.eql('HEALTHY');
});

it('computes the historical summary for a rolling timeslices SLO', async () => {
const response = await sloApi.fetchHistoricalSummary({
list: [
{
sloId: SLO_ID,
instanceId: ALL_VALUE,
timeWindow: {
duration: '7d',
type: 'rolling',
},
budgetingMethod: 'timeslices',
objective: {
target: 0.9,
timesliceTarget: 0.8,
timesliceWindow: '1m',
},
groupBy: ALL_VALUE,
revision: 1,
},
],
});
expect(response[0].sloId).to.eql(SLO_ID);
expect(response[0].instanceId).to.eql(ALL_VALUE);
expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour
const last = response[0].data.pop();
expect(last?.errorBudget).to.eql({
consumed: 0,
initial: 0.1,
isEstimated: false,
remaining: 1,
});
expect(last?.sliValue).to.eql(1);
expect(last?.status).to.eql('HEALTHY');
});
});
}
1 change: 1 addition & 0 deletions x-pack/test/api_integration/apis/slos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./get_slo'));
loadTestFile(require.resolve('./update_slo'));
loadTestFile(require.resolve('./reset_slo'));
loadTestFile(require.resolve('./fetch_historical_summary'));
});
}
23 changes: 22 additions & 1 deletion x-pack/test/api_integration/services/slo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
* 2.0.
*/

import { CreateSLOInput, FindSLODefinitionsResponse } from '@kbn/slo-schema';
import { SLO_SUMMARY_DESTINATION_INDEX_NAME } from '@kbn/slo-plugin/common/constants';
import {
CreateSLOInput,
fetchHistoricalSummaryParamsSchema,
FetchHistoricalSummaryResponse,
FindSLODefinitionsResponse,
} from '@kbn/slo-schema';
import * as t from 'io-ts';
import { waitForIndexToBeEmpty } from '../apis/slos/helper/wait_for_index_state';
import { FtrProviderContext } from '../ftr_provider_context';

type FetchHistoricalSummaryParams = t.OutputOf<
typeof fetchHistoricalSummaryParamsSchema.props.body
>;

export function SloApiProvider({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esClient = getService('es');
Expand Down Expand Up @@ -49,5 +59,16 @@ export function SloApiProvider({ getService }: FtrProviderContext) {
}
await waitForIndexToBeEmpty({ esClient, indexName: SLO_SUMMARY_DESTINATION_INDEX_NAME });
},
async fetchHistoricalSummary(
params: FetchHistoricalSummaryParams
): Promise<FetchHistoricalSummaryResponse> {
const { body } = await supertest
.post(`/internal/observability/slos/_historical_summary`)
.set('kbn-xsrf', 'foo')
.set('elastic-api-version', '1')
.send(params);

return body;
},
};
}
21 changes: 21 additions & 0 deletions x-pack/test_serverless/api_integration/services/slo_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* 2.0.
*/

import {
fetchHistoricalSummaryParamsSchema,
FetchHistoricalSummaryResponse,
} from '@kbn/slo-schema';
import * as t from 'io-ts';
import { FtrProviderContext } from '../ftr_provider_context';

type DurationUnit = 'm' | 'h' | 'd' | 'w' | 'M';
Expand Down Expand Up @@ -58,6 +63,10 @@ interface SloParams {
groupBy: string;
}

type FetchHistoricalSummaryParams = t.OutputOf<
typeof fetchHistoricalSummaryParamsSchema.props.body
>;

export function SloApiProvider({ getService }: FtrProviderContext) {
const es = getService('es');
const supertest = getService('supertest');
Expand All @@ -84,6 +93,18 @@ export function SloApiProvider({ getService }: FtrProviderContext) {
return response;
},

async fetchHistoricalSummary(
params: FetchHistoricalSummaryParams
): Promise<FetchHistoricalSummaryResponse> {
const { body } = await supertest
.post(`/internal/observability/slos/_historical_summary`)
.set('kbn-xsrf', 'foo')
.set('x-elastic-internal-origin', 'foo')
.send(params);

return body;
},

async waitForSloToBeDeleted(sloId: string) {
if (!sloId) {
throw new Error(`sloId is undefined`);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* 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 {
SLO_DESTINATION_INDEX_NAME,
SLO_DESTINATION_INDEX_PATTERN,
} from '@kbn/slo-plugin/common/constants';

import { ALL_VALUE } from '@kbn/slo-schema';
import moment from 'moment';
import { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getService }: FtrProviderContext) {
const esClient = getService('es');
const esDeleteAllIndices = getService('esDeleteAllIndices');
const sloApi = getService('sloApi');

const SLO_ID = 'slo-fake-1';
describe('fetch historical summary', () => {
before(async () => {
const now = moment().startOf('minute');
const curr = now.clone().subtract(30, 'days');
const end = now.clone().add(5, 'minutes');

const batchOperations = [];
while (curr.isSameOrBefore(end)) {
batchOperations.push([
{ index: { _index: SLO_DESTINATION_INDEX_NAME } },
{
'@timestamp': curr.toISOString(),
slo: {
id: SLO_ID,
revision: 1,
instanceId: ALL_VALUE,
numerator: 90,
denominator: 100,
isGoodSlice: 1,
groupings: {},
},
},
]);
curr.add(1, 'minute');
}

await esClient.bulk({
index: SLO_DESTINATION_INDEX_NAME,
operations: batchOperations.flat(),
refresh: 'wait_for',
});

await esClient.indices.refresh({ index: SLO_DESTINATION_INDEX_NAME });
});

after(async () => {
await esDeleteAllIndices(SLO_DESTINATION_INDEX_PATTERN);
});

it('computes the historical summary for a rolling occurrences SLO', async () => {
const response = await sloApi.fetchHistoricalSummary({
list: [
{
sloId: SLO_ID,
instanceId: ALL_VALUE,
timeWindow: {
duration: '7d',
type: 'rolling',
},
budgetingMethod: 'occurrences',
objective: {
target: 0.9,
},
groupBy: ALL_VALUE,
revision: 1,
},
],
});
expect(response[0].sloId).to.eql(SLO_ID);
expect(response[0].instanceId).to.eql(ALL_VALUE);
expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour
const last = response[0].data.pop();
expect(last?.errorBudget).to.eql({
consumed: 1,
initial: 0.1,
isEstimated: false,
remaining: 0,
});
expect(last?.sliValue).to.eql(0.9);
expect(last?.status).to.eql('HEALTHY');
});

it('computes the historical summary for a rolling timeslices SLO', async () => {
const response = await sloApi.fetchHistoricalSummary({
list: [
{
sloId: SLO_ID,
instanceId: ALL_VALUE,
timeWindow: {
duration: '7d',
type: 'rolling',
},
budgetingMethod: 'timeslices',
objective: {
target: 0.9,
timesliceTarget: 0.8,
timesliceWindow: '1m',
},
groupBy: ALL_VALUE,
revision: 1,
},
],
});
expect(response[0].sloId).to.eql(SLO_ID);
expect(response[0].instanceId).to.eql(ALL_VALUE);
expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour
const last = response[0].data.pop();
expect(last?.errorBudget).to.eql({
consumed: 0,
initial: 0.1,
isEstimated: false,
remaining: 1,
});
expect(last?.sliValue).to.eql(1);
expect(last?.status).to.eql('HEALTHY');
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
describe('SLOs', function () {
loadTestFile(require.resolve('./create_slo'));
loadTestFile(require.resolve('./delete_slo'));
loadTestFile(require.resolve('./fetch_historical_summary'));
});
}

0 comments on commit 36008b0

Please sign in to comment.