mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Stack Monitoring] Beats package integration tests (#147755)
### Summary
**Sets up the foundations for
https://github.com/elastic/kibana/issues/146000**
- created a new test server under
`x-pack/test/monitoring_api_integration/` that allows loading of
packages at kibana startup
- a test runner utility which is a simple for loop executing the
supplied test twice, one time with `metricbeat` data and a second time
with `package` data
- a utility that allows transformation of package data into metricbeat
data
**Adds API tests for the beats package**
- created a test case for each API exposed
- removed the duplicates from
`x-pack/test/api_integration/apis/monitoring`
-----
_See the included
[README](b55de5c1cc/x-pack/test/monitoring_api_integration/README.md
)
for additional details_
This directory defines a custom test server that provides bundled
integrations
packages to the spawned test Kibana. This allows us to install those
packages at
startup, with all their assets (index templates, ingest pipelines..),
without
having to reach a remote package registry.
With the packages and their templates already installed we don't have to
provide
the static mappings in the tests archives. This has the benefit of
reducing our
disk footprint and setup time but more importantly it enables an easy
upgrade path
of the mappings so we can verify no breaking changes were introduced by
bundling
the new versions of the packages.
_Note that while Stack Monitoring currently supports 3 collection modes,
the tests
in this directory only focus on metricbeat and elastic-agent data. Tests
for legacy
data are defined under `x-pack/test/api_integration/apis/monitoring`._
Since an elastic-agent integration spawns the corresponding metricbeat
module under
the hood (ie when an agent policy defines elasticsearch metrics data
streams,
a metricbeat process with the elasticsearch module will be spawned), the
output
documents are _almost_ identical. This means that we can easily
transform documents
from a source (elastic-agent) to another (metricbeat), and have the same
tests run
against both datasets.
Note that we don't have to install anything for the metricbeat data
since the mappings
are already installed by elasticseach at startup, and available at
`.monitoring-<component>-8-mb`
patterns. So we are always running the metricbeat tests against the
latest version of
the mappings.
We could have a similar approach for packages, for example by installing
the latest
packages versions from public EPR before the test suites run, instead of
using pinned
versions. Besides the questionable reliance on remote services for
running tests,
this is also dangerous given that packages are released in a continuous
model.
This means that whenever the test suite would execute against the latest
version
of packages it would be too late, as in already available to users.
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
55f6006a7f
commit
5c9df67e8d
39 changed files with 576 additions and 338 deletions
|
@ -223,6 +223,7 @@ enabled:
|
|||
- x-pack/test/licensing_plugin/config.public.ts
|
||||
- x-pack/test/licensing_plugin/config.ts
|
||||
- x-pack/test/lists_api_integration/security_and_spaces/config.ts
|
||||
- x-pack/test/monitoring_api_integration/config.ts
|
||||
- x-pack/test/observability_api_integration/basic/config.ts
|
||||
- x-pack/test/observability_api_integration/trial/config.ts
|
||||
- x-pack/test/observability_functional/with_rac_write.config.ts
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
export default function ({ loadTestFile }) {
|
||||
describe('APM', () => {
|
||||
loadTestFile(require.resolve('./overview'));
|
||||
loadTestFile(require.resolve('./overview_mb'));
|
||||
loadTestFile(require.resolve('./instances'));
|
||||
loadTestFile(require.resolve('./instances_mb'));
|
||||
loadTestFile(require.resolve('./instance'));
|
||||
loadTestFile(require.resolve('./instance_mb'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,46 +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 apmInstanceFixture from './fixtures/instance.json';
|
||||
import { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('instance detail mb', function () {
|
||||
// Archive contains non-cgroup data which collides with the in-cgroup services present by default on cloud deployments
|
||||
this.tags(['skipCloud']);
|
||||
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
const archive = 'x-pack/test/functional/es_archives/monitoring/apm_mb';
|
||||
const timeRange = {
|
||||
min: '2018-08-31T12:59:49.104Z',
|
||||
max: '2018-08-31T13:59:49.104Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should get apm instance data', async () => {
|
||||
const { body } = await supertest
|
||||
.post(
|
||||
'/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm/9b16f434-2092-4983-a401-80a2b61c79d6'
|
||||
)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(apmInstanceFixture);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,80 +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 { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('list mb', function () {
|
||||
// Archive contains non-cgroup data which collides with the in-cgroup services present by default on cloud deployments
|
||||
this.tags(['skipCloud']);
|
||||
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
const archive = 'x-pack/test/functional/es_archives/monitoring/apm_mb';
|
||||
const timeRange = {
|
||||
min: '2018-08-31T12:59:49.104Z',
|
||||
max: '2018-08-31T13:59:49.104Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should load multiple clusters', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm/instances')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
const expected = {
|
||||
stats: {
|
||||
totalEvents: 18,
|
||||
apms: {
|
||||
total: 2,
|
||||
},
|
||||
timeOfLastEvent: '2018-08-31T13:59:21.199Z',
|
||||
},
|
||||
apms: [
|
||||
{
|
||||
uuid: '55f1089b-43b1-472a-919a-344667bae595',
|
||||
name: 'd06490170f2b',
|
||||
type: 'Apm-server',
|
||||
output: 'Elasticsearch',
|
||||
total_events_rate: 0.0033333333333333335,
|
||||
bytes_sent_rate: 5.7316666666666665,
|
||||
errors: 0,
|
||||
memory: 3445920,
|
||||
version: '7.0.0-alpha1',
|
||||
time_of_last_event: '2018-08-31T13:59:21.199Z',
|
||||
},
|
||||
{
|
||||
uuid: '9b16f434-2092-4983-a401-80a2b61c79d6',
|
||||
name: '01323afae1fb',
|
||||
type: 'Apm-server',
|
||||
output: 'Elasticsearch',
|
||||
total_events_rate: 0.0016666666666666668,
|
||||
bytes_sent_rate: 2.9105555555555553,
|
||||
errors: 0,
|
||||
memory: 3087640,
|
||||
version: '7.0.0-alpha1',
|
||||
time_of_last_event: '2018-08-31T13:59:21.163Z',
|
||||
},
|
||||
],
|
||||
cgroup: false,
|
||||
};
|
||||
|
||||
expect(body).to.eql(expected);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,44 +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 apmClusterFixture from './fixtures/cluster.json';
|
||||
import { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('overview mb', function () {
|
||||
// Archive contains non-cgroup data which collides with the in-cgroup APM server present by default on cloud deployments
|
||||
this.tags(['skipCloud']);
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
|
||||
const archive = 'x-pack/test/functional/es_archives/monitoring/apm_mb';
|
||||
const timeRange = {
|
||||
min: '2018-08-31T12:59:49.104Z',
|
||||
max: '2018-08-31T13:59:49.104Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should summarize apm cluster with metrics', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/GUtE4UwgSR-XUICRDEFKkA/apm')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(apmClusterFixture);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,44 +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 beatDetailFixture from './fixtures/detail.json';
|
||||
import { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('instance detail mb', () => {
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
const archive =
|
||||
'x-pack/test/functional/es_archives/monitoring/beats_with_restarted_instance_mb';
|
||||
const timeRange = {
|
||||
min: '2018-02-09T20:49:00Z',
|
||||
max: '2018-02-09T21:50:00Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should summarize beat with metrics', async () => {
|
||||
const { body } = await supertest
|
||||
.post(
|
||||
'/api/monitoring/v1/clusters/fHJwISmKTFO8bj57oFBLUQ/beats/beat/60599a4f-8139-4251-b0b9-15866df34221'
|
||||
)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(beatDetailFixture);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -8,10 +8,7 @@
|
|||
export default function ({ loadTestFile }) {
|
||||
describe('Beats', () => {
|
||||
loadTestFile(require.resolve('./overview'));
|
||||
loadTestFile(require.resolve('./overview_mb'));
|
||||
loadTestFile(require.resolve('./list'));
|
||||
loadTestFile(require.resolve('./list_mb'));
|
||||
loadTestFile(require.resolve('./detail'));
|
||||
loadTestFile(require.resolve('./detail_mb'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,77 +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 { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('list mb', () => {
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
describe('with restarted beat instance', () => {
|
||||
const archive =
|
||||
'x-pack/test/functional/es_archives/monitoring/beats_with_restarted_instance_mb';
|
||||
const timeRange = {
|
||||
min: '2018-02-09T20:49:00Z',
|
||||
max: '2018-02-09T21:50:00Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should load multiple clusters', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/fHJwISmKTFO8bj57oFBLUQ/beats/beats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
const expected = {
|
||||
stats: {
|
||||
total: 2,
|
||||
types: [
|
||||
{ type: 'Metricbeat', count: 1 },
|
||||
{ type: 'Filebeat', count: 1 },
|
||||
],
|
||||
stats: { totalEvents: 12829, bytesSent: 2040312125 },
|
||||
},
|
||||
listing: [
|
||||
{
|
||||
uuid: '2736e08b-5830-409b-8169-32aac39c5e55',
|
||||
name: 'spicy.local',
|
||||
type: 'Filebeat',
|
||||
output: 'Elasticsearch',
|
||||
total_events_rate: 0.018032786885245903,
|
||||
bytes_sent_rate: 24135.450546448086,
|
||||
errors: 0,
|
||||
memory: 30680648,
|
||||
version: '7.0.0-alpha1',
|
||||
},
|
||||
{
|
||||
uuid: '60599a4f-8139-4251-b0b9-15866df34221',
|
||||
name: 'spicy.local',
|
||||
type: 'Metricbeat',
|
||||
output: 'Elasticsearch',
|
||||
total_events_rate: 3.1327868852459018,
|
||||
bytes_sent_rate: 2613.3185792349727,
|
||||
errors: 0,
|
||||
memory: 7598304,
|
||||
version: '7.0.0-alpha1',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(body).to.eql(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,41 +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 beatsClusterFixture from './fixtures/cluster.json';
|
||||
import { getLifecycleMethods } from '../data_stream';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('overview mb', () => {
|
||||
const { setup, tearDown } = getLifecycleMethods(getService);
|
||||
const archive = 'x-pack/test/functional/es_archives/monitoring/beats_mb';
|
||||
const timeRange = {
|
||||
min: '2017-12-19T18:11:32.000Z',
|
||||
max: '2017-12-19T18:14:38.000Z',
|
||||
};
|
||||
|
||||
before('load archive', () => {
|
||||
return setup(archive);
|
||||
});
|
||||
|
||||
after('unload archive', () => {
|
||||
return tearDown();
|
||||
});
|
||||
|
||||
it('should summarize beats cluster with metrics', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/FlV4ckTxQ0a78hmBkzzc9A/beats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(beatsClusterFixture);
|
||||
});
|
||||
});
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
53
x-pack/test/monitoring_api_integration/README.md
Normal file
53
x-pack/test/monitoring_api_integration/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
## Stack Monitoring API tests
|
||||
|
||||
This directory defines a custom test server that provides bundled integrations
|
||||
packages to the spawned test Kibana. This allows us to install those packages at
|
||||
startup, with all their assets (index templates, ingest pipelines..), without
|
||||
having to reach a remote package registry.
|
||||
With the packages and their templates already installed we don't have to provide
|
||||
the static mappings in the tests archives. This has the benefit of reducing our
|
||||
disk footprint and setup time but more importantly it enables an easy upgrade path
|
||||
of the mappings so we can verify no breaking changes were introduced by bundling
|
||||
the new versions of the packages.
|
||||
|
||||
_Note that while Stack Monitoring currently supports 3 collection modes, the tests
|
||||
in this directory only focus on metricbeat and elastic-agent data. Tests for legacy
|
||||
data are defined under `x-pack/test/api_integration/apis/monitoring`._
|
||||
|
||||
Since an elastic-agent integration spawns the corresponding metricbeat module under
|
||||
the hood (ie when an agent policy defines elasticsearch metrics data streams,
|
||||
a metricbeat process with the elasticsearch module will be spawned), the output
|
||||
documents are _almost_ identical. This means that we can easily transform documents
|
||||
from a source (elastic-agent) to another (metricbeat), and have the same tests run
|
||||
against both datasets.
|
||||
|
||||
Note that we don't have to install anything for the metricbeat data since the mappings
|
||||
are already installed by elasticseach at startup, and available at `.monitoring-<component>-8-mb`
|
||||
patterns. So we are always running the metricbeat tests against the latest version of
|
||||
the mappings.
|
||||
We could have a similar approach for packages, for example by installing the latest
|
||||
packages versions from public EPR before the test suites run, instead of using pinned
|
||||
versions. Besides the questionable reliance on remote services for running tests,
|
||||
this is also dangerous given that packages are released in a continuous model.
|
||||
This means that whenever the test suite would execute against the latest version
|
||||
of packages it would be too late, as in already available to users.
|
||||
|
||||
### Validating a new package version
|
||||
- Get the locally built package from `<integrations-repo>/build/packages/<package>-<version>.zip`; or
|
||||
- Download the package zip at `<package-registry-url>/epr/<package>/<package>-<version>.zip`
|
||||
- Add the zipped package of the new version under `./fixtures/packages` and remove the previous version
|
||||
- Update the package version in `./packages.ts`
|
||||
- Create draft PR with the change to run against CI; or
|
||||
- Run the impacted test suite locally:
|
||||
- start test server: `node scripts/functional_tests_server --config x-pack/test/monitoring_api_integration/config`
|
||||
- start test suite for the updated component (eg Elasticsearch, Kibana..): `node scripts/functional_test_runner --config x-pack/test/monitoring_api_integration/config --grep "<Component>"`
|
||||
|
||||
### Adding a new archive
|
||||
- Generate elastic-agent data for the relevant integration and archive the data
|
||||
with the kbn-es-archiver. Assuming the data is extracted from an elastic-package
|
||||
stack: `node scripts/es_archiver.js save <output-dir> 'metrics-<component>.stack_monitoring.*' --es-url=https://elastic:changeme@localhost:9200 --es-ca=~/.elastic-package/profiles/default/certs/ca-cert.pem`
|
||||
- `<output-dir>` should point to a subdirectory of the `./archives` dir for consistency,
|
||||
and since we're generating package data, end with `package` dir. example `<kibana>/x-pack/test/monitoring_api_integration/archives/kibana/two-nodes/package`
|
||||
- `<output-dir>` should only contain a `data.json.gz`. make sure the `mappings.json` file was removed by the script
|
||||
- run the transform script to generate metricbeat data `node scripts/transform_archive --src <output-dir>/data.json.gz`
|
||||
- create a test case with the new archive
|
16
x-pack/test/monitoring_api_integration/apis/apm/index.ts
Normal file
16
x-pack/test/monitoring_api_integration/apis/apm/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('APM', () => {
|
||||
loadTestFile(require.resolve('./overview'));
|
||||
loadTestFile(require.resolve('./instances'));
|
||||
loadTestFile(require.resolve('./instance'));
|
||||
});
|
||||
}
|
41
x-pack/test/monitoring_api_integration/apis/apm/instance.ts
Normal file
41
x-pack/test/monitoring_api_integration/apis/apm/instance.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/apm/instance.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Instance',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/apm',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T16:28:00.000Z',
|
||||
max: '2022-12-20T16:32:00.000Z',
|
||||
};
|
||||
|
||||
testRunner(() => {
|
||||
it('should load individual apm server', async () => {
|
||||
const { body } = await supertest
|
||||
.post(
|
||||
'/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/apm/503d57eb-6f1f-4991-89c3-34250cef80d1'
|
||||
)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(response);
|
||||
});
|
||||
});
|
||||
}
|
39
x-pack/test/monitoring_api_integration/apis/apm/instances.ts
Normal file
39
x-pack/test/monitoring_api_integration/apis/apm/instances.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/apm/instances.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Instances',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/apm',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T16:28:00.000Z',
|
||||
max: '2022-12-20T16:32:00.000Z',
|
||||
};
|
||||
|
||||
testRunner(() => {
|
||||
it('should load apm servers', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/apm/instances')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(response);
|
||||
});
|
||||
});
|
||||
}
|
39
x-pack/test/monitoring_api_integration/apis/apm/overview.ts
Normal file
39
x-pack/test/monitoring_api_integration/apis/apm/overview.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/apm/overview.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Overview',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/apm',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T16:28:00.000Z',
|
||||
max: '2022-12-20T16:32:00.000Z',
|
||||
};
|
||||
|
||||
testRunner(() => {
|
||||
it('should summarize apm cluster with metrics', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/apm')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(response);
|
||||
});
|
||||
});
|
||||
}
|
42
x-pack/test/monitoring_api_integration/apis/beats/beat.ts
Normal file
42
x-pack/test/monitoring_api_integration/apis/beats/beat.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/beats/beat.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Beat',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/beats',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T17:19:00.000Z',
|
||||
max: '2022-12-20T17:22:00.000Z',
|
||||
};
|
||||
|
||||
testRunner(() => {
|
||||
it('should load individual beat', async () => {
|
||||
const { body } = await supertest
|
||||
.post(
|
||||
'/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/beats/beat/52bac4f9-2985-467e-b00c-b3e9ca53fc57'
|
||||
)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(response);
|
||||
});
|
||||
});
|
||||
}
|
40
x-pack/test/monitoring_api_integration/apis/beats/beats.ts
Normal file
40
x-pack/test/monitoring_api_integration/apis/beats/beats.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/beats/beats.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Beats',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/beats',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T17:19:00.000Z',
|
||||
max: '2022-12-20T17:22:00.000Z',
|
||||
};
|
||||
|
||||
testRunner(() => {
|
||||
it('should load beats', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/beats/beats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(body).to.eql(response);
|
||||
});
|
||||
});
|
||||
}
|
16
x-pack/test/monitoring_api_integration/apis/beats/index.ts
Normal file
16
x-pack/test/monitoring_api_integration/apis/beats/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('Beats', () => {
|
||||
loadTestFile(require.resolve('./overview'));
|
||||
loadTestFile(require.resolve('./beats'));
|
||||
loadTestFile(require.resolve('./beat'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 { omit } from 'lodash';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
import { getTestRunner } from '../../utils/test_runner';
|
||||
|
||||
import response from '../../fixtures/beats/overview.json';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
const testRunner = getTestRunner({
|
||||
testName: 'Overview',
|
||||
archiveRoot: 'x-pack/test/monitoring_api_integration/archives/beats',
|
||||
getService,
|
||||
});
|
||||
|
||||
const timeRange = {
|
||||
min: '2022-12-20T17:19:00.000Z',
|
||||
max: '2022-12-20T17:22:00.000Z',
|
||||
};
|
||||
|
||||
// beats overview returns data relative to the current time which bypasses
|
||||
// any selected period
|
||||
const omitLatestProperties = (overview: any) =>
|
||||
omit(overview, ['latestActive', 'latestTypes', 'latestVersions']);
|
||||
|
||||
testRunner(() => {
|
||||
it('should summarize beats cluster with metrics', async () => {
|
||||
const { body } = await supertest
|
||||
.post('/api/monitoring/v1/clusters/3_pOMySBSkCwdyxxBdDbvA/beats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ timeRange })
|
||||
.expect(200);
|
||||
|
||||
expect(omitLatestProperties(body)).to.eql(omitLatestProperties(response));
|
||||
});
|
||||
});
|
||||
}
|
15
x-pack/test/monitoring_api_integration/apis/index.ts
Normal file
15
x-pack/test/monitoring_api_integration/apis/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('Monitoring Endpoints', function () {
|
||||
loadTestFile(require.resolve('./apm'));
|
||||
loadTestFile(require.resolve('./beats'));
|
||||
});
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
32
x-pack/test/monitoring_api_integration/config.ts
Normal file
32
x-pack/test/monitoring_api_integration/config.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
import { bundledPackagesLocation, getPackagesArgs } from './packages';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts'));
|
||||
|
||||
return {
|
||||
testFiles: [require.resolve('./apis')],
|
||||
servers: xPackAPITestsConfig.get('servers'),
|
||||
services: xPackAPITestsConfig.get('services'),
|
||||
junit: {
|
||||
reportName: 'X-Pack Monitoring API Integration Tests',
|
||||
},
|
||||
esTestCluster: xPackAPITestsConfig.get('esTestCluster'),
|
||||
kbnTestServer: {
|
||||
...xPackAPITestsConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...xPackAPITestsConfig.get('kbnTestServer.serverArgs'),
|
||||
`--xpack.fleet.developer.bundledPackageLocation=${bundledPackagesLocation}`,
|
||||
...getPackagesArgs(),
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"stats":{"totalEvents":1803,"apms":{"total":1},"timeOfLastEvent":"2022-12-20T16:31:53.427Z"},"apms":[{"uuid":"503d57eb-6f1f-4991-89c3-34250cef80d1","name":"42646a2ef4c2","type":"Apm-server","output":"Elasticsearch","total_events_rate":7.5125,"bytes_sent_rate":2805.175,"errors":0,"memory":108116392,"version":"8.7.0","time_of_last_event":"2022-12-20T16:31:53.427Z"}],"cgroup":false}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"stats":{"total":1,"types":[{"type":"Metricbeat","count":1}],"stats":{"totalEvents":238,"bytesSent":249724}},"listing":[{"uuid":"52bac4f9-2985-467e-b00c-b3e9ca53fc57","name":"768578f6a263","type":"Metricbeat","output":"Elasticsearch","total_events_rate":1.3222222222222222,"bytes_sent_rate":1387.3555555555556,"errors":0,"memory":12066528,"version":"8.7.0"}]}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
21
x-pack/test/monitoring_api_integration/packages.ts
Normal file
21
x-pack/test/monitoring_api_integration/packages.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 path from 'path';
|
||||
|
||||
const PACKAGES = [{ name: 'beat', version: '0.0.1' }];
|
||||
|
||||
export const getPackagesArgs = (): string[] => {
|
||||
return PACKAGES.flatMap((pkg, i) => {
|
||||
return [
|
||||
`--xpack.fleet.packages.${i}.name=${pkg.name}`,
|
||||
`--xpack.fleet.packages.${i}.version=${pkg.version}`,
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
export const bundledPackagesLocation = path.join(path.dirname(__filename), '/fixtures/packages');
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
require('../../../../src/setup_node_env');
|
||||
|
||||
const { createReadStream, createWriteStream } = require('fs');
|
||||
const { mkdir, rm } = require('fs/promises');
|
||||
const path = require('path');
|
||||
const { Transform } = require('stream');
|
||||
const { createGzip } = require('zlib');
|
||||
const { createPromiseFromStreams } = require('@kbn/utils');
|
||||
|
||||
const {
|
||||
createParseArchiveStreams,
|
||||
} = require('../../../../packages/kbn-es-archiver/src/lib/archives/parse'); // eslint-disable-line @kbn/imports/uniform_imports
|
||||
|
||||
/**
|
||||
* generates .monitoring-* (metricbeat) archive from a metrics-* (package) archive
|
||||
* options:
|
||||
* --src <archive-source> - eg /path/to/archive/data.json.gz
|
||||
*/
|
||||
(async () => {
|
||||
const opts = process.argv.slice(2);
|
||||
const sourceFile = opts[opts.findIndex((opt) => opt === '--src') + 1];
|
||||
if (!sourceFile) {
|
||||
throw new Error('missing required --src argument');
|
||||
}
|
||||
|
||||
const sourceDir = path.dirname(path.resolve(sourceFile));
|
||||
const targetDir = path.join(path.dirname(sourceDir), 'metricbeat');
|
||||
const targetFile = path.join(targetDir, 'data.json.gz');
|
||||
|
||||
console.info(`creating dir ${targetDir}`);
|
||||
await mkdir(targetDir, { recursive: true });
|
||||
|
||||
await createPromiseFromStreams([
|
||||
createReadStream(sourceFile),
|
||||
...createParseArchiveStreams({ gzip: true }),
|
||||
new Transform({
|
||||
objectMode: true,
|
||||
transform(item, _encoding, callback) {
|
||||
delete item.value.index;
|
||||
delete item.value.source.data_stream;
|
||||
delete item.value.source.elastic_agent;
|
||||
|
||||
const source = item.value.source;
|
||||
|
||||
/* eslint-disable no-nested-ternary */
|
||||
const product = source.logstash
|
||||
? 'logstash'
|
||||
: source.kibana
|
||||
? 'kibana'
|
||||
: source.beat
|
||||
? 'beats'
|
||||
: source.elasticsearch
|
||||
? 'es'
|
||||
: null;
|
||||
/* eslint-enable no-nested-ternary */
|
||||
|
||||
if (!product) {
|
||||
console.warn('could not detect source product of document:', source);
|
||||
return callback();
|
||||
}
|
||||
|
||||
item.value.data_stream = `.monitoring-${product}-8-mb`;
|
||||
callback(null, JSON.stringify(item, null, 2) + '\n'.repeat(2));
|
||||
},
|
||||
}),
|
||||
createGzip(),
|
||||
createWriteStream(targetFile),
|
||||
]);
|
||||
|
||||
console.info(`created metricbeat data at ${targetFile}`);
|
||||
|
||||
const mappingsFile = path.join(sourceDir, 'mappings.json');
|
||||
try {
|
||||
await rm(mappingsFile);
|
||||
console.info(`removed mappings at path ${mappingsFile}`);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') return;
|
||||
console.warn(`failed to remove mappings at path ${mappingsFile}:`, err);
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
||||
|
||||
export const getLifecycleMethods = (getService: FtrProviderContext['getService']) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const client = getService('es');
|
||||
|
||||
const deleteDataStream = async (index: string) => {
|
||||
await client.transport.request(
|
||||
{
|
||||
method: 'DELETE',
|
||||
path: `_data_stream/${index}`,
|
||||
},
|
||||
{
|
||||
ignore: [404],
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
async setup(archives: string[] | string) {
|
||||
const archivesArray = Array.isArray(archives) ? archives : [archives];
|
||||
await Promise.all(archivesArray.map((archive) => esArchiver.load(archive)));
|
||||
},
|
||||
|
||||
async tearDown() {
|
||||
// .monitoring-* and metrics-* mappings are already installed when we initiate
|
||||
// the tests suites. since the archiver doesn't have any reference to the
|
||||
// mappings it can't automatically delete it and we have to do the cleanup manually
|
||||
await deleteDataStream('.monitoring-*');
|
||||
await deleteDataStream('metrics-beats.stack_monitoring.*');
|
||||
},
|
||||
};
|
||||
};
|
41
x-pack/test/monitoring_api_integration/utils/test_runner.ts
Normal file
41
x-pack/test/monitoring_api_integration/utils/test_runner.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { FtrProviderContext } from '../../api_integration/ftr_provider_context';
|
||||
import { getLifecycleMethods } from './lifecycle_methods';
|
||||
|
||||
interface RunTestsOpts {
|
||||
testName: string;
|
||||
archiveRoot: string;
|
||||
getService: FtrProviderContext['getService'];
|
||||
}
|
||||
|
||||
/**
|
||||
* abstracts the duplication of tests running once for metricbeat data and once
|
||||
* for package data. Expects that the provided <archiveRoot> path defines two
|
||||
* subdirectories (metricbeat and package) containing their respective archived
|
||||
* data. The runner takes care of loading and unloading the test data.
|
||||
*/
|
||||
export function getTestRunner(opts: RunTestsOpts) {
|
||||
const archives = [
|
||||
{ path: `${opts.archiveRoot}/metricbeat`, variant: 'Metricbeat (.monitoring-*)' },
|
||||
{ path: `${opts.archiveRoot}/package`, variant: 'Package (metrics-*)' },
|
||||
];
|
||||
const { setup, tearDown } = getLifecycleMethods(opts.getService);
|
||||
|
||||
return function executeTest(assert: () => void) {
|
||||
describe(opts.testName, function () {
|
||||
archives.forEach(({ path, variant }) => {
|
||||
describe(variant, function () {
|
||||
before('load archive', () => setup(path));
|
||||
after('unload archive', () => tearDown());
|
||||
|
||||
assert();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
"./api_integration/apis/logstash/pipeline/fixtures/*.json",
|
||||
"./api_integration/apis/logstash/pipelines/fixtures/*.json",
|
||||
"./api_integration/apis/telemetry/fixtures/*.json",
|
||||
"./monitoring_api_integration/fixtures/**/*.json",
|
||||
"../../typings/**/*",
|
||||
"../../packages/kbn-test/types/ftr_globals/**/*",
|
||||
],
|
||||
|
@ -109,5 +110,6 @@
|
|||
"@kbn/core-saved-objects-common",
|
||||
"@kbn/alerting-fixture-plugin",
|
||||
"@kbn/user-profile-components",
|
||||
"@kbn/utils",
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue