Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Infrastructure UI] Functional tests Hosts View Alerts tab #152228

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const AlertsTabContent = () => {

return (
<HeightRetainer>
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexGroup direction="column" gutterSize="m" data-test-subj="hostsView-alerts">
<EuiFlexGroup justifyContent="flexStart" alignItems="center">
<EuiFlexItem grow={false}>
<AlertsStatusFilter onChange={setAlertStatus} status={alertStatus} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ export const AlertsTabBadge = () => {
typeof alertsCount?.activeAlertCount === 'number' && alertsCount.activeAlertCount > 0;

return shouldRenderBadge ? (
<EuiNotificationBadge className="eui-alignCenter" size="m">
<EuiNotificationBadge
className="eui-alignCenter"
size="m"
data-test-subj="hostsView-tabs-alerts-count"
>
{alertsCount?.activeAlertCount}
</EuiNotificationBadge>
) : null;
Expand Down
2 changes: 2 additions & 0 deletions x-pack/test/functional/apps/infra/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ export const ML_JOB_IDS = [
];

export const HOSTS_LINK_LOCAL_STORAGE_KEY = 'inventoryUI:hostsLinkClicked';

export const HOSTS_VIEW_PATH = 'metrics/hosts';
267 changes: 145 additions & 122 deletions x-pack/test/functional/apps/infra/hosts_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
*/

import expect from '@kbn/expect';
import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common';
import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils';
import moment from 'moment';
import { FtrProviderContext } from '../../ftr_provider_context';
import { DATES, HOSTS_LINK_LOCAL_STORAGE_KEY } from './constants';
import { DATES, HOSTS_LINK_LOCAL_STORAGE_KEY, HOSTS_VIEW_PATH } from './constants';

const START_DATE = moment.utc(DATES.metricsAndLogs.hosts.min);
const END_DATE = moment.utc(DATES.metricsAndLogs.hosts.max);
Expand All @@ -18,6 +20,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const kibanaServer = getService('kibanaServer');
const esArchiver = getService('esArchiver');
const browser = getService('browser');
const find = getService('find');
const security = getService('security');
const pageObjects = getPageObjects([
'common',
Expand All @@ -29,9 +32,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
]);

// Helpers
const setHostViewEnabled = (value: boolean = true) =>
kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value });

const loginWithReadOnlyUserAndNavigateToInfra = async () => {
await security.role.create('global_hosts_read_privileges_role', {
const loginWithReadOnlyUser = async () => {
const roleCreation = security.role.create('global_hosts_read_privileges_role', {
elasticsearch: {
indices: [{ names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] }],
},
Expand All @@ -46,13 +51,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
],
});

await security.user.create('global_hosts_read_privileges_user', {
const userCreation = security.user.create('global_hosts_read_privileges_user', {
password: 'global_hosts_read_privileges_user-password',
roles: ['global_hosts_read_privileges_role'],
full_name: 'test user',
});

await pageObjects.security.forceLogout();
const logout = pageObjects.security.forceLogout();

await Promise.all([roleCreation, userCreation, logout]);

await pageObjects.security.login(
'global_hosts_read_privileges_user',
Expand All @@ -61,87 +68,55 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expectSpaceSelector: false,
}
);

await browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
await pageObjects.common.navigateToApp('infraOps');
};

const logoutAndDeleteReadOnlyUser = async () => {
await pageObjects.security.forceLogout();
await Promise.all([
const logoutAndDeleteReadOnlyUser = () =>
Promise.all([
pageObjects.security.forceLogout(),
security.role.delete('global_hosts_read_privileges_role'),
security.user.delete('global_hosts_read_privileges_user'),
]);
};

const navigateAndDisableHostView = async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.common.navigateToUrl('management', 'kibana/settings', {
basePath: `/s/default`,
ensureCurrentUrl: false,
shouldLoginIfPrompted: false,
shouldUseHashForSubUrl: false,
});
await pageObjects.settings.toggleAdvancedSettingCheckbox(
'observability:enableInfrastructureHostsView',
false
);
return esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
};

const navigateAndEnableHostView = async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await pageObjects.infraHostsView.clickTryHostViewLink();
await pageObjects.infraHostsView.clickEnableHostViewButton();
};
const enableHostView = () => pageObjects.infraHostsView.clickEnableHostViewButton();

// Tests

describe('Hosts view', function () {
describe('Hosts View', function () {
this.tags('includeFirefox');

before(async () => {
await kibanaServer.savedObjects.cleanStandardList();
await Promise.all([
esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'),
esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
kibanaServer.savedObjects.cleanStandardList(),
]);
});

describe('shows hosts view landing page for admin', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await pageObjects.infraHostsView.clickTryHostViewBadge();
});
after(async () => {
await browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
return esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
});
after(() => {
esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts');
esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
});

it('should show hosts landing page with enable button when the hosts view is disabled', async () => {
const landingPageEnableButton =
await pageObjects.infraHostsView.getHostsLandingPageEnableButton();
const landingPageEnableButtonText = await landingPageEnableButton.getVisibleText();
expect(landingPageEnableButtonText).to.eql('Enable hosts view');
});
it('should be accessible from the Inventory page', async () => {
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await pageObjects.infraHostsView.clickTryHostViewBadge();

const pageUrl = await browser.getCurrentUrl();

expect(pageUrl).to.contain(HOSTS_VIEW_PATH);
});

describe('should show hosts view landing page for user with read permission', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await loginWithReadOnlyUserAndNavigateToInfra();
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await pageObjects.infraHostsView.clickTryHostViewBadge();
});
after(async () => {
// NOTE: Logout needs to happen before anything else to avoid flaky behavior
await logoutAndDeleteReadOnlyUser();
return esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
describe('#Landing page', () => {
beforeEach(() => {
setHostViewEnabled(false);
});

it('should show hosts landing page with callout when the hosts view is disabled', async () => {
it('as a user with read permission, should show hosts landing page with callout when the hosts view is disabled', async () => {
await loginWithReadOnlyUser();
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);

const landingPageDisabled = await pageObjects.infraHostsView.getHostsLandingPageDisabled();
const learnMoreDocsUrl = await pageObjects.infraHostsView.getHostsLandingPageDocsLink();
const parsedUrl = new URL(learnMoreDocsUrl);
Expand All @@ -151,33 +126,57 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(landingPageDisabled).to.contain(
'Your user role doesn’t have sufficient privileges to enable this feature'
);

await logoutAndDeleteReadOnlyUser();
});

it('as an admin, should see an enable button when the hosts view is disabled', async () => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);

const landingPageEnableButton =
await pageObjects.infraHostsView.getHostsLandingPageEnableButton();
const landingPageEnableButtonText = await landingPageEnableButton.getVisibleText();
expect(landingPageEnableButtonText).to.eql('Enable hosts view');
});

it('as an admin, should be able to enable the hosts view feature', async () => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await enableHostView();

const titleElement = await find.byCssSelector('h1');
const title = await titleElement.getVisibleText();

expect(title).to.contain('Hosts');
});
});

describe('enables hosts view page and checks content', () => {
describe('#Page Content', () => {
before(async () => {
await navigateAndEnableHostView();
await setHostViewEnabled(true);
await loginWithReadOnlyUser();
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(timepickerFormat),
END_DATE.format(timepickerFormat)
);
});

after(async () => {
await navigateAndDisableHostView();
await logoutAndDeleteReadOnlyUser();
});

describe('should show hosts page for admin user and see the page content', async () => {
it('should render the correct page title', async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain('Hosts - Infrastructure - Observability - Elastic');
});
it('should render the correct page title', async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain('Hosts - Infrastructure - Observability - Elastic');
});

it('should have six hosts', async () => {
const hosts = await pageObjects.infraHostsView.getHostsTableData();
expect(hosts.length).to.equal(6);
});
it('should render a table with 6 hosts', async () => {
const hosts = await pageObjects.infraHostsView.getHostsTableData();
expect(hosts.length).to.equal(6);
});

it('should load 5 metrics trend tiles', async () => {
describe('KPI tiles', () => {
it('should render 5 metrics trend tiles', async () => {
const hosts = await pageObjects.infraHostsView.getAllMetricsTrendTiles();
expect(hosts.length).to.equal(5);
});
Expand All @@ -195,56 +194,80 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
});
});

describe('should show hosts page for read only user and see the page content', async () => {
before(async () => {
await navigateAndEnableHostView();
await loginWithReadOnlyUserAndNavigateToInfra();
await browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY);
await pageObjects.infraHostsView.clickTryHostViewLink();
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(timepickerFormat),
END_DATE.format(timepickerFormat)
);
});
after(async () => {
// NOTE: Logout needs to happen before anything else to avoid flaky behavior
await logoutAndDeleteReadOnlyUser();
await navigateAndDisableHostView();
});
describe('Metrics Tab', () => {
it('should load 8 lens metric charts', async () => {
const metricCharts = await pageObjects.infraHostsView.getAllMetricsCharts();
expect(metricCharts.length).to.equal(8);
});

it('should have six hosts', async () => {
const hosts = await pageObjects.infraHostsView.getHostsTableData();
expect(hosts.length).to.equal(6);
it('should have an option to open the chart in lens', async () => {
await pageObjects.infraHostsView.getOpenInLensOption();
});
});

it('should load 5 metrics trend tiles', async () => {
const hosts = await pageObjects.infraHostsView.getAllMetricsTrendTiles();
expect(hosts.length).to.equal(5);
});
describe('Alerts Tab', () => {
const observability = getService('observability');
const testSubjects = getService('testSubjects');
const retry = getService('retry');

const ACTIVE_ALERTS = 6;
const RECOVERED_ALERTS = 4;
const ALL_ALERTS = ACTIVE_ALERTS + RECOVERED_ALERTS;
const COLUMNS = 5;

[
{ metric: 'hosts', value: '6' },
{ metric: 'cpu', value: '0.8%' },
{ metric: 'memory', value: '16.8%' },
{ metric: 'tx', value: '0 bit/s' },
{ metric: 'rx', value: '0 bit/s' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
const tileValue = await pageObjects.infraHostsView.getMetricsTrendTileValue(metric);
expect(tileValue).to.eql(value);
before(async () => {
await pageObjects.infraHostsView.visitAlertTab();
});
});

describe('Lens charts', () => {
it('should load 8 lens metric charts', async () => {
const metricCharts = await pageObjects.infraHostsView.getAllMetricsCharts();
expect(metricCharts.length).to.equal(8);
it('should correctly load the Alerts tab section when clicking on it', async () => {
testSubjects.existOrFail('hostsView-alerts');
});

it('should have an option to open the chart in lens', async () => {
await pageObjects.infraHostsView.getOpenInLensOption();
it('should correctly render a badge with the active alerts count', async () => {
const alertsCountBadge = await pageObjects.infraHostsView.getAlertsTabCountBadge();
const alertsCount = await alertsCountBadge.getVisibleText();

expect(alertsCount).to.be('6');
});

describe('#FilterButtonGroup', () => {
it('can be filtered to only show "active" alerts using the filter button', async () => {
await pageObjects.infraHostsView.setAlertStatusFilter(ALERT_STATUS_ACTIVE);
await retry.try(async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(ACTIVE_ALERTS);
});
});

it('can be filtered to only show "recovered" alerts using the filter button', async () => {
await pageObjects.infraHostsView.setAlertStatusFilter(ALERT_STATUS_RECOVERED);
await retry.try(async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(RECOVERED_ALERTS);
});
});

it('can be filtered to only show "all" alerts using the filter button', async () => {
await pageObjects.infraHostsView.setAlertStatusFilter();
await retry.try(async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(ALL_ALERTS);
});
});
});

describe('#AlertsTable', () => {
it('should correctly render', async () => {
await observability.alerts.common.getTableOrFail();
});

it('should renders the correct number of cells', async () => {
await retry.try(async () => {
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(ALL_ALERTS * COLUMNS);
});
});
});
});
});
Expand Down
Binary file not shown.
Loading