mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
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:
parent
96a9f913d8
commit
f5acf76351
9 changed files with 278 additions and 34 deletions
|
@ -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 && (
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
};
|
|
@ -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: {
|
||||
|
|
|
@ -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'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -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');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue