mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Search Profiler] Enable functional tests for serverless (#172656)
## Summary This PR adds a test that profiles a simple query with a test index to stateful and enables 2 tests for serverless (loading a query from url and profiling a simple query with a test index).
This commit is contained in:
parent
387cb38bd9
commit
7faa488a13
9 changed files with 222 additions and 33 deletions
|
@ -6,26 +6,27 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { compressToEncodedURIComponent } from 'lz-string';
|
|
||||||
import { asyncForEach } from '@kbn/std';
|
import { asyncForEach } from '@kbn/std';
|
||||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
|
||||||
|
const testIndex = 'test-index';
|
||||||
|
const testQuery = {
|
||||||
|
query: {
|
||||||
|
match_all: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
const PageObjects = getPageObjects(['common']);
|
const PageObjects = getPageObjects(['common', 'searchProfiler']);
|
||||||
const testSubjects = getService('testSubjects');
|
|
||||||
const aceEditor = getService('aceEditor');
|
|
||||||
const retry = getService('retry');
|
const retry = getService('retry');
|
||||||
const security = getService('security');
|
const security = getService('security');
|
||||||
const es = getService('es');
|
const es = getService('es');
|
||||||
const log = getService('log');
|
const log = getService('log');
|
||||||
|
|
||||||
const editorTestSubjectSelector = 'searchProfilerEditor';
|
|
||||||
|
|
||||||
describe('Search Profiler Editor', () => {
|
describe('Search Profiler Editor', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await security.testUser.setRoles(['global_devtools_read']);
|
await security.testUser.setRoles(['global_devtools_read']);
|
||||||
await PageObjects.common.navigateToApp('searchProfiler');
|
await PageObjects.common.navigateToApp('searchProfiler');
|
||||||
expect(await testSubjects.exists('searchProfilerEditor')).to.be(true);
|
expect(await PageObjects.searchProfiler.editorExists()).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
@ -36,7 +37,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
// The below inputs are written to work _with_ ace's autocomplete unlike console's unit test
|
// The below inputs are written to work _with_ ace's autocomplete unlike console's unit test
|
||||||
// counterparts in src/legacy/core_plugins/console/public/tests/src/editor.test.js
|
// counterparts in src/legacy/core_plugins/console/public/tests/src/editor.test.js
|
||||||
|
|
||||||
const okInput = [
|
const okInputs = [
|
||||||
`{
|
`{
|
||||||
"query": {
|
"query": {
|
||||||
"match_all": {}`,
|
"match_all": {}`,
|
||||||
|
@ -46,7 +47,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
"test": """{ "more": "json" }"""`,
|
"test": """{ "more": "json" }"""`,
|
||||||
];
|
];
|
||||||
|
|
||||||
const notOkInput = [
|
const notOkInputs = [
|
||||||
`{
|
`{
|
||||||
"query": {
|
"query": {
|
||||||
"match_all": {
|
"match_all": {
|
||||||
|
@ -59,24 +60,24 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
|
|
||||||
const expectHasParseErrorsToBe = (expectation: boolean) => async (inputs: string[]) => {
|
const expectHasParseErrorsToBe = (expectation: boolean) => async (inputs: string[]) => {
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
await aceEditor.setValue(editorTestSubjectSelector, input);
|
await PageObjects.searchProfiler.setQuery(input);
|
||||||
|
|
||||||
await retry.waitFor(
|
await retry.waitFor(
|
||||||
`parser errors to match expectation: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`,
|
`parser errors to match expectation: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`,
|
||||||
async () => {
|
async () => {
|
||||||
const actual = await aceEditor.hasParseErrors(editorTestSubjectSelector);
|
const actual = await PageObjects.searchProfiler.editorHasParseErrors();
|
||||||
return expectation === actual;
|
return expectation === actual;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await expectHasParseErrorsToBe(false)(okInput);
|
await expectHasParseErrorsToBe(false)(okInputs);
|
||||||
await expectHasParseErrorsToBe(true)(notOkInput);
|
await expectHasParseErrorsToBe(true)(notOkInputs);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports pre-configured search query', async () => {
|
it('supports pre-configured search query', async () => {
|
||||||
const searchQuery = {
|
const query = {
|
||||||
query: {
|
query: {
|
||||||
bool: {
|
bool: {
|
||||||
should: [
|
should: [
|
||||||
|
@ -106,24 +107,21 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
// this index name is just an input placeholder and does not exist
|
// this index name is just an input placeholder and does not exist
|
||||||
const indexName = 'my_index';
|
const indexName = 'my_index';
|
||||||
|
|
||||||
const searchQueryURI = compressToEncodedURIComponent(JSON.stringify(searchQuery, null, 2));
|
|
||||||
|
|
||||||
await PageObjects.common.navigateToUrl(
|
await PageObjects.common.navigateToUrl(
|
||||||
'searchProfiler',
|
'searchProfiler',
|
||||||
`/searchprofiler?index=${indexName}&load_from=${searchQueryURI}`,
|
PageObjects.searchProfiler.getUrlWithIndexAndQuery({ indexName, query }),
|
||||||
{
|
{
|
||||||
useActualUrl: true,
|
useActualUrl: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const indexInput = await testSubjects.find('indexName');
|
const indexInputValue = await PageObjects.searchProfiler.getIndexName();
|
||||||
const indexInputValue = await indexInput.getAttribute('value');
|
|
||||||
|
|
||||||
expect(indexInputValue).to.eql(indexName);
|
expect(indexInputValue).to.eql(indexName);
|
||||||
|
|
||||||
await retry.try(async () => {
|
await retry.try(async () => {
|
||||||
const searchProfilerInput = JSON.parse(await aceEditor.getValue('searchProfilerEditor'));
|
const searchProfilerInput = await PageObjects.searchProfiler.getQuery();
|
||||||
expect(searchProfilerInput).to.eql(searchQuery);
|
expect(searchProfilerInput).to.eql(query);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -148,23 +146,35 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error if profile is executed with no valid indices', async () => {
|
it('returns error if profile is executed with no valid indices', async () => {
|
||||||
const input = {
|
await PageObjects.searchProfiler.setIndexName('_all');
|
||||||
query: {
|
await PageObjects.searchProfiler.setQuery(testQuery);
|
||||||
match_all: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
await testSubjects.setValue('indexName', '_all');
|
await PageObjects.searchProfiler.clickProfileButton();
|
||||||
await aceEditor.setValue(editorTestSubjectSelector, JSON.stringify(input));
|
|
||||||
|
|
||||||
await testSubjects.click('profileButton');
|
|
||||||
|
|
||||||
await retry.waitFor('notification renders', async () => {
|
await retry.waitFor('notification renders', async () => {
|
||||||
const notification = await testSubjects.find('noShardsNotification');
|
return await PageObjects.searchProfiler.editorHasErrorNotification();
|
||||||
const notificationText = await notification.getVisibleText();
|
|
||||||
return notificationText.includes('Unable to profile');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('With a test index', () => {
|
||||||
|
before(async () => {
|
||||||
|
await es.indices.create({ index: testIndex });
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await es.indices.delete({ index: testIndex });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('profiles a simple query', async () => {
|
||||||
|
await PageObjects.searchProfiler.setIndexName(testIndex);
|
||||||
|
await PageObjects.searchProfiler.setQuery(testQuery);
|
||||||
|
|
||||||
|
await PageObjects.searchProfiler.clickProfileButton();
|
||||||
|
|
||||||
|
const content = await PageObjects.searchProfiler.getProfileContent();
|
||||||
|
expect(content).to.contain(testIndex);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ import { UpgradeAssistantPageObject } from './upgrade_assistant_page';
|
||||||
import { UptimePageObject } from './uptime_page';
|
import { UptimePageObject } from './uptime_page';
|
||||||
import { UserProfilePageProvider } from './user_profile_page';
|
import { UserProfilePageProvider } from './user_profile_page';
|
||||||
import { WatcherPageObject } from './watcher_page';
|
import { WatcherPageObject } from './watcher_page';
|
||||||
|
import { SearchProfilerPageProvider } from './search_profiler_page';
|
||||||
|
|
||||||
// just like services, PageObjects are defined as a map of
|
// just like services, PageObjects are defined as a map of
|
||||||
// names to Providers. Merge in Kibana's or pick specific ones
|
// names to Providers. Merge in Kibana's or pick specific ones
|
||||||
|
@ -87,6 +88,7 @@ export const pageObjects = {
|
||||||
reporting: ReportingPageObject,
|
reporting: ReportingPageObject,
|
||||||
roleMappings: RoleMappingsPageProvider,
|
roleMappings: RoleMappingsPageProvider,
|
||||||
rollup: RollupPageObject,
|
rollup: RollupPageObject,
|
||||||
|
searchProfiler: SearchProfilerPageProvider,
|
||||||
searchSessionsManagement: SearchSessionsPageProvider,
|
searchSessionsManagement: SearchSessionsPageProvider,
|
||||||
security: SecurityPageObject,
|
security: SecurityPageObject,
|
||||||
shareSavedObjectsToSpace: ShareSavedObjectsToSpacePageProvider,
|
shareSavedObjectsToSpace: ShareSavedObjectsToSpacePageProvider,
|
||||||
|
|
54
x-pack/test/functional/page_objects/search_profiler_page.ts
Normal file
54
x-pack/test/functional/page_objects/search_profiler_page.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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 { compressToEncodedURIComponent } from 'lz-string';
|
||||||
|
import { FtrProviderContext } from '../ftr_provider_context';
|
||||||
|
|
||||||
|
export function SearchProfilerPageProvider({ getService }: FtrProviderContext) {
|
||||||
|
const find = getService('find');
|
||||||
|
const testSubjects = getService('testSubjects');
|
||||||
|
const aceEditor = getService('aceEditor');
|
||||||
|
const editorTestSubjectSelector = 'searchProfilerEditor';
|
||||||
|
|
||||||
|
return {
|
||||||
|
async editorExists() {
|
||||||
|
return await testSubjects.exists(editorTestSubjectSelector);
|
||||||
|
},
|
||||||
|
async setQuery(query: any) {
|
||||||
|
await aceEditor.setValue(editorTestSubjectSelector, JSON.stringify(query));
|
||||||
|
},
|
||||||
|
async getQuery() {
|
||||||
|
return JSON.parse(await aceEditor.getValue(editorTestSubjectSelector));
|
||||||
|
},
|
||||||
|
async setIndexName(indexName: string) {
|
||||||
|
await testSubjects.setValue('indexName', indexName);
|
||||||
|
},
|
||||||
|
async getIndexName() {
|
||||||
|
const indexInput = await testSubjects.find('indexName');
|
||||||
|
return await indexInput.getAttribute('value');
|
||||||
|
},
|
||||||
|
async clickProfileButton() {
|
||||||
|
await testSubjects.click('profileButton');
|
||||||
|
},
|
||||||
|
async getProfileContent() {
|
||||||
|
const profileTree = await find.byClassName('prfDevTool__main__profiletree');
|
||||||
|
return profileTree.getVisibleText();
|
||||||
|
},
|
||||||
|
getUrlWithIndexAndQuery({ indexName, query }: { indexName: string; query: any }) {
|
||||||
|
const searchQueryURI = compressToEncodedURIComponent(JSON.stringify(query, null, 2));
|
||||||
|
return `/searchprofiler?index=${indexName}&load_from=${searchQueryURI}`;
|
||||||
|
},
|
||||||
|
async editorHasParseErrors() {
|
||||||
|
return await aceEditor.hasParseErrors(editorTestSubjectSelector);
|
||||||
|
},
|
||||||
|
async editorHasErrorNotification() {
|
||||||
|
const notification = await testSubjects.find('noShardsNotification');
|
||||||
|
const text = await notification.getVisibleText();
|
||||||
|
return text.includes('Unable to profile');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -103,6 +103,10 @@ export function createTestConfig(options: CreateTestConfigOptions) {
|
||||||
pathname: '/app/discover',
|
pathname: '/app/discover',
|
||||||
hash: '/context',
|
hash: '/context',
|
||||||
},
|
},
|
||||||
|
searchProfiler: {
|
||||||
|
pathname: '/app/dev_tools',
|
||||||
|
hash: '/searchprofiler',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
// choose where screenshots should be saved
|
// choose where screenshots should be saved
|
||||||
screenshots: {
|
screenshots: {
|
||||||
|
|
|
@ -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 { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
|
||||||
|
export default ({ loadTestFile }: FtrProviderContext) => {
|
||||||
|
describe('Serverless Common UI - Dev Tools', function () {
|
||||||
|
loadTestFile(require.resolve('./search_profiler'));
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
const testIndex = 'test-index';
|
||||||
|
const testQuery = {
|
||||||
|
query: {
|
||||||
|
match_all: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||||
|
const PageObjects = getPageObjects(['svlCommonPage', 'common', 'searchProfiler']);
|
||||||
|
const retry = getService('retry');
|
||||||
|
const es = getService('es');
|
||||||
|
|
||||||
|
describe('Search Profiler Editor', () => {
|
||||||
|
before(async () => {
|
||||||
|
await PageObjects.svlCommonPage.login();
|
||||||
|
await PageObjects.common.navigateToApp('searchProfiler');
|
||||||
|
expect(await PageObjects.searchProfiler.editorExists()).to.be(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await PageObjects.svlCommonPage.forceLogout();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports pre-configured search query', async () => {
|
||||||
|
const query = {
|
||||||
|
query: {
|
||||||
|
bool: {
|
||||||
|
should: [
|
||||||
|
{
|
||||||
|
match: {
|
||||||
|
name: 'fred',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
terms: {
|
||||||
|
name: ['sue', 'sally'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
aggs: {
|
||||||
|
stats: {
|
||||||
|
stats: {
|
||||||
|
field: 'price',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Since we're not actually running the query in the test,
|
||||||
|
// this index name is just an input placeholder and does not exist
|
||||||
|
const indexName = 'my_index';
|
||||||
|
|
||||||
|
await PageObjects.common.navigateToUrl(
|
||||||
|
'searchProfiler',
|
||||||
|
PageObjects.searchProfiler.getUrlWithIndexAndQuery({ indexName, query }),
|
||||||
|
{
|
||||||
|
useActualUrl: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const indexInputValue = await PageObjects.searchProfiler.getIndexName();
|
||||||
|
|
||||||
|
expect(indexInputValue).to.eql(indexName);
|
||||||
|
|
||||||
|
await retry.try(async () => {
|
||||||
|
const searchProfilerInput = await PageObjects.searchProfiler.getQuery();
|
||||||
|
expect(searchProfilerInput).to.eql(query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('With a test index', () => {
|
||||||
|
before(async () => {
|
||||||
|
await es.indices.create({ index: testIndex });
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await es.indices.delete({ index: testIndex });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('profiles a simple query', async () => {
|
||||||
|
await PageObjects.searchProfiler.setIndexName(testIndex);
|
||||||
|
await PageObjects.searchProfiler.setQuery(testQuery);
|
||||||
|
|
||||||
|
await PageObjects.searchProfiler.clickProfileButton();
|
||||||
|
|
||||||
|
const content = await PageObjects.searchProfiler.getProfileContent();
|
||||||
|
expect(content).to.contain(testIndex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||||
testFiles: [
|
testFiles: [
|
||||||
require.resolve('../../common/home_page'),
|
require.resolve('../../common/home_page'),
|
||||||
require.resolve('../../common/management'),
|
require.resolve('../../common/management'),
|
||||||
|
require.resolve('../../common/dev_tools'),
|
||||||
require.resolve('../../common/platform_security'),
|
require.resolve('../../common/platform_security'),
|
||||||
require.resolve('../../common/reporting'),
|
require.resolve('../../common/reporting'),
|
||||||
require.resolve('../../common/grok_debugger'),
|
require.resolve('../../common/grok_debugger'),
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||||
testFiles: [
|
testFiles: [
|
||||||
require.resolve('../../common/home_page'),
|
require.resolve('../../common/home_page'),
|
||||||
require.resolve('../../common/management'),
|
require.resolve('../../common/management'),
|
||||||
|
require.resolve('../../common/dev_tools'),
|
||||||
require.resolve('../../common/platform_security'),
|
require.resolve('../../common/platform_security'),
|
||||||
require.resolve('../../common/reporting'),
|
require.resolve('../../common/reporting'),
|
||||||
require.resolve('../../common/console'),
|
require.resolve('../../common/console'),
|
||||||
|
|
|
@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||||
testFiles: [
|
testFiles: [
|
||||||
require.resolve('../../common/home_page'),
|
require.resolve('../../common/home_page'),
|
||||||
require.resolve('../../common/management'),
|
require.resolve('../../common/management'),
|
||||||
|
require.resolve('../../common/dev_tools'),
|
||||||
require.resolve('../../common/platform_security'),
|
require.resolve('../../common/platform_security'),
|
||||||
require.resolve('../../common/reporting'),
|
require.resolve('../../common/reporting'),
|
||||||
require.resolve('../../common/grok_debugger'),
|
require.resolve('../../common/grok_debugger'),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue