diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.test.ts index 255572d57cf49..1a4f2998d49dd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.test.ts @@ -42,6 +42,30 @@ const mockedRemoveArchiveEntries = removeArchiveEntries as jest.MockedFunction< let soClient: jest.Mocked; let esClient: jest.Mocked; +const assetsMap = new Map([ + [ + 'endpoint-0.16.0-dev.0/elasticsearch/transform/metadata_current/default.json', + Buffer.from('{"content": "data"}'), + ], + ['security_detection_engine-8.16.1/LICENSE.txt', Buffer.from('{"content": "data"}')], + ['security_detection_engine-8.16.1/NOTICE.txt', Buffer.from('{"content": "data"}')], + ['security_detection_engine-8.16.1/changelog.yml', Buffer.from('{"content": "data"}')], + ['security_detection_engine-8.16.1/manifest.yml', Buffer.from('{"content": "data"}')], + ['security_detection_engine-8.16.1/docs/README.md', Buffer.from('{"content": "data"}')], + [ + 'security_detection_engine-8.16.1/img/security-logo-color-64px.svg', + Buffer.from('{"content": "data"}'), + ], + [ + 'security_detection_engine-8.16.1/kibana/security_rule/000047bb-b27a-47ec-8b62-ef1a5d2c9e19_208.json', + Buffer.from('{"content": "data"}'), + ], + [ + 'security_detection_engine-8.16.1/kibana/security_rule/000047bb-b27a-47ec-8b62-ef1a5d2c9e19_209.json', + Buffer.from('{"content": "data"}'), + ], +]); + const packageInstallContext = { packageInfo: { title: 'title', @@ -56,13 +80,8 @@ const packageInstallContext = { owner: { github: 'elastic/fleet' }, } as any, paths: ['some/path/1', 'some/path/2'], - assetsMap: new Map([ - [ - 'endpoint-0.16.0-dev.0/elasticsearch/transform/metadata_current/default.json', - Buffer.from('{"content": "data"}'), - ], - ]), - archiveIterator: createArchiveIteratorFromMap(new Map()), + assetsMap, + archiveIterator: createArchiveIteratorFromMap(assetsMap), }; const getMockInstalledPackageSo = ( installedEs: EsAssetReference[] = [] @@ -196,6 +215,63 @@ describe('stepSaveArchiveEntries', () => { ], }); }); + + it('should save package icons, readme, and changelog but not Kibana assets with useStreaming:true ', async () => { + jest.mocked(mockedSaveArchiveEntriesFromAssetsMap).mockResolvedValue({ + saved_objects: [ + { + id: 'test', + attributes: { + package_name: 'test-package', + package_version: '1.0.0', + install_source: 'registry', + asset_path: 'some/path', + media_type: '', + data_utf8: '', + data_base64: '', + }, + type: '', + references: [], + }, + ], + }); + await stepSaveArchiveEntries({ + savedObjectsClient: soClient, + // @ts-ignore + savedObjectsImporter: jest.fn(), + esClient, + logger: loggerMock.create(), + packageInstallContext, + installedPkg, + installType: 'update', + installSource: 'registry', + spaceId: DEFAULT_SPACE_ID, + useStreaming: true, + esReferences: [ + { + id: 'something', + type: ElasticsearchAssetType.ilmPolicy, + }, + ], + }); + expect( + [ + ...(jest + .mocked(mockedSaveArchiveEntriesFromAssetsMap) + .mock.lastCall?.[0].assetsMap?.keys() ?? []), + ].sort() + ).toMatchInlineSnapshot(` + Array [ + "endpoint-0.16.0-dev.0/elasticsearch/transform/metadata_current/default.json", + "security_detection_engine-8.16.1/LICENSE.txt", + "security_detection_engine-8.16.1/NOTICE.txt", + "security_detection_engine-8.16.1/changelog.yml", + "security_detection_engine-8.16.1/docs/README.md", + "security_detection_engine-8.16.1/img/security-logo-color-64px.svg", + "security_detection_engine-8.16.1/manifest.yml", + ] + `); + }); }); describe('cleanupArchiveEntriesStep', () => { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.ts index 7db44bb243f85..f081d9a93e633 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_archive_entries.ts @@ -14,7 +14,7 @@ import { withPackageSpan } from '../../utils'; import type { InstallContext } from '../_state_machine_package_install'; import { INSTALL_STATES } from '../../../../../../common/types'; -import { MANIFEST_NAME } from '../../../archive/parse'; +import { isKibanaAssetType } from '../../../kibana/assets/install'; export async function stepSaveArchiveEntries(context: InstallContext) { const { packageInstallContext, savedObjectsClient, installSource, useStreaming } = context; @@ -28,7 +28,8 @@ export async function stepSaveArchiveEntries(context: InstallContext) { if (useStreaming) { assetsMap = new Map(); await archiveIterator.traverseEntries(async (entry) => { - if (entry.path.endsWith(MANIFEST_NAME)) { + // Skip only kibana assets type + if (!isKibanaAssetType(entry.path)) { assetsMap.set(entry.path, entry.buffer); } }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/get_environment.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/get_environment.spec.ts new file mode 100644 index 0000000000000..ba6f0df98e3a1 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/get_environment.spec.ts @@ -0,0 +1,155 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +async function generateData({ + apmSynthtraceEsClient, + start, + end, +}: { + apmSynthtraceEsClient: ApmSynthtraceEsClient; + start: number; + end: number; +}) { + const environmentNames = ['production', 'development', 'staging']; + const serviceNames = ['go', 'java', 'node']; + + const services = environmentNames.flatMap((environment) => { + return serviceNames.flatMap((serviceName) => { + return apm + .service({ + name: serviceName, + environment, + agentName: serviceName, + }) + .instance('instance-a'); + }); + }); + + const goServiceWithAdditionalEnvironment = apm + .service({ + name: 'go', + environment: 'custom-go-environment', + agentName: 'go', + }) + .instance('instance-a'); + + // Generate a transaction for each service + const docs = timerange(start, end) + .ratePerMinute(1) + .generator((timestamp) => { + const loopGeneratedDocs = services.flatMap((service) => { + return service + .transaction({ transactionName: 'GET /api/product/:id' }) + .timestamp(timestamp) + .duration(1000); + }); + + const customDoc = goServiceWithAdditionalEnvironment + .transaction({ + transactionName: 'GET /api/go/memory', + transactionType: 'custom-go-type', + }) + .timestamp(timestamp) + .duration(1000); + + return [...loopGeneratedDocs, customDoc]; + }); + + return apmSynthtraceEsClient.index(docs); +} + +const startNumber = new Date('2021-01-01T00:00:00.000Z').getTime(); +const endNumber = new Date('2021-01-01T00:05:00.000Z').getTime() - 1; + +const start = new Date(startNumber).toISOString(); +const end = new Date(endNumber).toISOString(); + +export default function environmentsAPITests({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); + + describe('get environments', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + await generateData({ + apmSynthtraceEsClient, + start: startNumber, + end: endNumber, + }); + }); + + after(async () => { + await apmSynthtraceEsClient.clean(); + }); + + describe('when service name is not specified', () => { + it('returns all environments', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/environments', + params: { + query: { start, end }, + }, + }); + + expect(body.environments.length).to.be.equal(4); + expectSnapshot(body.environments).toMatchInline(` + Array [ + "development", + "production", + "staging", + "custom-go-environment", + ] + `); + }); + }); + + describe('when service name is specified', () => { + it('returns service specific environments for go', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/environments', + params: { + query: { start, end, serviceName: 'go' }, + }, + }); + + expect(body.environments.length).to.be.equal(4); + expectSnapshot(body.environments).toMatchInline(` + Array [ + "custom-go-environment", + "development", + "production", + "staging", + ] + `); + }); + + it('returns service specific environments for java', async () => { + const { body } = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/environments', + params: { + query: { start, end, serviceName: 'java' }, + }, + }); + + expect(body.environments.length).to.be.equal(3); + expectSnapshot(body.environments).toMatchInline(` + Array [ + "development", + "production", + "staging", + ] + `); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/index.ts new file mode 100644 index 0000000000000..4a77e610d5000 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/environment/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('environment', () => { + loadTestFile(require.resolve('./get_environment.spec.ts')); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts index a62386b536ea8..6c1bd3633c4cc 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts @@ -16,6 +16,7 @@ export default function apmApiIntegrationTests({ loadTestFile(require.resolve('./mobile')); loadTestFile(require.resolve('./custom_dashboards')); loadTestFile(require.resolve('./dependencies')); + loadTestFile(require.resolve('./environment')); loadTestFile(require.resolve('./error_rate')); loadTestFile(require.resolve('./data_view')); loadTestFile(require.resolve('./correlations')); diff --git a/x-pack/test/apm_api_integration/tests/environment/generate_data.ts b/x-pack/test/apm_api_integration/tests/environment/generate_data.ts deleted file mode 100644 index 3cfd5d92e00f1..0000000000000 --- a/x-pack/test/apm_api_integration/tests/environment/generate_data.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { apm, timerange } from '@kbn/apm-synthtrace-client'; -import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; - -// Generate synthetic data for the environment test suite -export async function generateData({ - apmSynthtraceEsClient, - start, - end, -}: { - apmSynthtraceEsClient: ApmSynthtraceEsClient; - start: number; - end: number; -}) { - const environmentNames = ['production', 'development', 'staging']; - const serviceNames = ['go', 'java', 'node']; - - const services = environmentNames.flatMap((environment) => { - return serviceNames.flatMap((serviceName) => { - return apm - .service({ - name: serviceName, - environment, - agentName: serviceName, - }) - .instance('instance-a'); - }); - }); - - const goServiceWithAdditionalEnvironment = apm - .service({ - name: 'go', - environment: 'custom-go-environment', - agentName: 'go', - }) - .instance('instance-a'); - - // Generate a transaction for each service - const docs = timerange(start, end) - .ratePerMinute(1) - .generator((timestamp) => { - const loopGeneratedDocs = services.flatMap((service) => { - return service - .transaction({ transactionName: 'GET /api/product/:id' }) - .timestamp(timestamp) - .duration(1000); - }); - - const customDoc = goServiceWithAdditionalEnvironment - .transaction({ - transactionName: 'GET /api/go/memory', - transactionType: 'custom-go-type', - }) - .timestamp(timestamp) - .duration(1000); - - return [...loopGeneratedDocs, customDoc]; - }); - - return apmSynthtraceEsClient.index(docs); -} diff --git a/x-pack/test/apm_api_integration/tests/environment/get_environment.spec.ts b/x-pack/test/apm_api_integration/tests/environment/get_environment.spec.ts deleted file mode 100644 index e67c601e7713c..0000000000000 --- a/x-pack/test/apm_api_integration/tests/environment/get_environment.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { generateData } from './generate_data'; - -const startNumber = new Date('2021-01-01T00:00:00.000Z').getTime(); -const endNumber = new Date('2021-01-01T00:05:00.000Z').getTime() - 1; - -const start = new Date(startNumber).toISOString(); -const end = new Date(endNumber).toISOString(); - -export default function environmentsAPITests({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); - - registry.when('environments when data is loaded', { config: 'basic', archives: [] }, async () => { - before(async () => - generateData({ - apmSynthtraceEsClient, - start: startNumber, - end: endNumber, - }) - ); - - after(() => apmSynthtraceEsClient.clean()); - - describe('get environments', () => { - describe('when service name is not specified', () => { - it('returns all environments', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/environments', - params: { - query: { start, end }, - }, - }); - expect(body.environments.length).to.be.equal(4); - expectSnapshot(body.environments).toMatchInline(` - Array [ - "development", - "production", - "staging", - "custom-go-environment", - ] - `); - }); - }); - - describe('when service name is specified', () => { - it('returns service specific environments for go', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/environments', - params: { - query: { start, end, serviceName: 'go' }, - }, - }); - - expect(body.environments.length).to.be.equal(4); - expectSnapshot(body.environments).toMatchInline(` - Array [ - "custom-go-environment", - "development", - "production", - "staging", - ] - `); - }); - - it('returns service specific environments for java', async () => { - const { body } = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/environments', - params: { - query: { start, end, serviceName: 'java' }, - }, - }); - - expect(body.environments.length).to.be.equal(3); - expectSnapshot(body.environments).toMatchInline(` - Array [ - "development", - "production", - "staging", - ] - `); - }); - }); - }); - }); -}