CCS Smoke Test for Remote Clusters and Index Management (#142423)

* Removed comment of the issue that was referenced for the skip. But the tests were already skipped.

* Added initial tests and page objects for remtoe clusters.

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* Fixed the test and test names.

* removed exclusive suite.

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* Fixed i18n issue.

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* Added more testing stuff.

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* Added more testing stuff.

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* Added test and stuff.

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* Fixed the tests. The only things to update now are the permissions so we stop using super user and also need to fix the cleanup.

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* Fixed accessibility test to use new ccr page function.

* Fixed an error in checks.

* Restored original settings.

* Adjusted cleanup.

* Removed exclusive suite.

* Removed unused variable.

* Removed unused variable.

* Working with perms.

* Fixes per comments in PR.

* added follower index user.

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* Added comment about super user issue.

* Removed the console.log.

* Fixed nits per PR.

* Removed extra assertion.

Co-authored-by: cuffs <cuffs@cuffss-Office-MacBook-Pro.local>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
John Dorlus 2022-11-01 01:14:21 -04:00 committed by GitHub
parent 96a9f913d8
commit f5acf76351
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 278 additions and 34 deletions

View file

@ -41,11 +41,15 @@ export function ConnectionStatus({ isConnected, mode }) {
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<span className="eui-displayBlock">{icon}</span>
<span data-test-subj="remoteClusterConnectionStatusIcon" className="eui-displayBlock">
{icon}
</span>
</EuiFlexItem>
<EuiFlexItem grow={false} className="remoteClustersConnectionStatus__message">
<EuiText size="s">{message}</EuiText>
<EuiText data-test-subj="remoteClusterConnectionStatusMessage" size="s">
{message}
</EuiText>
</EuiFlexItem>
{!isConnected && mode === SNIFF_MODE && (

View file

@ -19,6 +19,7 @@ import {
EuiInMemoryTable,
EuiLink,
EuiToolTip,
EuiText,
} from '@elastic/eui';
import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public';
import { UIM_SHOW_DETAILS_CLICK } from '../../../constants';
@ -205,24 +206,47 @@ export class RemoteClusterTable extends Component {
defaultMessage: 'Mode',
}),
sortable: true,
render: (mode) =>
render: (mode) => {
let modeMessage;
mode === PROXY_MODE
? mode
: i18n.translate('xpack.remoteClusters.remoteClusterList.table.sniffModeDescription', {
defaultMessage: 'default',
}),
? (modeMessage = mode)
: (modeMessage = i18n.translate(
'xpack.remoteClusters.remoteClusterList.table.sniffModeDescription',
{
defaultMessage: 'default',
}
));
const modeMessageComponent = (
<EuiFlexItem grow={false} className="remoteClustersConnectionMode__message">
<EuiText
id="xpack.remoteClusters.remoteClusterList.table.sniffModeDescription"
data-test-subj="remoteClusterConnectionModeMessage"
size="s"
>
{modeMessage}
</EuiText>
</EuiFlexItem>
);
return modeMessageComponent;
},
},
{
field: 'mode',
name: i18n.translate('xpack.remoteClusters.remoteClusterList.table.addressesColumnTitle', {
defaultMessage: 'Addresses',
}),
dataTestSubj: 'remoteClustersAddress',
truncateText: true,
render: (mode, { seeds, proxyAddress }) => {
if (mode === PROXY_MODE) {
return proxyAddress;
}
return seeds.join(', ');
const clusterAddressString = mode === PROXY_MODE ? proxyAddress : seeds.join(', ');
const connectionMode = (
<EuiFlexItem grow={false} className="remoteClustersConnectionAddress__message">
<EuiText data-test-subj="remoteClusterConnectionAddressMessage" size="s">
{clusterAddressString}
</EuiText>
</EuiFlexItem>
);
return connectionMode;
},
},
{
@ -236,10 +260,16 @@ export class RemoteClusterTable extends Component {
sortable: true,
width: '160px',
render: (mode, { connectedNodesCount, connectedSocketsCount }) => {
if (mode === PROXY_MODE) {
return connectedSocketsCount;
}
return connectedNodesCount;
const remoteNodesCount =
mode === PROXY_MODE ? connectedSocketsCount : connectedNodesCount;
const connectionMode = (
<EuiFlexItem grow={false} className="remoteClustersNodeCount__message">
<EuiText data-test-subj="remoteClusterNodeCountMessage" size="s">
{remoteNodesCount}
</EuiText>
</EuiFlexItem>
);
return connectionMode;
},
},
{

View file

@ -46,7 +46,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.common.navigateToApp('crossClusterReplication');
await PageObjects.crossClusterReplication.clickCreateFollowerIndexButton();
await a11y.testAppSnapshot();
await PageObjects.crossClusterReplication.createFollowerIndex(testLeader, testFollower);
await PageObjects.crossClusterReplication.createFollowerIndex(
testLeader,
testFollower,
false
);
});
it('follower index flyout', async () => {
// https://github.com/elastic/kibana/issues/135503

View file

@ -0,0 +1,114 @@
/*
* 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 ({ getPageObjects, getService }: FtrProviderContext) => {
const pageObjects = getPageObjects([
'common',
'remoteClusters',
'indexManagement',
'crossClusterReplication',
]);
const security = getService('security');
const retry = getService('retry');
const testSubjects = getService('testSubjects');
const remoteEs = getService('remoteEs' as 'es');
const localEs = getService('es');
describe('CCS Remote Clusters > Index Management', function () {
const leaderName = 'my-index';
const followerName = 'my-follower';
before(async () => {
await security.testUser.setRoles(['superuser']);
// This test is temporarily using superuser because of an issue with the permissions
// of the follower index creation wizard. There is an open issue to address the issue.
// We can change the permissions to use follower_index_user once the issue is fixed.
// https://github.com/elastic/kibana/issues/143720
// await security.testUser.setRoles(['follower_index_user']);
});
describe('Remote Clusters', function () {
before(async () => {
await pageObjects.common.navigateToApp('remoteClusters');
});
it('Verify "ftr-remote" remote cluster exists', async () => {
await retry.waitFor('table to be visible', async () => {
return await testSubjects.isDisplayed('remoteClusterListTable');
});
const remotes = await pageObjects.remoteClusters.getRemoteClustersList();
expect(remotes.length).to.eql(1);
expect(remotes[0].remoteName).to.eql('ftr-remote');
expect(remotes[0].remoteAddress).to.contain('localhost');
expect(remotes[0].remoteStatus).to.eql('Connected');
expect(remotes[0].remoteConnectionCount).to.eql('1');
expect(remotes[0].remoteMode).to.eql('default');
});
});
describe('Cross Cluster Replication', function () {
before(async () => {
await remoteEs.indices.create({
index: leaderName,
body: {
settings: { number_of_shards: 1, soft_deletes: { enabled: true } },
},
});
await pageObjects.common.navigateToApp('crossClusterReplication');
await retry.waitFor('indices table to be visible', async () => {
return await testSubjects.isDisplayed('createFollowerIndexButton');
});
});
it('Create Follower Index', async () => {
await pageObjects.crossClusterReplication.clickCreateFollowerIndexButton();
await pageObjects.crossClusterReplication.createFollowerIndex(
leaderName,
followerName,
true,
'1s'
);
});
});
describe('Index Management', function () {
before(async () => {
await remoteEs.index({
index: leaderName,
body: { a: 'b' },
});
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
});
});
it('Verify that the follower index is duplicating from the remote.', async () => {
await pageObjects.indexManagement.clickIndiceAt(0);
await pageObjects.indexManagement.performIndexActionInDetailPanel('flush');
await testSubjects.click('euiFlyoutCloseButton');
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
});
const indicesList = await pageObjects.indexManagement.getIndexList();
const followerIndex = indicesList[0];
expect(followerIndex.indexDocuments).to.eql('1');
});
});
after(async () => {
await localEs.indices.delete({
index: followerName,
});
await remoteEs.indices.delete({
index: leaderName,
});
await security.testUser.restoreDefaults();
});
});
};

View file

@ -499,6 +499,33 @@ export default async function ({ readConfigFile }) {
cluster: ['manage', 'manage_ccr'],
},
},
// There is an issue open for follower_index_user permissions not working correctly
// in kibana.
// https://github.com/elastic/kibana/issues/143720
// follower_index_user: {
// elasticsearch: {
// cluster: ['monitor', 'manage', 'manage_ccr', 'transport_client', 'read_ccr', 'all'],
// indices: [
// {
// names: ['*'],
// privileges: [
// 'write',
// 'monitor',
// 'manage_follow_index',
// 'manage_leader_index',
// 'read',
// 'view_index_metadata',
// ],
// },
// ],
// },
// kibana: [
// {
// base: ['all'],
// spaces: ['*'],
// },
// ],
// },
manage_ilm: {
elasticsearch: {

View file

@ -18,6 +18,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
testFiles: [
require.resolve('./apps/canvas'),
require.resolve('./apps/lens/group1'),
require.resolve('./apps/remote_clusters/ccs/remote_clusters_index_management_flow'),
require.resolve('./apps/rollup_job'),
],
@ -29,10 +30,11 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
...functionalConfig.get('security'),
remoteEsRoles: {
ccs_remote_search: {
cluster: ['manage', 'manage_ccr'],
indices: [
{
names: ['*'],
privileges: ['read', 'view_index_metadata', 'read_cross_cluster'],
privileges: ['read', 'view_index_metadata', 'read_cross_cluster', 'monitor'],
},
],
},

View file

@ -39,9 +39,23 @@ export function CrossClusterReplicationPageProvider({ getService }: FtrProviderC
return await testSubjects.isDisplayed('nameInput');
});
},
async createFollowerIndex(leader: string, follower: string) {
async createFollowerIndex(
leader: string,
follower: string,
advancedSettings: boolean = false,
readPollTimeout?: string
) {
await testSubjects.setValue('leaderIndexInput', leader);
await testSubjects.setValue('followerIndexInput', follower);
if (advancedSettings) {
await this.clickAdvancedSettingsToggle();
await retry.waitFor('advanced settings to be shown', async () => {
return await testSubjects.isDisplayed('readPollTimeoutInput');
});
if (readPollTimeout) {
await testSubjects.setValue('readPollTimeoutInput', readPollTimeout);
}
}
await testSubjects.click('submitButton');
await retry.waitForWithTimeout('follower index to be in table', 45000, async () => {
return await testSubjects.isDisplayed('maxReadReqSize');
@ -55,5 +69,8 @@ export function CrossClusterReplicationPageProvider({ getService }: FtrProviderC
return await testSubjects.isDisplayed('settingsValues');
});
},
async clickAdvancedSettingsToggle() {
await testSubjects.click('advancedSettingsToggle');
},
};
}

View file

@ -41,26 +41,46 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
});
},
async performIndexActionInDetailPanel(action: string) {
await this.clickContextMenuInDetailPanel();
if (action === 'flush') {
await testSubjects.click('flushIndexMenuButton');
}
},
async clickContextMenuInDetailPanel() {
await testSubjects.click('indexActionsContextMenuButton');
},
async getIndexList() {
const table = await find.byCssSelector('table');
const $ = await table.parseDomContent();
const indexList = await $.findTestSubjects('indexTableRow')
.toArray()
.map((row) => {
const rows = await table.findAllByTestSubject('indexTableRow');
return await Promise.all(
rows.map(async (row) => {
return {
indexName: $(row).findTestSubject('indexTableIndexNameLink').text(),
indexHealth: $(row).findTestSubject('indexTableCell-health').text(),
indexStatus: $(row).findTestSubject('indexTableCell-status').text(),
indexPrimary: $(row).findTestSubject('indexTableCell-primary').text(),
indexReplicas: $(row).findTestSubject('indexTableCell-replica').text(),
indexDocuments: $(row)
.findTestSubject('indexTableCell-documents')
.text()
.replace('documents', ''),
indexSize: $(row).findTestSubject('indexTableCell-size').text(),
indexLink: await row.findByTestSubject('indexTableIndexNameLink'),
indexName: await (
await row.findByTestSubject('indexTableIndexNameLink')
).getVisibleText(),
indexHealth: await (
await row.findByTestSubject('indexTableCell-health')
).getVisibleText(),
indexStatus: await (
await row.findByTestSubject('indexTableCell-status')
).getVisibleText(),
indexPrimary: await (
await row.findByTestSubject('indexTableCell-primary')
).getVisibleText(),
indexReplicas: await (
await row.findByTestSubject('indexTableCell-replica')
).getVisibleText(),
indexDocuments: await (
await (await row.findByTestSubject('indexTableCell-documents')).getVisibleText()
).replace('documents', ''),
indexSize: await (await row.findByTestSubject('indexTableCell-size')).getVisibleText(),
};
});
return indexList;
})
);
},
async changeTabs(

View file

@ -31,5 +31,31 @@ export function RemoteClustersPageProvider({ getService }: FtrProviderContext) {
await comboBox.setCustom('comboBoxInput', seedNode);
await testSubjects.click('remoteClusterFormSaveButton');
},
async getRemoteClustersList() {
const table = await testSubjects.find('remoteClusterListTable');
const rows = await table.findAllByCssSelector('.euiTableRow');
return await Promise.all(
rows.map(async (row) => {
return {
remoteLink: await row.findByTestSubject('remoteClustersTableListClusterLink'),
remoteName: await (
await row.findByTestSubject('remoteClustersTableListClusterLink')
).getVisibleText(),
remoteStatus: await (
await row.findByTestSubject('remoteClusterConnectionStatusMessage')
).getVisibleText(),
remoteMode: await (
await row.findByTestSubject('remoteClusterConnectionModeMessage')
).getVisibleText(),
remoteAddress: await (
await row.findByTestSubject('remoteClusterConnectionAddressMessage')
).getVisibleText(),
remoteConnectionCount: await (
await row.findByTestSubject('remoteClusterNodeCountMessage')
).getVisibleText(),
};
})
);
},
};
}