From bffeb366aae24b99327f014d02215c9f7de2fa7a Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Tue, 8 Oct 2024 16:01:59 -0400 Subject: [PATCH 01/16] Add missing slo api --- .../deployment_agnostic/services/slo_api.ts | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts index 05db3259ddbc6..756850686ce42 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts @@ -5,42 +5,16 @@ * 2.0. */ +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { - fetchHistoricalSummaryParamsSchema, + CreateSLOInput, + FetchHistoricalSummaryParams, FetchHistoricalSummaryResponse, + FindSLODefinitionsResponse, + UpdateSLOInput, } from '@kbn/slo-schema'; -import * as t from 'io-ts'; -import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { DeploymentAgnosticFtrProviderContext } from '../ftr_provider_context'; -interface SloParams { - id?: string; - name: string; - description: string; - indicator: { - type: 'sli.kql.custom'; - params: { - index: string; - good: string; - total: string; - timestampField: string; - }; - }; - timeWindow: { - duration: string; - type: string; - }; - budgetingMethod: string; - objective: { - target: number; - }; - groupBy: string; -} - -type FetchHistoricalSummaryParams = t.OutputOf< - typeof fetchHistoricalSummaryParamsSchema.props.body ->; - interface SloRequestParams { id: string; roleAuthc: RoleCredentials; @@ -56,7 +30,7 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont const requestTimeout = 30 * 1000; return { - async create(slo: SloParams, roleAuthc: RoleCredentials) { + async create(slo: CreateSLOInput, roleAuthc: RoleCredentials) { const { body } = await supertestWithoutAuth .post(`/api/observability/slos`) .set(roleAuthc.apiKeyHeader) @@ -65,6 +39,19 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont return body; }, + async update( + { sloId, slo }: { sloId: string; slo: UpdateSLOInput }, + roleAuthc: RoleCredentials + ) { + const { body } = await supertestWithoutAuth + .put(`/api/observability/slos/${sloId}`) + .set(roleAuthc.apiKeyHeader) + .set(samlAuth.getInternalRequestHeader()) + .send(slo); + + return body; + }, + async delete({ id, roleAuthc }: SloRequestParams) { const response = await supertestWithoutAuth .delete(`/api/observability/slos/${id}`) @@ -73,6 +60,17 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont return response; }, + async findDefinitions(roleAuthc: RoleCredentials): Promise { + const { body } = await supertestWithoutAuth + .get(`/api/observability/slos/_definitions`) + .set(roleAuthc.apiKeyHeader) + .set(samlAuth.getInternalRequestHeader()) + .send() + .expect(200); + + return body; + }, + async fetchHistoricalSummary( params: FetchHistoricalSummaryParams, roleAuthc: RoleCredentials @@ -113,6 +111,24 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont }); }, + async waitForSloUpdated( + { sloId, slo }: { sloId: string; slo: UpdateSLOInput }, + roleAuthc: RoleCredentials + ) { + return await retry.tryForTime(retryTimeout, async () => { + const response = await supertestWithoutAuth + .put(`/api/observability/slos/${sloId}`) + .set(roleAuthc.apiKeyHeader) + .set(samlAuth.getInternalRequestHeader()) + .send(slo) + .timeout(requestTimeout); + if (response.body.id === undefined) { + throw new Error(`No SLO with id '${sloId}' found`); + } + return response.body; + }); + }, + async waitForSloSummaryTempIndexToExist(index: string) { return await retry.tryForTime(retryTimeout, async () => { const indexExists = await es.indices.exists({ index, allow_no_indices: false }); From c39c78b636b9459955b5a47bf2485aaec074ca5e Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 9 Oct 2024 16:02:46 -0400 Subject: [PATCH 02/16] Migrate create slo tests to the agnostic config --- .../apis/observability/alerting/index.ts | 2 +- .../apis/observability/slo/create_slo.ts | 258 ++++++++++++++++++ .../apis/observability/slo/fixtures/slo.ts | 33 +++ .../observability/slo/helpers/dataforge.ts | 24 ++ .../apis/observability/slo/index.ts | 14 + .../configs/serverless/oblt.index.ts | 15 +- .../configs/stateful/oblt.index.ts | 5 +- .../deployment_agnostic/services/slo_api.ts | 2 + 8 files changed, 343 insertions(+), 10 deletions(-) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/fixtures/slo.ts create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts index b2dc2abeca67d..336fcf65c830f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/alerting/index.ts @@ -8,7 +8,7 @@ import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { - describe('Slo - Burn rate rule', () => { + describe('SLO - Burn rate rule', () => { loadTestFile(require.resolve('./burn_rate_rule')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts new file mode 100644 index 0000000000000..53c397536c047 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -0,0 +1,258 @@ +/* + * 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, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const retry = getService('retry'); + const samlAuth = getService('samlAuth'); + const dataViewApi = getService('dataViewApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const config = getService('config'); + + const isServerless = config.get('serverless'); + const expectedConsumer = isServerless ? 'observability' : 'slo'; + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + let internalHeaders: InternalRequestHeader; + + describe('Create SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalHeaders = samlAuth.getInternalRequestHeader(); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('creates a new slo and transforms', async () => { + const apiResponse = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + expect(apiResponse).property('id'); + const { id } = apiResponse; + + const definitions = await sloApi.findDefinitions(adminRoleAuthc); + expect(definitions.total).eql(1); + expect(definitions.results[0]).eql({ + budgetingMethod: 'occurrences', + updatedAt: definitions.results[0].updatedAt, + createdAt: definitions.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', + preventInitialBackfill: false, + }, + tags: ['test'], + timeWindow: { + duration: '7d', + type: 'rolling', + }, + version: 2, + }); + + const rollUpTransformResponse = await supertestWithoutAuth + .get(`/internal/transform/transforms/slo-${id}-1`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(rollUpTransformResponse.body.transforms[0].source.index).eql(['kbn-data-forge*']); + expect(rollUpTransformResponse.body.transforms[0].dest).eql({ + index: '.slo-observability.sli-v3.3', + pipeline: `.slo-observability.sli.pipeline-${id}-1`, + }); + expect(rollUpTransformResponse.body.transforms[0].pivot.group_by).eql({ + 'slo.groupings.tags': { terms: { field: 'tags' } }, + '@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } }, + }); + + const summaryTransform = await supertestWithoutAuth + .get(`/internal/transform/transforms/slo-summary-${id}-1`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(summaryTransform.body.transforms[0].source.index).eql([ + '.slo-observability.sli-v3.3*', + ]); + expect(summaryTransform.body.transforms[0].dest).eql({ + index: '.slo-observability.summary-v3.3', + pipeline: `.slo-observability.summary.pipeline-${id}-1`, + }); + }); + + it('creates instanceId for SLOs with multi groupBy', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: ['system.network.name', 'event.dataset'] }), + adminRoleAuthc + ); + + expect(apiResponse).property('id'); + const { id } = apiResponse; + + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); + + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql( + 'eth1,system.network' + ); + }); + }); + + it('creates instanceId for SLOs with single groupBy', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: 'system.network.name' }), + adminRoleAuthc + ); + + expect(apiResponse).property('id'); + const { id } = apiResponse; + + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); + + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('eth1'); + }); + }); + + it('creates instanceId for SLOs without groupBy ([])', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: [] }), + adminRoleAuthc + ); + + expect(apiResponse).property('id'); + const { id } = apiResponse; + + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); + + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); + }); + + it('creates instanceId for SLOs without groupBy (["*"])', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: ['*'] }), + adminRoleAuthc + ); + + expect(apiResponse).property('id'); + const { id } = apiResponse; + + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); + + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); + }); + + it('creates instanceId for SLOs without groupBy ("")', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: '' }), + adminRoleAuthc + ); + expect(apiResponse).property('id'); + const { id } = apiResponse; + + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); + + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); + }); + }); +} + +const getRollupDataEsQuery = (id: string) => ({ + index: '.slo-observability.sli-v3*', + size: 0, + query: { + bool: { + filter: [ + { + term: { + 'slo.id': id, + }, + }, + ], + }, + }, + aggs: { + last_doc: { + top_hits: { + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + _source: { + includes: ['slo.instanceId'], + }, + size: 1, + }, + }, + }, +}); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/fixtures/slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/fixtures/slo.ts new file mode 100644 index 0000000000000..dfc216760644c --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/fixtures/slo.ts @@ -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 DEFAULT_SLO: 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', +}; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts new file mode 100644 index 0000000000000..fd51f002a557d --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts @@ -0,0 +1,24 @@ +/* + * 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 { Dataset, PartialConfig } from '@kbn/data-forge/src/types'; + +export const DATA_FORGE_CONFIG: PartialConfig = { + schedule: [ + { + template: 'good', + start: 'now-15m', + end: 'now+5m', + metrics: [ + { name: 'system.cpu.user.pct', method: 'linear', start: 2.5, end: 2.5 }, + { name: 'system.cpu.total.pct', method: 'linear', start: 0.5, end: 0.5 }, + { name: 'system.cpu.total.norm.pct', method: 'linear', start: 0.8, end: 0.8 }, + ], + }, + ], + indexing: { dataset: 'fake_hosts' as Dataset, eventsPerCycle: 1, interval: 10000 }, +}; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts new file mode 100644 index 0000000000000..0464d9a1a84ef --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { + describe('SLO', () => { + loadTestFile(require.resolve('./create_slo')); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts index f734f0b805d85..fa6f0bb9aea1a 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts @@ -9,12 +9,13 @@ import { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { describe('Serverless Observability - Deployment-agnostic api integration tests', () => { // load new oblt and platform deployment-agnostic test here - loadTestFile(require.resolve('../../apis/console')); - loadTestFile(require.resolve('../../apis/core')); - loadTestFile(require.resolve('../../apis/management')); - loadTestFile(require.resolve('../../apis/observability/alerting')); - loadTestFile(require.resolve('../../apis/observability/dataset_quality')); - loadTestFile(require.resolve('../../apis/painless_lab')); - loadTestFile(require.resolve('../../apis/saved_objects_management')); + // loadTestFile(require.resolve('../../apis/console')); + // loadTestFile(require.resolve('../../apis/core')); + // loadTestFile(require.resolve('../../apis/management')); + // loadTestFile(require.resolve('../../apis/observability/alerting')); + // loadTestFile(require.resolve('../../apis/observability/dataset_quality')); + // loadTestFile(require.resolve('../../apis/painless_lab')); + // loadTestFile(require.resolve('../../apis/saved_objects_management')); + loadTestFile(require.resolve('../../apis/observability/slo')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts index cb51d672ab972..018c947f8d8ef 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts @@ -10,7 +10,8 @@ import { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { describe('apis', () => { // load new oblt deployment-agnostic test here - loadTestFile(require.resolve('../../apis/observability/alerting')); - loadTestFile(require.resolve('../../apis/observability/dataset_quality')); + // loadTestFile(require.resolve('../../apis/observability/alerting')); + // loadTestFile(require.resolve('../../apis/observability/dataset_quality')); + loadTestFile(require.resolve('../../apis/observability/slo')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts index 756850686ce42..942dbf24ac82e 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts @@ -57,6 +57,7 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont .delete(`/api/observability/slos/${id}`) .set(roleAuthc.apiKeyHeader) .set(samlAuth.getInternalRequestHeader()); + return response; }, @@ -80,6 +81,7 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont .set(roleAuthc.apiKeyHeader) .set(samlAuth.getInternalRequestHeader()) .send(params); + return body; }, From ee711fbc123250386ad160ace2cb49f73f8367d7 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 10 Oct 2024 11:08:22 -0400 Subject: [PATCH 03/16] Add delete SLO tests --- .../apis/observability/slo/delete_slo.ts | 145 ++++++++++++++++++ .../apis/observability/slo/index.ts | 1 + 2 files changed, 146 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts new file mode 100644 index 0000000000000..6422fa243efee --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -0,0 +1,145 @@ +/* + * 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, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { + SLO_DESTINATION_INDEX_PATTERN, + SLO_SUMMARY_DESTINATION_INDEX_PATTERN, +} from '@kbn/slo-plugin/common/constants'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const retry = getService('retry'); + const samlAuth = getService('samlAuth'); + const dataViewApi = getService('dataViewApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const config = getService('config'); + + const isServerless = config.get('serverless'); + const expectedConsumer = isServerless ? 'observability' : 'slo'; + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + let internalHeaders: InternalRequestHeader; + + describe('Delete SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalHeaders = samlAuth.getInternalRequestHeader(); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('deletes SLO and related resources', async () => { + const response = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + expect(response).property('id'); + const id = response.id; + + await sloApi.delete({ id, roleAuthc: adminRoleAuthc }); + + // Expect no definitions exists + const definitions = await sloApi.findDefinitions(adminRoleAuthc); + expect(definitions.total).eql(0); + + await retry.waitForWithTimeout('Transforms are deleted', 60 * 1000, async () => { + // roll up transform should be deleted + await supertestWithoutAuth + .get(`/internal/transform/transforms/slo-${id}-1`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(404); + + // summary transform should be deleted + await supertestWithoutAuth + .get(`/internal/transform/transforms/slo-summary-${id}-1`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(404); + + return true; + }); + + // expect summary and rollup documents to be deleted + await retry.waitForWithTimeout('SLO summary data is deleted', 60 * 1000, async () => { + const sloSummaryResponseAfterDeletion = await esClient.search({ + index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN, + body: { + query: { + bool: { + filter: [ + { + term: { 'slo.id': id }, + }, + { + term: { isTempDoc: false }, + }, + ], + }, + }, + }, + }); + if (sloSummaryResponseAfterDeletion.hits.hits.length > 0) { + throw new Error('SLO summary data not deleted yet'); + } + return true; + }); + + await retry.waitForWithTimeout('SLO rollup data is deleted', 60 * 1000, async () => { + const sloRollupResponseAfterDeletion = await esClient.search({ + index: SLO_DESTINATION_INDEX_PATTERN, + body: { + query: { + bool: { + filter: [ + { + term: { 'slo.id': id }, + }, + ], + }, + }, + }, + }); + if (sloRollupResponseAfterDeletion.hits.hits.length > 1) { + throw new Error('SLO rollup data not deleted yet'); + } + return true; + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts index 0464d9a1a84ef..3834b72e9375f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -10,5 +10,6 @@ import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_cont export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { describe('SLO', () => { loadTestFile(require.resolve('./create_slo')); + loadTestFile(require.resolve('./delete_slo')); }); } From 5ff35c4ea94cde949b5ea7381a728483b1fb6871 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 10 Oct 2024 11:40:32 -0400 Subject: [PATCH 04/16] Add get_slo tests --- .../apis/observability/slo/get_slo.ts | 117 ++++++++++++++++++ .../apis/observability/slo/index.ts | 1 + 2 files changed, 118 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts new file mode 100644 index 0000000000000..a3a79ee958c88 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -0,0 +1,117 @@ +/* + * 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, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const retry = getService('retry'); + const samlAuth = getService('samlAuth'); + const dataViewApi = getService('dataViewApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const config = getService('config'); + + const isServerless = config.get('serverless'); + const expectedConsumer = isServerless ? 'observability' : 'slo'; + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + let internalHeaders: InternalRequestHeader; + + describe('Get SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalHeaders = samlAuth.getInternalRequestHeader(); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('find SLOs', async () => { + const createResponse1 = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + await sloApi.create( + Object.assign({}, DEFAULT_SLO, { name: 'something irrelevant foo' }), + adminRoleAuthc + ); + + expect(createResponse1).property('id'); + const sloId1 = createResponse1.id; + + // get the slo by ID + const getSloResponse = await sloApi.waitForSloCreated({ + id: sloId1, + roleAuthc: adminRoleAuthc, + }); + // We cannot assert on the summary values itself - it would make the test too flaky + // But we can assert on the existence of these fields at least. + // On top of whatever the SLO definition contains. + expect(getSloResponse).property('summary'); + expect(getSloResponse).property('meta'); + expect(getSloResponse).property('instanceId'); + expect(getSloResponse.budgetingMethod).eql('occurrences'); + expect(getSloResponse.timeWindow).eql({ duration: '7d', type: 'rolling' }); + + await retry.tryForTime(360 * 1000, async () => { + let response = await supertestWithoutAuth + .get(`/api/observability/slos`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send(); + + expect(response.body.results).length(2); + + response = await supertestWithoutAuth + .get(`/api/observability/slos?kqlQuery=slo.name%3Airrelevant`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(response.body.results).length(1); + + response = await supertestWithoutAuth + .get(`/api/observability/slos?kqlQuery=slo.name%3Aintegration`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(response.body.results).length(1); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts index 3834b72e9375f..1ed7f52eeb18d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -11,5 +11,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) describe('SLO', () => { loadTestFile(require.resolve('./create_slo')); loadTestFile(require.resolve('./delete_slo')); + loadTestFile(require.resolve('./get_slo')); }); } From f2f973cdf984463d10646f669492e21368c0adf9 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 10 Oct 2024 11:52:26 -0400 Subject: [PATCH 05/16] Add search SLO tests --- .../apis/observability/slo/find_slo.ts | 108 ++++++++++++++++++ .../apis/observability/slo/get_slo.ts | 33 +----- .../apis/observability/slo/index.ts | 1 + 3 files changed, 110 insertions(+), 32 deletions(-) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts new file mode 100644 index 0000000000000..1b3d73d3593e6 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts @@ -0,0 +1,108 @@ +/* + * 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, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const retry = getService('retry'); + const samlAuth = getService('samlAuth'); + const dataViewApi = getService('dataViewApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const config = getService('config'); + + const isServerless = config.get('serverless'); + const expectedConsumer = isServerless ? 'observability' : 'slo'; + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + let internalHeaders: InternalRequestHeader; + + describe('Find SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalHeaders = samlAuth.getInternalRequestHeader(); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('searches SLOs', async () => { + const createResponse1 = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + const createResponse2 = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { name: 'something irrelevant foo' }), + adminRoleAuthc + ); + + const sloId1 = createResponse1.id; + const sloId2 = createResponse2.id; + + // search SLOs + await retry.tryForTime(360 * 1000, async () => { + let response = await supertestWithoutAuth + .get(`/api/observability/slos`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send(); + + expect(response.body.results).length(2); + + response = await supertestWithoutAuth + .get(`/api/observability/slos?kqlQuery=slo.name%3Airrelevant`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(response.body.results).length(1); + expect(response.body.results[0].id).eql(sloId2); + + response = await supertestWithoutAuth + .get(`/api/observability/slos?kqlQuery=slo.name%3Aintegration`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .expect(200); + + expect(response.body.results).length(1); + expect(response.body.results[0].id).eql(sloId1); + + return true; + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts index a3a79ee958c88..27e300ff60977 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -58,7 +58,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - it('find SLOs', async () => { + it('get SLO by id', async () => { const createResponse1 = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); await sloApi.create( Object.assign({}, DEFAULT_SLO, { name: 'something irrelevant foo' }), @@ -81,37 +81,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(getSloResponse).property('instanceId'); expect(getSloResponse.budgetingMethod).eql('occurrences'); expect(getSloResponse.timeWindow).eql({ duration: '7d', type: 'rolling' }); - - await retry.tryForTime(360 * 1000, async () => { - let response = await supertestWithoutAuth - .get(`/api/observability/slos`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send(); - - expect(response.body.results).length(2); - - response = await supertestWithoutAuth - .get(`/api/observability/slos?kqlQuery=slo.name%3Airrelevant`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(200); - - expect(response.body.results).length(1); - - response = await supertestWithoutAuth - .get(`/api/observability/slos?kqlQuery=slo.name%3Aintegration`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(200); - - expect(response.body.results).length(1); - }); }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts index 1ed7f52eeb18d..5b7235bc8b0eb 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('./create_slo')); loadTestFile(require.resolve('./delete_slo')); loadTestFile(require.resolve('./get_slo')); + loadTestFile(require.resolve('./find_slo')); }); } From 0392e95b71e6f0d723529d6a3d95099784ba2a0d Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 10 Oct 2024 11:56:21 -0400 Subject: [PATCH 06/16] Reduce interval --- .../apis/observability/slo/helpers/dataforge.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts index fd51f002a557d..04da0f81a0643 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/dataforge.ts @@ -20,5 +20,5 @@ export const DATA_FORGE_CONFIG: PartialConfig = { ], }, ], - indexing: { dataset: 'fake_hosts' as Dataset, eventsPerCycle: 1, interval: 10000 }, + indexing: { dataset: 'fake_hosts' as Dataset, eventsPerCycle: 1 }, }; From 67ebabe6ff7970b13cdc5f9a6f4474e4905c3a4c Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:00:31 -0400 Subject: [PATCH 07/16] Add reset api tests --- .../apis/observability/slo/index.ts | 1 + .../apis/observability/slo/reset_slo.ts | 78 +++++++++++++++++++ .../deployment_agnostic/services/slo_api.ts | 10 +++ 3 files changed, 89 insertions(+) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts index 5b7235bc8b0eb..38e4d16c8380d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -13,5 +13,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('./delete_slo')); loadTestFile(require.resolve('./get_slo')); loadTestFile(require.resolve('./find_slo')); + loadTestFile(require.resolve('./reset_slo')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts new file mode 100644 index 0000000000000..86a05cade928d --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts @@ -0,0 +1,78 @@ +/* + * 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, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { getSLOPipelineId } from '@kbn/slo-plugin/common/constants'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const retry = getService('retry'); + const samlAuth = getService('samlAuth'); + const dataViewApi = getService('dataViewApi'); + const config = getService('config'); + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + + describe('Reset SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('resets the related resources', async () => { + const createResponse = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + expect(createResponse).property('id'); + const sloId = createResponse.id; + const sloPipelineId = getSLOPipelineId(sloId, 1); + + // Delete the slo rollup ingest pipeline + await retry.tryForTime(60 * 1000, async () => { + await esClient.ingest.deletePipeline({ id: sloPipelineId }); + return true; + }); + + // reset + await sloApi.reset(sloId, adminRoleAuthc); + + // assert the pipeline is re-created + await retry.tryForTime(60 * 1000, async () => { + const response = await esClient.ingest.getPipeline({ id: sloPipelineId }); + return !!response[sloPipelineId]; + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts index 942dbf24ac82e..47e6e3cc1a846 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts @@ -39,6 +39,16 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont return body; }, + async reset(id: string, roleAuthc: RoleCredentials) { + const { body } = await supertestWithoutAuth + .post(`/api/observability/slos/${id}/_reset`) + .set(roleAuthc.apiKeyHeader) + .set(samlAuth.getInternalRequestHeader()) + .send(); + + return body; + }, + async update( { sloId, slo }: { sloId: string; slo: UpdateSLOInput }, roleAuthc: RoleCredentials From 1ee8e437108e041744fcc2b36948b24c86a6e8ef Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:03:58 -0400 Subject: [PATCH 08/16] Cleanup tests --- .../apis/observability/slo/create_slo.ts | 4 ---- .../apis/observability/slo/delete_slo.ts | 4 ---- .../apis/observability/slo/find_slo.ts | 4 ---- .../apis/observability/slo/get_slo.ts | 10 +--------- .../apis/observability/slo/reset_slo.ts | 1 - 5 files changed, 1 insertion(+), 22 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts index 53c397536c047..340fb7f9c8af7 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -20,10 +20,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const config = getService('config'); - - const isServerless = config.get('serverless'); - const expectedConsumer = isServerless ? 'observability' : 'slo'; const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index 6422fa243efee..6ad2c0dc93073 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -24,10 +24,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const config = getService('config'); - - const isServerless = config.get('serverless'); - const expectedConsumer = isServerless ? 'observability' : 'slo'; const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts index 1b3d73d3593e6..df34b4fe890e7 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts @@ -20,10 +20,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const config = getService('config'); - - const isServerless = config.get('serverless'); - const expectedConsumer = isServerless ? 'observability' : 'slo'; const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts index 27e300ff60977..d0a53988e7ac4 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -7,7 +7,7 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; -import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; import { DATA_FORGE_CONFIG } from './helpers/dataforge'; @@ -16,25 +16,17 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const esClient = getService('es'); const sloApi = getService('sloApi'); const logger = getService('log'); - const retry = getService('retry'); const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const config = getService('config'); - - const isServerless = config.get('serverless'); - const expectedConsumer = isServerless ? 'observability' : 'slo'; const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; - let internalHeaders: InternalRequestHeader; describe('Get SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - internalHeaders = samlAuth.getInternalRequestHeader(); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts index 86a05cade928d..3b8f4a8daab3d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts @@ -20,7 +20,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const retry = getService('retry'); const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); - const config = getService('config'); const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; From 6ba6a77650af24215ccccdeef8eb7d8f3494040e Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:27:14 -0400 Subject: [PATCH 09/16] Add update slo tests --- .../apis/observability/slo/delete_slo.ts | 2 +- .../apis/observability/slo/get_slo.ts | 5 +- .../apis/observability/slo/index.ts | 1 + .../apis/observability/slo/reset_slo.ts | 6 +- .../apis/observability/slo/update_slo.ts | 131 ++++++++++++++++++ .../deployment_agnostic/services/slo_api.ts | 28 +++- 6 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index 6ad2c0dc93073..b1786f242d8be 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -63,7 +63,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(response).property('id'); const id = response.id; - await sloApi.delete({ id, roleAuthc: adminRoleAuthc }); + await sloApi.delete(id, adminRoleAuthc); // Expect no definitions exists const definitions = await sloApi.findDefinitions(adminRoleAuthc); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts index d0a53988e7ac4..401c7104c0121 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -61,10 +61,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const sloId1 = createResponse1.id; // get the slo by ID - const getSloResponse = await sloApi.waitForSloCreated({ - id: sloId1, - roleAuthc: adminRoleAuthc, - }); + const getSloResponse = await sloApi.get(sloId1, adminRoleAuthc); // We cannot assert on the summary values itself - it would make the test too flaky // But we can assert on the existence of these fields at least. // On top of whatever the SLO definition contains. diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts index 38e4d16c8380d..d47438d163b13 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/index.ts @@ -14,5 +14,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('./get_slo')); loadTestFile(require.resolve('./find_slo')); loadTestFile(require.resolve('./reset_slo')); + loadTestFile(require.resolve('./update_slo')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts index 3b8f4a8daab3d..33b9808dff5c8 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts @@ -8,7 +8,7 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; import { RoleCredentials } from '@kbn/ftr-common-functional-services'; -import { getSLOPipelineId } from '@kbn/slo-plugin/common/constants'; +import { SLO_MODEL_VERSION, getSLOPipelineId } from '@kbn/slo-plugin/common/constants'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; import { DATA_FORGE_CONFIG } from './helpers/dataforge'; @@ -65,7 +65,9 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { }); // reset - await sloApi.reset(sloId, adminRoleAuthc); + const resetResponse = await sloApi.reset(sloId, adminRoleAuthc); + expect(resetResponse).property('version', SLO_MODEL_VERSION); + expect(resetResponse).property('revision', 1); // assert the pipeline is re-created await retry.tryForTime(60 * 1000, async () => { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts new file mode 100644 index 0000000000000..232c837c7e70e --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts @@ -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 { cleanup, generate } from '@kbn/data-forge'; +import expect from '@kbn/expect'; +import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { getSLOSummaryTransformId, getSLOTransformId } from '@kbn/slo-plugin/common/constants'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { DEFAULT_SLO } from './fixtures/slo'; +import { DATA_FORGE_CONFIG } from './helpers/dataforge'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const esClient = getService('es'); + const sloApi = getService('sloApi'); + const logger = getService('log'); + const samlAuth = getService('samlAuth'); + const retry = getService('retry'); + const dataViewApi = getService('dataViewApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; + const DATA_VIEW_ID = 'data-view-id'; + + let adminRoleAuthc: RoleCredentials; + let internalHeaders: InternalRequestHeader; + + describe('Update SLOs', function () { + before(async () => { + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalHeaders = samlAuth.getInternalRequestHeader(); + + await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + + await dataViewApi.create({ + roleAuthc: adminRoleAuthc, + name: DATA_VIEW, + id: DATA_VIEW_ID, + title: DATA_VIEW, + }); + + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + afterEach(async () => { + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + after(async () => { + await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); + await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); + await sloApi.deleteAllSLOs(adminRoleAuthc); + }); + + it('updates the definition without a revision bump', async () => { + const createResponse = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + const sloId = createResponse.id; + + const getResponse = await sloApi.get(sloId, adminRoleAuthc); + expect(getResponse).property('revision', 1); + + const updateResponse = await sloApi.update( + { sloId, slo: Object.assign({}, DEFAULT_SLO, { name: 'updated name' }) }, + adminRoleAuthc + ); + expect(updateResponse).property('revision', 1); + expect(updateResponse).property('name', 'updated name'); + + await assertTransformExist(getSLOTransformId(sloId, 1)); + await assertTransformExist(getSLOSummaryTransformId(sloId, 1)); + }); + + it('updates the definition with a revision bump', async () => { + const createResponse = await sloApi.create(DEFAULT_SLO, adminRoleAuthc); + const sloId = createResponse.id; + + const getResponse = await sloApi.get(sloId, adminRoleAuthc); + expect(getResponse).property('revision', 1); + + const updateResponse = await sloApi.update( + { sloId, slo: Object.assign({}, DEFAULT_SLO, { objective: { target: 0.63 } }) }, + adminRoleAuthc + ); + expect(updateResponse).property('revision', 2); + expect(updateResponse.objective).eql({ target: 0.63 }); + + await assertTransformDeleted(getSLOTransformId(sloId, 1)); + await assertTransformDeleted(getSLOSummaryTransformId(sloId, 1)); + + await assertTransformExist(getSLOTransformId(sloId, 2)); + await assertTransformExist(getSLOSummaryTransformId(sloId, 2)); + }); + }); + + async function assertTransformDeleted(transformId: string) { + return await retry.tryWithRetries( + `Wait for transform ${transformId} to be deleted`, + async () => { + await supertestWithoutAuth + .get(`/internal/transform/transforms/${transformId}`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .timeout(10000) + .expect(404); + }, + { retryCount: 5, retryDelay: 2000 } + ); + } + + async function assertTransformExist(transformId: string) { + return await retry.tryWithRetries( + `Wait for transform ${transformId} to exist`, + async () => { + await supertestWithoutAuth + .get(`/internal/transform/transforms/${transformId}`) + .set(adminRoleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .timeout(10000) + .expect(200); + }, + { retryCount: 5, retryDelay: 2000 } + ); + } +} diff --git a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts index 47e6e3cc1a846..5b8f70380e46c 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts @@ -35,7 +35,8 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont .post(`/api/observability/slos`) .set(roleAuthc.apiKeyHeader) .set(samlAuth.getInternalRequestHeader()) - .send(slo); + .send(slo) + .expect(200); return body; }, @@ -44,7 +45,8 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont .post(`/api/observability/slos/${id}/_reset`) .set(roleAuthc.apiKeyHeader) .set(samlAuth.getInternalRequestHeader()) - .send(); + .send() + .expect(200); return body; }, @@ -57,18 +59,30 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont .put(`/api/observability/slos/${sloId}`) .set(roleAuthc.apiKeyHeader) .set(samlAuth.getInternalRequestHeader()) - .send(slo); + .send(slo) + .expect(200); return body; }, - async delete({ id, roleAuthc }: SloRequestParams) { - const response = await supertestWithoutAuth + async delete(id: string, roleAuthc: RoleCredentials) { + return await supertestWithoutAuth .delete(`/api/observability/slos/${id}`) .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()); + .set(samlAuth.getInternalRequestHeader()) + .send() + .expect(204); + }, + + async get(id: string, roleAuthc: RoleCredentials) { + const { body } = await supertestWithoutAuth + .get(`/api/observability/slos/${id}`) + .set(roleAuthc.apiKeyHeader) + .set(samlAuth.getInternalRequestHeader()) + .send() + .expect(200); - return response; + return body; }, async findDefinitions(roleAuthc: RoleCredentials): Promise { From 616d4a5ecd360e829357945bf48a50f90271a8ac Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:44:57 -0400 Subject: [PATCH 10/16] Update helpers --- .../apis/observability/slo/create_slo.ts | 35 ++++------- .../apis/observability/slo/delete_slo.ts | 30 +++------- .../observability/slo/helpers/transform.ts | 59 +++++++++++++++++++ .../apis/observability/slo/update_slo.ts | 51 +++------------- 4 files changed, 88 insertions(+), 87 deletions(-) create mode 100644 x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts index 340fb7f9c8af7..be28cabf6a049 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -8,9 +8,11 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { getSLOSummaryTransformId, getSLOTransformId } from '@kbn/slo-plugin/common/constants'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; import { DATA_FORGE_CONFIG } from './helpers/dataforge'; +import { TransformHelper, createTransformHelper } from './helpers/transform'; export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const esClient = getService('es'); @@ -19,18 +21,19 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const retry = getService('retry'); const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; let internalHeaders: InternalRequestHeader; + let transformHelper: TransformHelper; describe('Create SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); internalHeaders = samlAuth.getInternalRequestHeader(); + transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -97,36 +100,24 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { version: 2, }); - const rollUpTransformResponse = await supertestWithoutAuth - .get(`/internal/transform/transforms/slo-${id}-1`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(200); - - expect(rollUpTransformResponse.body.transforms[0].source.index).eql(['kbn-data-forge*']); - expect(rollUpTransformResponse.body.transforms[0].dest).eql({ + const rollUpTransformResponse = await transformHelper.assertExist(getSLOTransformId(id, 1)); + expect(rollUpTransformResponse.transforms[0].source.index).eql(['kbn-data-forge*']); + expect(rollUpTransformResponse.transforms[0].dest).eql({ index: '.slo-observability.sli-v3.3', pipeline: `.slo-observability.sli.pipeline-${id}-1`, }); - expect(rollUpTransformResponse.body.transforms[0].pivot.group_by).eql({ + expect(rollUpTransformResponse.transforms[0].pivot.group_by).eql({ 'slo.groupings.tags': { terms: { field: 'tags' } }, '@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } }, }); - const summaryTransform = await supertestWithoutAuth - .get(`/internal/transform/transforms/slo-summary-${id}-1`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(200); - - expect(summaryTransform.body.transforms[0].source.index).eql([ + const summaryTransformResponse = await transformHelper.assertExist( + getSLOSummaryTransformId(id, 1) + ); + expect(summaryTransformResponse.transforms[0].source.index).eql([ '.slo-observability.sli-v3.3*', ]); - expect(summaryTransform.body.transforms[0].dest).eql({ + expect(summaryTransformResponse.transforms[0].dest).eql({ index: '.slo-observability.summary-v3.3', pipeline: `.slo-observability.summary.pipeline-${id}-1`, }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index b1786f242d8be..48229967902a1 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -11,10 +11,13 @@ import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-function import { SLO_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, + getSLOSummaryTransformId, + getSLOTransformId, } from '@kbn/slo-plugin/common/constants'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; import { DATA_FORGE_CONFIG } from './helpers/dataforge'; +import { TransformHelper, createTransformHelper } from './helpers/transform'; export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const esClient = getService('es'); @@ -23,18 +26,19 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const retry = getService('retry'); const samlAuth = getService('samlAuth'); const dataViewApi = getService('dataViewApi'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; let internalHeaders: InternalRequestHeader; + let transformHelper: TransformHelper; describe('Delete SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); internalHeaders = samlAuth.getInternalRequestHeader(); + transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -69,28 +73,8 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const definitions = await sloApi.findDefinitions(adminRoleAuthc); expect(definitions.total).eql(0); - await retry.waitForWithTimeout('Transforms are deleted', 60 * 1000, async () => { - // roll up transform should be deleted - await supertestWithoutAuth - .get(`/internal/transform/transforms/slo-${id}-1`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(404); - - // summary transform should be deleted - await supertestWithoutAuth - .get(`/internal/transform/transforms/slo-summary-${id}-1`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .expect(404); - - return true; - }); - + await transformHelper.assertNotFound(getSLOTransformId(id, 1)); + await transformHelper.assertNotFound(getSLOSummaryTransformId(id, 1)); // expect summary and rollup documents to be deleted await retry.waitForWithTimeout('SLO summary data is deleted', 60 * 1000, async () => { const sloSummaryResponseAfterDeletion = await esClient.search({ diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts new file mode 100644 index 0000000000000..5d8913e4b3b6b --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts @@ -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 { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; +import { InternalRequestHeader, RoleCredentials } from '../../../../services'; + +export type TransformHelper = ReturnType; + +export function createTransformHelper( + getService: DeploymentAgnosticFtrProviderContext['getService'], + roleAuthc: RoleCredentials, + internalHeaders: InternalRequestHeader +) { + const retry = getService('retry'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + return { + assertNotFound: async (transformId: string) => { + return await retry.tryWithRetries( + `Wait for transform ${transformId} to be deleted`, + async () => { + const response = await supertestWithoutAuth + .get(`/internal/transform/transforms/${transformId}`) + .set(roleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .timeout(10000) + .expect(404); + + return response.body; + }, + { retryCount: 5, retryDelay: 2000 } + ); + }, + + assertExist: async (transformId: string) => { + return await retry.tryWithRetries( + `Wait for transform ${transformId} to exist`, + async () => { + const response = await supertestWithoutAuth + .get(`/internal/transform/transforms/${transformId}`) + .set(roleAuthc.apiKeyHeader) + .set(internalHeaders) + .set('elastic-api-version', '1') + .send() + .timeout(10000) + .expect(200); + return response.body; + }, + { retryCount: 5, retryDelay: 2000 } + ); + }, + }; +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts index 232c837c7e70e..afabbfa131f38 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts @@ -12,26 +12,27 @@ import { getSLOSummaryTransformId, getSLOTransformId } from '@kbn/slo-plugin/com import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; import { DATA_FORGE_CONFIG } from './helpers/dataforge'; +import { TransformHelper, createTransformHelper } from './helpers/transform'; export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const esClient = getService('es'); const sloApi = getService('sloApi'); const logger = getService('log'); const samlAuth = getService('samlAuth'); - const retry = getService('retry'); const dataViewApi = getService('dataViewApi'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); const DATA_VIEW = 'kbn-data-forge-fake_hosts.fake_hosts-*'; const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; let internalHeaders: InternalRequestHeader; + let transformHelper: TransformHelper; describe('Update SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); internalHeaders = samlAuth.getInternalRequestHeader(); + transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -69,8 +70,8 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(updateResponse).property('revision', 1); expect(updateResponse).property('name', 'updated name'); - await assertTransformExist(getSLOTransformId(sloId, 1)); - await assertTransformExist(getSLOSummaryTransformId(sloId, 1)); + await transformHelper.assertExist(getSLOTransformId(sloId, 1)); + await transformHelper.assertExist(getSLOSummaryTransformId(sloId, 1)); }); it('updates the definition with a revision bump', async () => { @@ -87,45 +88,11 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(updateResponse).property('revision', 2); expect(updateResponse.objective).eql({ target: 0.63 }); - await assertTransformDeleted(getSLOTransformId(sloId, 1)); - await assertTransformDeleted(getSLOSummaryTransformId(sloId, 1)); + await transformHelper.assertNotFound(getSLOTransformId(sloId, 1)); + await transformHelper.assertNotFound(getSLOSummaryTransformId(sloId, 1)); - await assertTransformExist(getSLOTransformId(sloId, 2)); - await assertTransformExist(getSLOSummaryTransformId(sloId, 2)); + await transformHelper.assertExist(getSLOTransformId(sloId, 2)); + await transformHelper.assertExist(getSLOSummaryTransformId(sloId, 2)); }); }); - - async function assertTransformDeleted(transformId: string) { - return await retry.tryWithRetries( - `Wait for transform ${transformId} to be deleted`, - async () => { - await supertestWithoutAuth - .get(`/internal/transform/transforms/${transformId}`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .timeout(10000) - .expect(404); - }, - { retryCount: 5, retryDelay: 2000 } - ); - } - - async function assertTransformExist(transformId: string) { - return await retry.tryWithRetries( - `Wait for transform ${transformId} to exist`, - async () => { - await supertestWithoutAuth - .get(`/internal/transform/transforms/${transformId}`) - .set(adminRoleAuthc.apiKeyHeader) - .set(internalHeaders) - .set('elastic-api-version', '1') - .send() - .timeout(10000) - .expect(200); - }, - { retryCount: 5, retryDelay: 2000 } - ); - } } From 0c878b4cfdee0ed5f07ea4741ece9d10a1897a79 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:54:31 -0400 Subject: [PATCH 11/16] Remove unused function --- .../apis/observability/slo/create_slo.ts | 130 +++++++++--------- .../apis/observability/slo/delete_slo.ts | 6 +- .../observability/slo/helpers/transform.ts | 10 +- .../apis/observability/slo/update_slo.ts | 6 +- .../deployment_agnostic/services/slo_api.ts | 118 +--------------- 5 files changed, 75 insertions(+), 195 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts index be28cabf6a049..f182a08d6cf84 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -7,7 +7,7 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; -import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { getSLOSummaryTransformId, getSLOTransformId } from '@kbn/slo-plugin/common/constants'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; @@ -26,14 +26,12 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; - let internalHeaders: InternalRequestHeader; let transformHelper: TransformHelper; describe('Create SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - internalHeaders = samlAuth.getInternalRequestHeader(); - transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); + transformHelper = createTransformHelper(getService, adminRoleAuthc); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -123,89 +121,91 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { }); }); - it('creates instanceId for SLOs with multi groupBy', async () => { - const apiResponse = await sloApi.create( - Object.assign({}, DEFAULT_SLO, { groupBy: ['system.network.name', 'event.dataset'] }), - adminRoleAuthc - ); + describe('groupBy smoke tests', () => { + it('creates instanceId for SLOs with multi groupBy', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: ['system.network.name', 'event.dataset'] }), + adminRoleAuthc + ); - expect(apiResponse).property('id'); - const { id } = apiResponse; + expect(apiResponse).property('id'); + const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { - const response = await esClient.search(getRollupDataEsQuery(id)); + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); - // @ts-ignore - expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql( - 'eth1,system.network' - ); + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql( + 'eth1,system.network' + ); + }); }); - }); - it('creates instanceId for SLOs with single groupBy', async () => { - const apiResponse = await sloApi.create( - Object.assign({}, DEFAULT_SLO, { groupBy: 'system.network.name' }), - adminRoleAuthc - ); + it('creates instanceId for SLOs with single groupBy', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: 'system.network.name' }), + adminRoleAuthc + ); - expect(apiResponse).property('id'); - const { id } = apiResponse; + expect(apiResponse).property('id'); + const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { - const response = await esClient.search(getRollupDataEsQuery(id)); + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); - // @ts-ignore - expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('eth1'); + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('eth1'); + }); }); - }); - it('creates instanceId for SLOs without groupBy ([])', async () => { - const apiResponse = await sloApi.create( - Object.assign({}, DEFAULT_SLO, { groupBy: [] }), - adminRoleAuthc - ); + it('creates instanceId for SLOs without groupBy ([])', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: [] }), + adminRoleAuthc + ); - expect(apiResponse).property('id'); - const { id } = apiResponse; + expect(apiResponse).property('id'); + const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { - const response = await esClient.search(getRollupDataEsQuery(id)); + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); - // @ts-ignore - expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); }); - }); - it('creates instanceId for SLOs without groupBy (["*"])', async () => { - const apiResponse = await sloApi.create( - Object.assign({}, DEFAULT_SLO, { groupBy: ['*'] }), - adminRoleAuthc - ); + it('creates instanceId for SLOs without groupBy (["*"])', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: ['*'] }), + adminRoleAuthc + ); - expect(apiResponse).property('id'); - const { id } = apiResponse; + expect(apiResponse).property('id'); + const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { - const response = await esClient.search(getRollupDataEsQuery(id)); + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); - // @ts-ignore - expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); }); - }); - it('creates instanceId for SLOs without groupBy ("")', async () => { - const apiResponse = await sloApi.create( - Object.assign({}, DEFAULT_SLO, { groupBy: '' }), - adminRoleAuthc - ); - expect(apiResponse).property('id'); - const { id } = apiResponse; + it('creates instanceId for SLOs without groupBy ("")', async () => { + const apiResponse = await sloApi.create( + Object.assign({}, DEFAULT_SLO, { groupBy: '' }), + adminRoleAuthc + ); + expect(apiResponse).property('id'); + const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { - const response = await esClient.search(getRollupDataEsQuery(id)); + await retry.tryForTime(300 * 1000, async () => { + const response = await esClient.search(getRollupDataEsQuery(id)); - // @ts-ignore - expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + // @ts-ignore + expect(response.aggregations?.last_doc.hits?.hits[0]._source.slo.instanceId).eql('*'); + }); }); }); }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index 48229967902a1..a94c32dc52d1c 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -7,7 +7,7 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; -import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { SLO_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, @@ -31,14 +31,12 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; - let internalHeaders: InternalRequestHeader; let transformHelper: TransformHelper; describe('Delete SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - internalHeaders = samlAuth.getInternalRequestHeader(); - transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); + transformHelper = createTransformHelper(getService, adminRoleAuthc); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts index 5d8913e4b3b6b..80a5f9b206ac1 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts @@ -6,17 +6,17 @@ */ import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; -import { InternalRequestHeader, RoleCredentials } from '../../../../services'; +import { RoleCredentials } from '../../../../services'; export type TransformHelper = ReturnType; export function createTransformHelper( getService: DeploymentAgnosticFtrProviderContext['getService'], - roleAuthc: RoleCredentials, - internalHeaders: InternalRequestHeader + roleAuthc: RoleCredentials ) { const retry = getService('retry'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const samlAuth = getService('samlAuth'); return { assertNotFound: async (transformId: string) => { @@ -26,7 +26,7 @@ export function createTransformHelper( const response = await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) .set(roleAuthc.apiKeyHeader) - .set(internalHeaders) + .set(samlAuth.getInternalRequestHeader()) .set('elastic-api-version', '1') .send() .timeout(10000) @@ -45,7 +45,7 @@ export function createTransformHelper( const response = await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) .set(roleAuthc.apiKeyHeader) - .set(internalHeaders) + .set(samlAuth.getInternalRequestHeader()) .set('elastic-api-version', '1') .send() .timeout(10000) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts index afabbfa131f38..498293128a4a6 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts @@ -7,7 +7,7 @@ import { cleanup, generate } from '@kbn/data-forge'; import expect from '@kbn/expect'; -import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { RoleCredentials } from '@kbn/ftr-common-functional-services'; import { getSLOSummaryTransformId, getSLOTransformId } from '@kbn/slo-plugin/common/constants'; import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; import { DEFAULT_SLO } from './fixtures/slo'; @@ -25,14 +25,12 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const DATA_VIEW_ID = 'data-view-id'; let adminRoleAuthc: RoleCredentials; - let internalHeaders: InternalRequestHeader; let transformHelper: TransformHelper; describe('Update SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - internalHeaders = samlAuth.getInternalRequestHeader(); - transformHelper = createTransformHelper(getService, adminRoleAuthc, internalHeaders); + transformHelper = createTransformHelper(getService, adminRoleAuthc); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts index 5b8f70380e46c..8ee202b2cf23e 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/slo_api.ts @@ -6,28 +6,12 @@ */ import { RoleCredentials } from '@kbn/ftr-common-functional-services'; -import { - CreateSLOInput, - FetchHistoricalSummaryParams, - FetchHistoricalSummaryResponse, - FindSLODefinitionsResponse, - UpdateSLOInput, -} from '@kbn/slo-schema'; +import { CreateSLOInput, FindSLODefinitionsResponse, UpdateSLOInput } from '@kbn/slo-schema'; import { DeploymentAgnosticFtrProviderContext } from '../ftr_provider_context'; -interface SloRequestParams { - id: string; - roleAuthc: RoleCredentials; -} - export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderContext) { - const es = getService('es'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const samlAuth = getService('samlAuth'); - const retry = getService('retry'); - const config = getService('config'); - const retryTimeout = config.get('timeouts.try'); - const requestTimeout = 30 * 1000; return { async create(slo: CreateSLOInput, roleAuthc: RoleCredentials) { @@ -96,106 +80,6 @@ export function SloApiProvider({ getService }: DeploymentAgnosticFtrProviderCont return body; }, - async fetchHistoricalSummary( - params: FetchHistoricalSummaryParams, - roleAuthc: RoleCredentials - ): Promise { - const { body } = await supertestWithoutAuth - .post(`/internal/observability/slos/_historical_summary`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) - .send(params); - - return body; - }, - - async waitForSloToBeDeleted({ id, roleAuthc }: SloRequestParams) { - return await retry.tryForTime(retryTimeout, async () => { - const response = await supertestWithoutAuth - .delete(`/api/observability/slos/${id}`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) - .timeout(requestTimeout); - if (!response.ok) { - throw new Error(`SLO with id '${id}' was not deleted`); - } - return response; - }); - }, - - async waitForSloCreated({ id, roleAuthc }: SloRequestParams) { - return await retry.tryForTime(retryTimeout, async () => { - const response = await supertestWithoutAuth - .get(`/api/observability/slos/${id}`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) - .timeout(requestTimeout); - if (response.body.id === undefined) { - throw new Error(`No SLO with id '${id}' found`); - } - return response.body; - }); - }, - - async waitForSloUpdated( - { sloId, slo }: { sloId: string; slo: UpdateSLOInput }, - roleAuthc: RoleCredentials - ) { - return await retry.tryForTime(retryTimeout, async () => { - const response = await supertestWithoutAuth - .put(`/api/observability/slos/${sloId}`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) - .send(slo) - .timeout(requestTimeout); - if (response.body.id === undefined) { - throw new Error(`No SLO with id '${sloId}' found`); - } - return response.body; - }); - }, - - async waitForSloSummaryTempIndexToExist(index: string) { - return await retry.tryForTime(retryTimeout, async () => { - const indexExists = await es.indices.exists({ index, allow_no_indices: false }); - if (!indexExists) { - throw new Error(`SLO summary index '${index}' should exist`); - } - return indexExists; - }); - }, - - async getSloData({ sloId, indexName }: { sloId: string; indexName: string }) { - const response = await es.search({ - index: indexName, - body: { - query: { - bool: { - filter: [{ term: { 'slo.id': sloId } }], - }, - }, - }, - }); - return response; - }, - async waitForSloData({ id, indexName }: { id: string; indexName: string }) { - return await retry.tryForTime(retryTimeout, async () => { - const response = await es.search({ - index: indexName, - body: { - query: { - bool: { - filter: [{ term: { 'slo.id': id } }], - }, - }, - }, - }); - if (response.hits.hits.length === 0) { - throw new Error(`No hits found at index '${indexName}' for slo id='${id}'`); - } - return response; - }); - }, async deleteAllSLOs(roleAuthc: RoleCredentials) { const response = await supertestWithoutAuth .get(`/api/observability/slos/_definitions`) From 8a621556992538dd599c6e04f03f7f6d50e7cc7f Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 09:56:54 -0400 Subject: [PATCH 12/16] Add disabled tests back --- .../configs/serverless/oblt.index.ts | 14 +++++++------- .../configs/stateful/oblt.index.ts | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts index fa6f0bb9aea1a..e68aad1824c71 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.index.ts @@ -9,13 +9,13 @@ import { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { describe('Serverless Observability - Deployment-agnostic api integration tests', () => { // load new oblt and platform deployment-agnostic test here - // loadTestFile(require.resolve('../../apis/console')); - // loadTestFile(require.resolve('../../apis/core')); - // loadTestFile(require.resolve('../../apis/management')); - // loadTestFile(require.resolve('../../apis/observability/alerting')); - // loadTestFile(require.resolve('../../apis/observability/dataset_quality')); - // loadTestFile(require.resolve('../../apis/painless_lab')); - // loadTestFile(require.resolve('../../apis/saved_objects_management')); + loadTestFile(require.resolve('../../apis/console')); + loadTestFile(require.resolve('../../apis/core')); + loadTestFile(require.resolve('../../apis/management')); + loadTestFile(require.resolve('../../apis/observability/alerting')); + loadTestFile(require.resolve('../../apis/observability/dataset_quality')); + loadTestFile(require.resolve('../../apis/painless_lab')); + loadTestFile(require.resolve('../../apis/saved_objects_management')); loadTestFile(require.resolve('../../apis/observability/slo')); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts index 018c947f8d8ef..a467264698e57 100644 --- a/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.index.ts @@ -10,8 +10,8 @@ import { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { describe('apis', () => { // load new oblt deployment-agnostic test here - // loadTestFile(require.resolve('../../apis/observability/alerting')); - // loadTestFile(require.resolve('../../apis/observability/dataset_quality')); + loadTestFile(require.resolve('../../apis/observability/alerting')); + loadTestFile(require.resolve('../../apis/observability/dataset_quality')); loadTestFile(require.resolve('../../apis/observability/slo')); }); } From 6b46330fb8290f854fd0753103fa184eb88ce1f0 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 13:16:54 -0400 Subject: [PATCH 13/16] address comments --- .../apis/observability/slo/create_slo.ts | 6 +----- .../apis/observability/slo/delete_slo.ts | 6 +----- .../apis/observability/slo/find_slo.ts | 4 ---- .../apis/observability/slo/get_slo.ts | 4 ---- .../observability/slo/helpers/transform.ts | 18 ++++++++---------- .../apis/observability/slo/reset_slo.ts | 4 ---- .../apis/observability/slo/update_slo.ts | 6 +----- 7 files changed, 11 insertions(+), 37 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts index f182a08d6cf84..dd1f578aaa105 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -31,7 +31,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { describe('Create SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - transformHelper = createTransformHelper(getService, adminRoleAuthc); + transformHelper = createTransformHelper(getService); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -45,10 +45,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index a94c32dc52d1c..b890370488f5f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -36,7 +36,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { describe('Delete SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - transformHelper = createTransformHelper(getService, adminRoleAuthc); + transformHelper = createTransformHelper(getService); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -50,10 +50,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts index df34b4fe890e7..63ab8efcf7362 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts @@ -44,10 +44,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts index 401c7104c0121..02078f15506b9 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -40,10 +40,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts index 80a5f9b206ac1..a6a983f439a27 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts @@ -6,13 +6,11 @@ */ import { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; -import { RoleCredentials } from '../../../../services'; export type TransformHelper = ReturnType; export function createTransformHelper( - getService: DeploymentAgnosticFtrProviderContext['getService'], - roleAuthc: RoleCredentials + getService: DeploymentAgnosticFtrProviderContext['getService'] ) { const retry = getService('retry'); const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -20,19 +18,18 @@ export function createTransformHelper( return { assertNotFound: async (transformId: string) => { + const cookieHeader = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); + return await retry.tryWithRetries( `Wait for transform ${transformId} to be deleted`, async () => { - const response = await supertestWithoutAuth + await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) + .set(cookieHeader) .set('elastic-api-version', '1') .send() .timeout(10000) .expect(404); - - return response.body; }, { retryCount: 5, retryDelay: 2000 } ); @@ -42,10 +39,11 @@ export function createTransformHelper( return await retry.tryWithRetries( `Wait for transform ${transformId} to exist`, async () => { + const cookieHeader = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); + const response = await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) - .set(roleAuthc.apiKeyHeader) - .set(samlAuth.getInternalRequestHeader()) + .set(cookieHeader) .set('elastic-api-version', '1') .send() .timeout(10000) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts index 33b9808dff5c8..12a7f89062652 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts @@ -42,10 +42,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts index 498293128a4a6..1e3729a9896a2 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts @@ -30,7 +30,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { describe('Update SLOs', function () { before(async () => { adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); - transformHelper = createTransformHelper(getService, adminRoleAuthc); + transformHelper = createTransformHelper(getService); await generate({ client: esClient, config: DATA_FORGE_CONFIG, logger }); @@ -44,10 +44,6 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await sloApi.deleteAllSLOs(adminRoleAuthc); }); - afterEach(async () => { - await sloApi.deleteAllSLOs(adminRoleAuthc); - }); - after(async () => { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); From fcd5a0ab89bff83668724d409e49bec949fb41c5 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Fri, 11 Oct 2024 15:57:30 -0400 Subject: [PATCH 14/16] Increase delay transofrm --- .../apis/observability/slo/helpers/transform.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts index a6a983f439a27..805e113e39eac 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts @@ -31,7 +31,7 @@ export function createTransformHelper( .timeout(10000) .expect(404); }, - { retryCount: 5, retryDelay: 2000 } + { retryCount: 10, retryDelay: 3000 } ); }, @@ -50,7 +50,7 @@ export function createTransformHelper( .expect(200); return response.body; }, - { retryCount: 5, retryDelay: 2000 } + { retryCount: 10, retryDelay: 3000 } ); }, }; From c9cdcaa40b337041da56f73700df6caba3f947fc Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Tue, 15 Oct 2024 12:59:37 -0400 Subject: [PATCH 15/16] fix transform helper --- .../apis/observability/slo/helpers/transform.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts index 805e113e39eac..37b6ff1396c56 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/helpers/transform.ts @@ -26,6 +26,7 @@ export function createTransformHelper( await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) .set(cookieHeader) + .set(samlAuth.getInternalRequestHeader()) .set('elastic-api-version', '1') .send() .timeout(10000) @@ -44,6 +45,7 @@ export function createTransformHelper( const response = await supertestWithoutAuth .get(`/internal/transform/transforms/${transformId}`) .set(cookieHeader) + .set(samlAuth.getInternalRequestHeader()) .set('elastic-api-version', '1') .send() .timeout(10000) From 85449d31b2c30bf9b5906ad7756ca090b61f34a8 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 17 Oct 2024 09:03:16 -0400 Subject: [PATCH 16/16] Address comments --- .../apis/observability/slo/create_slo.ts | 9 +++++---- .../apis/observability/slo/delete_slo.ts | 1 + .../apis/observability/slo/find_slo.ts | 3 ++- .../apis/observability/slo/get_slo.ts | 1 + .../apis/observability/slo/reset_slo.ts | 1 + .../apis/observability/slo/update_slo.ts | 1 + 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts index dd1f578aaa105..28cef8c2c566c 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/create_slo.ts @@ -49,6 +49,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('creates a new slo and transforms', async () => { @@ -127,7 +128,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(apiResponse).property('id'); const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { + await retry.tryForTime(180 * 1000, async () => { const response = await esClient.search(getRollupDataEsQuery(id)); // @ts-ignore @@ -146,7 +147,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(apiResponse).property('id'); const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { + await retry.tryForTime(180 * 1000, async () => { const response = await esClient.search(getRollupDataEsQuery(id)); // @ts-ignore @@ -180,7 +181,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(apiResponse).property('id'); const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { + await retry.tryForTime(180 * 1000, async () => { const response = await esClient.search(getRollupDataEsQuery(id)); // @ts-ignore @@ -196,7 +197,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { expect(apiResponse).property('id'); const { id } = apiResponse; - await retry.tryForTime(300 * 1000, async () => { + await retry.tryForTime(180 * 1000, async () => { const response = await esClient.search(getRollupDataEsQuery(id)); // @ts-ignore diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts index b890370488f5f..733d2b6250c29 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/delete_slo.ts @@ -54,6 +54,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('deletes SLO and related resources', async () => { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts index 63ab8efcf7362..1d1be9dc338af 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/find_slo.ts @@ -48,6 +48,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('searches SLOs', async () => { @@ -61,7 +62,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { const sloId2 = createResponse2.id; // search SLOs - await retry.tryForTime(360 * 1000, async () => { + await retry.tryForTime(180 * 1000, async () => { let response = await supertestWithoutAuth .get(`/api/observability/slos`) .set(adminRoleAuthc.apiKeyHeader) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts index 02078f15506b9..7a27c3b36fb0d 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/get_slo.ts @@ -44,6 +44,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('get SLO by id', async () => { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts index 12a7f89062652..c765c4ea55332 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/reset_slo.ts @@ -46,6 +46,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('resets the related resources', async () => { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts index 1e3729a9896a2..8946f2d613a99 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/slo/update_slo.ts @@ -48,6 +48,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { await dataViewApi.delete({ roleAuthc: adminRoleAuthc, id: DATA_VIEW_ID }); await cleanup({ client: esClient, config: DATA_FORGE_CONFIG, logger }); await sloApi.deleteAllSLOs(adminRoleAuthc); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); }); it('updates the definition without a revision bump', async () => {