[Console] Add api integration tests for serverless (#172306)

## Summary

This PR adds api integration test for Console routes: some were missing
on stateful and all are now enabled on serverless.
This commit is contained in:
Yulia Čech 2023-12-05 10:26:51 +01:00 committed by GitHub
parent 9d81996329
commit a29b0f4573
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 558 additions and 118 deletions

View file

@ -32,5 +32,4 @@ export const registerSpecDefinitionsRoute = ({ router, services }: RouteDependen
};
router.get({ path: '/api/console/api_server', validate: false }, handler);
router.post({ path: '/api/console/api_server', validate: false }, handler);
};

View file

@ -8,125 +8,27 @@
import expect from '@kbn/expect';
import type { FtrProviderContext } from '../../ftr_provider_context';
import { helpers } from './helpers';
export default ({ getService }: FtrProviderContext) => {
const {
createIndex,
createAlias,
createLegacyTemplate,
createIndexTemplate,
createComponentTemplate,
createDataStream,
deleteIndex,
deleteAlias,
deleteLegacyTemplate,
deleteIndexTemplate,
deleteComponentTemplate,
deleteDataStream,
} = helpers(getService);
const supertest = getService('supertest');
const client = getService('es');
const createIndex = async (indexName: string) => {
await client.indices.create({
index: indexName,
body: {
mappings: {
properties: {
foo: {
type: 'text',
},
},
},
},
});
};
const createAlias = async (indexName: string, aliasName: string) => {
await client.indices.putAlias({
index: indexName,
name: aliasName,
});
};
const createLegacyTemplate = async (templateName: string) => {
await client.indices.putTemplate({
name: templateName,
body: {
index_patterns: ['*'],
},
});
};
const createComponentTemplate = async (templateName: string) => {
await client.cluster.putComponentTemplate({
name: templateName,
body: {
template: {
mappings: {
properties: {
'@timestamp': {
type: 'date',
format: 'date_optional_time||epoch_millis',
},
message: {
type: 'wildcard',
},
},
},
},
},
});
};
const createIndexTemplate = async (
templateName: string,
indexPatterns: string[],
composedOf: string[]
) => {
await client.indices.putIndexTemplate({
name: templateName,
body: {
index_patterns: indexPatterns,
data_stream: {},
composed_of: composedOf,
priority: 500,
},
});
};
const createDataStream = async (dataStream: string) => {
await client.indices.createDataStream({
name: dataStream,
});
};
const deleteIndex = async (indexName: string) => {
await client.indices.delete({
index: indexName,
});
};
const deleteAlias = async (indexName: string, aliasName: string) => {
await client.indices.deleteAlias({
index: indexName,
name: aliasName,
});
};
const deleteIndexTemplate = async (templateName: string) => {
await client.indices.deleteIndexTemplate({
name: templateName,
});
};
const deleteComponentTemplate = async (templateName: string) => {
await client.cluster.deleteComponentTemplate({
name: templateName,
});
};
const deleteLegacyTemplate = async (templateName: string) => {
await client.indices.deleteTemplate({
name: templateName,
});
};
const deleteDataStream = async (dataStream: string) => {
await client.indices.deleteDataStream({
name: dataStream,
});
};
const sendRequest = async (query: object) => {
return await supertest.get('/api/console/autocomplete_entities').query(query);
};
const sendRequest = (query: object) =>
supertest.get('/api/console/autocomplete_entities').query(query);
describe('/api/console/autocomplete_entities', function () {
const indexName = 'test-index-1';

View file

@ -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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('GET /api/console/es_config', () => {
it('returns es host', async () => {
const { body } = await supertest
.get('/api/console/es_config')
.set('kbn-xsrf', 'true')
.expect(200);
expect(body.host).to.be.ok();
});
});
}

View file

@ -0,0 +1,139 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { FtrProviderContext } from '../../ftr_provider_context';
export function helpers(getService: FtrProviderContext['getService']) {
const client = getService('es');
const createIndex = async (indexName: string) => {
await client.indices.create({
index: indexName,
body: {
mappings: {
properties: {
foo: {
type: 'text',
},
},
},
},
});
};
const createAlias = async (indexName: string, aliasName: string) => {
await client.indices.putAlias({
index: indexName,
name: aliasName,
});
};
const createLegacyTemplate = async (templateName: string) => {
await client.indices.putTemplate({
name: templateName,
body: {
index_patterns: ['*'],
},
});
};
const createComponentTemplate = async (templateName: string) => {
await client.cluster.putComponentTemplate({
name: templateName,
body: {
template: {
mappings: {
properties: {
'@timestamp': {
type: 'date',
format: 'date_optional_time||epoch_millis',
},
message: {
type: 'wildcard',
},
},
},
},
},
});
};
const createIndexTemplate = async (
templateName: string,
indexPatterns: string[],
composedOf: string[]
) => {
await client.indices.putIndexTemplate({
name: templateName,
body: {
index_patterns: indexPatterns,
data_stream: {},
composed_of: composedOf,
priority: 500,
},
});
};
const createDataStream = async (dataStream: string) => {
await client.indices.createDataStream({
name: dataStream,
});
};
const deleteIndex = async (indexName: string) => {
await client.indices.delete({
index: indexName,
});
};
const deleteAlias = async (indexName: string, aliasName: string) => {
await client.indices.deleteAlias({
index: indexName,
name: aliasName,
});
};
const deleteIndexTemplate = async (templateName: string) => {
await client.indices.deleteIndexTemplate({
name: templateName,
});
};
const deleteComponentTemplate = async (templateName: string) => {
await client.cluster.deleteComponentTemplate({
name: templateName,
});
};
const deleteLegacyTemplate = async (templateName: string) => {
await client.indices.deleteTemplate({
name: templateName,
});
};
const deleteDataStream = async (dataStream: string) => {
await client.indices.deleteDataStream({
name: dataStream,
});
};
return {
createIndex,
createAlias,
createLegacyTemplate,
createIndexTemplate,
createComponentTemplate,
createDataStream,
deleteIndex,
deleteAlias,
deleteLegacyTemplate,
deleteIndexTemplate,
deleteComponentTemplate,
deleteDataStream,
};
}

View file

@ -9,8 +9,10 @@
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('core', () => {
describe('console', () => {
loadTestFile(require.resolve('./proxy_route'));
loadTestFile(require.resolve('./autocomplete_entities'));
loadTestFile(require.resolve('./es_config'));
loadTestFile(require.resolve('./spec_definitions'));
});
}

View file

@ -0,0 +1,30 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('GET /api/console/api_server', () => {
it('returns autocomplete definitions', async () => {
const { body } = await supertest
.get('/api/console/api_server')
.set('kbn-xsrf', 'true')
.expect(200);
expect(body.es).to.be.ok();
const {
es: { name, globals, endpoints },
} = body;
expect(name).to.be.ok();
expect(Object.keys(globals).length).to.be.above(0);
expect(Object.keys(endpoints).length).to.be.above(0);
});
});
}

View 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { FtrProviderContext } from '../ftr_provider_context';
import { helpers } from '../../api_integration/apis/console/helpers';
export function ConsoleProvider({ getService }: FtrProviderContext) {
return {
helpers: helpers(getService),
};
}

View file

@ -14,6 +14,7 @@ import { EsDeleteAllIndicesProvider } from './es_delete_all_indices';
import { SavedObjectInfoService } from './saved_object_info';
import { IndexPatternsService } from './index_patterns';
import { BsearchService } from './bsearch';
import { ConsoleProvider } from './console';
export const services = {
...commonFunctionalServices,
@ -24,4 +25,5 @@ export const services = {
savedObjectInfo: SavedObjectInfoService,
indexPatterns: IndexPatternsService,
bsearch: BsearchService,
console: ConsoleProvider,
};

View file

@ -0,0 +1,201 @@
/*
* 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 '../../../ftr_provider_context';
export default ({ getService }: FtrProviderContext) => {
const svlCommonApi = getService('svlCommonApi');
const consoleService = getService('console');
const supertest = getService('supertest');
const sendRequest = (query: object) =>
supertest
.get('/api/console/autocomplete_entities')
.set(svlCommonApi.getInternalRequestHeader())
.query(query);
describe('/api/console/autocomplete_entities', function () {
let createIndex: typeof consoleService['helpers']['createIndex'];
let createAlias: typeof consoleService['helpers']['createAlias'];
let createIndexTemplate: typeof consoleService['helpers']['createIndexTemplate'];
let createComponentTemplate: typeof consoleService['helpers']['createComponentTemplate'];
let createDataStream: typeof consoleService['helpers']['createDataStream'];
let deleteIndex: typeof consoleService['helpers']['deleteIndex'];
let deleteAlias: typeof consoleService['helpers']['deleteAlias'];
let deleteIndexTemplate: typeof consoleService['helpers']['deleteIndexTemplate'];
let deleteComponentTemplate: typeof consoleService['helpers']['deleteComponentTemplate'];
let deleteDataStream: typeof consoleService['helpers']['deleteDataStream'];
const indexName = 'test-index-1';
const aliasName = 'test-alias-1';
const indexTemplateName = 'test-index-template-1';
const componentTemplateName = 'test-component-template-1';
const dataStreamName = 'test-data-stream-1';
before(async () => {
({
helpers: {
createIndex,
createAlias,
createIndexTemplate,
createComponentTemplate,
createDataStream,
deleteIndex,
deleteAlias,
deleteIndexTemplate,
deleteComponentTemplate,
deleteDataStream,
},
} = consoleService);
// Setup indices, aliases, templates, and data streams
await createIndex(indexName);
await createAlias(indexName, aliasName);
await createComponentTemplate(componentTemplateName);
await createIndexTemplate(indexTemplateName, [dataStreamName], [componentTemplateName]);
await createDataStream(dataStreamName);
});
after(async () => {
// Cleanup indices, aliases, templates, and data streams
await deleteAlias(indexName, aliasName);
await deleteIndex(indexName);
await deleteDataStream(dataStreamName);
await deleteIndexTemplate(indexTemplateName);
await deleteComponentTemplate(componentTemplateName);
});
it('should not succeed if no settings are provided in query params', async () => {
const response = await sendRequest({});
const { status } = response;
expect(status).to.be(400);
});
it('should return an object with properties of "mappings", "aliases", "dataStreams", "legacyTemplates", "indexTemplates", "componentTemplates"', async () => {
const response = await sendRequest({
indices: true,
fields: true,
templates: true,
dataStreams: true,
});
const { body, status } = response;
expect(status).to.be(200);
expect(Object.keys(body).sort()).to.eql([
'aliases',
'componentTemplates',
'dataStreams',
'indexTemplates',
'legacyTemplates',
'mappings',
]);
});
it('should return empty payload with all settings are set to false', async () => {
const response = await sendRequest({
indices: false,
fields: false,
templates: false,
dataStreams: false,
});
const { body, status } = response;
expect(status).to.be(200);
expect(body.legacyTemplates).to.eql({});
expect(body.indexTemplates).to.eql({});
expect(body.componentTemplates).to.eql({});
expect(body.aliases).to.eql({});
expect(body.mappings).to.eql({});
expect(body.dataStreams).to.eql({});
});
it('should return empty templates with templates setting is set to false', async () => {
const response = await sendRequest({
templates: false,
});
const { body, status } = response;
expect(status).to.be(200);
expect(body.legacyTemplates).to.eql({});
expect(body.indexTemplates).to.eql({});
expect(body.componentTemplates).to.eql({});
});
it('should return empty data streams with dataStreams setting is set to false', async () => {
const response = await sendRequest({
dataStreams: false,
});
const { body, status } = response;
expect(status).to.be(200);
expect(body.dataStreams).to.eql({});
});
it('should return empty aliases with indices setting is set to false', async () => {
const response = await sendRequest({
indices: false,
});
const { body, status } = response;
expect(status).to.be(200);
expect(body.aliases).to.eql({});
});
it('should return empty mappings with fields setting is set to false', async () => {
const response = await sendRequest({
fields: false,
});
const { body, status } = response;
expect(status).to.be(200);
expect(body.mappings).to.eql({});
});
it('should not return mappings with fields setting is set to true without the list of indices is provided', async () => {
const response = await sendRequest({ fields: true });
const { body, status } = response;
expect(status).to.be(200);
expect(Object.keys(body.mappings)).to.not.contain(indexName);
});
it('should return mappings with fields setting is set to true and the list of indices is provided', async () => {
const response = await sendRequest({ fields: true, fieldsIndices: indexName });
const { body, status } = response;
expect(status).to.be(200);
expect(Object.keys(body.mappings)).to.contain(indexName);
});
it('should return aliases with indices setting is set to true', async () => {
const response = await sendRequest({ indices: true });
const { body, status } = response;
expect(status).to.be(200);
expect(body.aliases[indexName].aliases).to.eql({ [aliasName]: {} });
});
it('should return data streams with dataStreams setting is set to true', async () => {
const response = await sendRequest({ dataStreams: true });
const { body, status } = response;
expect(status).to.be(200);
expect(body.dataStreams.data_streams.map((ds: { name: string }) => ds.name)).to.contain(
dataStreamName
);
});
it('should return all templates with templates setting is set to true', async () => {
const response = await sendRequest({ templates: true });
const { body, status } = response;
expect(status).to.be(200);
expect(body.indexTemplates.index_templates.map((it: { name: string }) => it.name)).to.contain(
indexTemplateName
);
expect(
body.componentTemplates.component_templates.map((ct: { name: string }) => ct.name)
).to.contain(componentTemplateName);
});
});
};

View file

@ -0,0 +1,25 @@
/*
* 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 '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const svlCommonApi = getService('svlCommonApi');
describe('GET /api/console/es_config', () => {
it('returns es host', async () => {
const { body } = await supertest
.get('/api/console/es_config')
.set('kbn-xsrf', 'true')
.set(svlCommonApi.getInternalRequestHeader())
.expect(200);
expect(body.host).to.be.ok();
});
});
}

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('Console APIs', function () {
this.tags(['esGate']);
loadTestFile(require.resolve('./autocomplete_entities'));
loadTestFile(require.resolve('./es_config'));
loadTestFile(require.resolve('./proxy_route'));
loadTestFile(require.resolve('./spec_definitions'));
});
}

View file

@ -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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const svlCommonApi = getService('svlCommonApi');
describe('POST /api/console/proxy', () => {
describe('system indices behavior', () => {
it('returns warning header when making requests to .kibana index', async () => {
return await supertest
.post('/api/console/proxy?method=GET&path=/.kibana/_settings')
.set('kbn-xsrf', 'true')
.set(svlCommonApi.getInternalRequestHeader())
.then((response) => {
expect(response.header).to.have.property('warning');
const { warning } = response.header as { warning: string };
expect(warning.startsWith('299')).to.be(true);
expect(warning.includes('system indices')).to.be(true);
});
});
it('does not forward x-elastic-product-origin', async () => {
// If we pass the header and we still get the warning back, we assume that the header was not forwarded.
return await supertest
.post('/api/console/proxy?method=GET&path=/.kibana/_settings')
.set('kbn-xsrf', 'true')
.set(svlCommonApi.getInternalRequestHeader())
.set('x-elastic-product-origin', 'kibana')
.then((response) => {
expect(response.header).to.have.property('warning');
const { warning } = response.header as { warning: string };
expect(warning.startsWith('299')).to.be(true);
expect(warning.includes('system indices')).to.be(true);
});
});
});
});
}

View 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const svlCommonApi = getService('svlCommonApi');
describe('GET /api/console/api_server', () => {
it('returns autocomplete definitions', async () => {
const { body } = await supertest
.get('/api/console/api_server')
.set('kbn-xsrf', 'true')
.set(svlCommonApi.getInternalRequestHeader())
.expect(200);
expect(body.es).to.be.ok();
const {
es: { name, globals, endpoints },
} = body;
expect(name).to.be.ok();
expect(Object.keys(globals).length).to.be.above(0);
expect(Object.keys(endpoints).length).to.be.above(0);
});
});
}

View file

@ -29,6 +29,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
require.resolve('../../common/reporting'),
require.resolve('../../common/grok_debugger'),
require.resolve('../../common/painless_lab'),
require.resolve('../../common/console'),
],
junit: {
reportName: 'Serverless Observability API Integration Tests - Common Group 1',

View file

@ -27,6 +27,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
require.resolve('../../common/search_xpack'),
require.resolve('../../common/core'),
require.resolve('../../common/reporting'),
require.resolve('../../common/console'),
],
junit: {
reportName: 'Serverless Search API Integration Tests - Common Group 1',

View file

@ -29,6 +29,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
require.resolve('../../common/reporting'),
require.resolve('../../common/grok_debugger'),
require.resolve('../../common/painless_lab'),
require.resolve('../../common/console'),
],
junit: {
reportName: 'Serverless Security API Integration Tests - Common Group 1',

View file

@ -28,6 +28,7 @@ const deploymentAgnosticApiIntegrationServices = _.pick(apiIntegrationServices,
'retry',
'security',
'usageAPI',
'console',
]);
export const services = {