[ObsUX][Infra] Improve test in infra adding synthtrace (#190121)

Closes https://github.com/elastic/kibana/issues/189867

#### Summary

This PR improves the use of synthtrace as data generator for infra
functional test

#### What was done

- update `host.ts` in infra synthtrace client, so it can accept `cpu`
value as a param, added `core` metrics and the option to create a k8s
node same as a pod
- added `k8snode` entity to synthtrace client
- created `uninstallSystemPackage` method to
`infra_synthtrace_kibana_client`
- created a getter for the logs ES client in the test utils
- update and fix infra funtional tests

#### TODO in follow-up

- remove the use of archives
- get processes data also with synthtrace
- create alerts data with synthtrace
This commit is contained in:
Miriam 2024-08-26 10:40:14 +01:00 committed by GitHub
parent b2d0846434
commit c6126d9235
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1503 additions and 976 deletions

View file

@ -8,6 +8,7 @@
/* eslint-disable max-classes-per-file */
import { Entity, Fields } from '../entity';
import { Serializable } from '../serializable';
import { k8sNode } from './k8s_node';
import { pod } from './pod';
interface HostDocument extends Fields {
@ -20,17 +21,20 @@ interface HostDocument extends Fields {
'host.ip'?: string;
'host.os.name'?: string;
'host.os.version'?: string;
'host.os.platform'?: string;
'cloud.provider'?: string;
}
class Host extends Entity<HostDocument> {
cpu() {
cpu({ cpuTotalValue }: { cpuTotalValue?: number } = {}) {
return new HostMetrics({
...this.fields,
'system.cpu.total.norm.pct': 0.094,
'system.cpu.total.norm.pct': cpuTotalValue ?? 0.98,
'system.cpu.user.pct': 0.805,
'system.cpu.system.pct': 0.704,
'system.cpu.cores': 16,
'process.cpu.pct': 0.1,
'system.cpu.nice.pct': 0.1,
'metricset.period': 10000,
'metricset.name': 'cpu',
});
@ -45,6 +49,7 @@ class Host extends Entity<HostDocument> {
'system.memory.total': 68719476736,
'system.memory.used.bytes': 39964708864,
'system.memory.used.pct': 0.582,
'process.memory.pct': 0.1,
'metricset.period': 10000,
'metricset.name': 'memory',
});
@ -72,6 +77,22 @@ class Host extends Entity<HostDocument> {
});
}
core() {
return new HostMetrics({
...this.fields,
'system.core.total.pct': 0.98,
'system.core.user.pct': 0.805,
'system.core.nice.pct': 0.704,
'system.core.idle.pct': 0.1,
'system.core.iowait.pct': 0.1,
'system.core.irq.pct': 0.1,
'system.core.softirq.pct': 0.1,
'system.core.steal.pct': 0.1,
'metricset.period': 10000,
'metricset.name': 'core',
});
}
filesystem() {
return new HostMetrics({
...this.fields,
@ -96,6 +117,10 @@ class Host extends Entity<HostDocument> {
pod(uid: string) {
return pod(uid, this.fields['host.hostname']);
}
node(podUid: string) {
return k8sNode(this.fields['host.hostname'], podUid);
}
}
export interface HostMetricsDocument extends HostDocument {
@ -120,6 +145,17 @@ export interface HostMetricsDocument extends HostDocument {
'system.load'?: { 1: number; cores: number };
'host.network.ingress.bytes'?: number;
'host.network.egress.bytes'?: number;
'process.cpu.pct'?: number;
'process.memory.pct'?: number;
'system.core.total.pct'?: number;
'system.core.user.pct'?: number;
'system.core.nice.pct'?: number;
'system.core.idle.pct'?: number;
'system.core.iowait.pct'?: number;
'system.core.irq.pct'?: number;
'system.core.softirq.pct'?: number;
'system.core.steal.pct'?: number;
'system.cpu.nice.pct'?: number;
}
class HostMetrics extends Serializable<HostMetricsDocument> {}
@ -132,6 +168,7 @@ export function host(name: string): Host {
'host.name': name,
'host.ip': '10.128.0.2',
'host.os.name': 'Linux',
'host.os.platform': 'ubuntu',
'host.os.version': '4.19.76-linuxkit',
'cloud.provider': 'gcp',
});

View file

@ -11,13 +11,15 @@ import { host, HostMetricsDocument } from './host';
import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container';
import { pod, PodMetricsDocument } from './pod';
import { awsRds, AWSRdsMetricsDocument } from './aws/rds';
import { k8sNode, K8sNodeMetricsDocument } from './k8s_node';
export type InfraDocument =
| HostMetricsDocument
| PodMetricsDocument
| DockerContainerMetricsDocument
| K8sContainerMetricsDocument
| AWSRdsMetricsDocument;
| AWSRdsMetricsDocument
| K8sNodeMetricsDocument;
export const infra = {
host,
@ -25,4 +27,5 @@ export const infra = {
dockerContainer,
k8sContainer,
awsRds,
k8sNode,
};

View file

@ -18,11 +18,13 @@ interface K8sContainerDocument extends Fields {
'container.name'?: string;
'container.image.name'?: string;
'container.runtime'?: string;
'host.name'?: string;
'host.name': string;
'host.hostname': string;
'cloud.provider'?: string;
'cloud.instance.id'?: string;
'cloud.image.id'?: string;
'event.dataset'?: string;
'agent.id': string;
}
export class K8sContainer extends Entity<K8sContainerDocument> {
@ -31,6 +33,7 @@ export class K8sContainer extends Entity<K8sContainerDocument> {
...this.fields,
'kubernetes.container.cpu.usage.limit.pct': 46,
'kubernetes.container.memory.usage.limit.pct': 30,
'kubernetes.pod.cpu.usage.limit.pct': 46,
});
}
}
@ -38,6 +41,7 @@ export class K8sContainer extends Entity<K8sContainerDocument> {
export interface K8sContainerMetricsDocument extends K8sContainerDocument {
'kubernetes.container.cpu.usage.limit.pct': number;
'kubernetes.container.memory.usage.limit.pct': number;
'kubernetes.pod.cpu.usage.limit.pct': number;
}
class K8sContainerMetrics extends Serializable<K8sContainerMetricsDocument> {}
@ -51,6 +55,8 @@ export function k8sContainer(id: string, uid: string, nodeName: string): K8sCont
'container.runtime': 'containerd',
'container.image.name': 'image-1',
'host.name': 'host-1',
'host.hostname': 'host-1',
'agent.id': 'synthtrace',
'cloud.instance.id': 'instance-1',
'cloud.image.id': 'image-1',
'cloud.provider': 'aws',

View file

@ -0,0 +1,58 @@
/*
* 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.
*/
/* eslint-disable max-classes-per-file */
import { Entity, Fields } from '../entity';
import { Serializable } from '../serializable';
interface K8sNodeDocument extends Fields {
'kubernetes.node.name': string;
'kubernetes.pod.uid'?: string;
'agent.id': string;
'host.hostname': string;
'host.name': string;
'metricset.name'?: string;
'event.dataset'?: string;
}
export class K8sNode extends Entity<K8sNodeDocument> {
metrics() {
return new K8sNodeMetrics({
...this.fields,
'kubernetes.node.cpu.allocatable.cores': 0.53,
'kubernetes.node.cpu.usage.nanocores': 0.32,
'kubernetes.node.memory.allocatable.bytes': 0.46,
'kubernetes.node.memory.usage.bytes': 0.86,
'kubernetes.node.fs.capacity.bytes': 100,
'kubernetes.node.fs.used.bytes': 100,
'kubernetes.node.pod.allocatable.total': 10,
});
}
}
export interface K8sNodeMetricsDocument extends K8sNodeDocument {
'kubernetes.node.cpu.allocatable.cores': number;
'kubernetes.node.cpu.usage.nanocores': number;
'kubernetes.node.memory.allocatable.bytes': number;
'kubernetes.node.memory.usage.bytes': number;
'kubernetes.node.fs.capacity.bytes': number;
'kubernetes.node.fs.used.bytes': number;
'kubernetes.node.pod.allocatable.total': number;
}
class K8sNodeMetrics extends Serializable<K8sNodeMetricsDocument> {}
export function k8sNode(name: string, podUid: string) {
return new K8sNode({
'kubernetes.node.name': name,
'kubernetes.pod.uid': podUid,
'agent.id': 'synthtrace',
'host.hostname': name,
'host.name': name,
'event.dataset': 'kubernetes.node',
});
}

View file

@ -12,6 +12,9 @@ import { Serializable } from '../serializable';
import { k8sContainer } from './k8s_container';
interface PodDocument extends Fields {
'agent.id': string;
'host.hostname': string;
'host.name': string;
'kubernetes.pod.uid': string;
'kubernetes.node.name': string;
'metricset.name'?: string;
@ -40,5 +43,8 @@ export function pod(uid: string, nodeName: string) {
return new Pod({
'kubernetes.pod.uid': uid,
'kubernetes.node.name': nodeName,
'agent.id': 'synthtrace',
'host.hostname': nodeName,
'host.name': nodeName,
});
}

View file

@ -22,7 +22,14 @@ export class InfraSynthtraceEsClient extends SynthtraceEsClient<InfraDocument> {
...options,
pipeline: infraPipeline(),
});
this.dataStreams = ['metrics-*', 'logs-*'];
this.dataStreams = [
'metrics-system*',
'metrics-kubernetes*',
'metrics-docker*',
'metrics-aws*',
'metricbeat-*',
'logs-*',
];
}
}
@ -60,7 +67,10 @@ function getRoutingTransform() {
document._index = 'metrics-system.filesystem-default';
} else if (metricset === 'diskio') {
document._index = 'metrics-system.diskio-default';
} else if (metricset === 'core') {
document._index = 'metrics-system.core-default';
} else if ('container.id' in document) {
document._index = 'metrics-docker.container-default';
document._index = 'metrics-kubernetes.container-default';
} else if ('kubernetes.pod.uid' in document) {
document._index = 'metrics-kubernetes.pod-default';

View file

@ -70,4 +70,27 @@ export class InfraSynthtraceKibanaClient {
this.logger.info(`Installed System package ${packageVersion}`);
}
async uninstallSystemPackage(packageVersion: string) {
this.logger.debug(`Uninstalling System package ${packageVersion}`);
const url = join(this.target, `/api/fleet/epm/packages/system/${packageVersion}`);
const response = await pRetry(() => {
return fetch(url, {
method: 'DELETE',
headers: kibanaHeaders(),
body: '{"force":true}',
});
});
const responseJson = await response.json();
if (!responseJson.items) {
throw new Error(
`Failed to uninstall System package version ${packageVersion}, received HTTP ${response.status} and message: ${responseJson.message} for url ${url}`
);
}
this.logger.info(`System package ${packageVersion} uninstalled`);
}
}

View file

@ -0,0 +1,17 @@
/*
* 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 { Client } from '@elastic/elasticsearch';
import { LogsSynthtraceEsClient, createLogger, LogLevel } from '@kbn/apm-synthtrace';
export async function getLogsSynthtraceEsClient(client: Client) {
return new LogsSynthtraceEsClient({
client,
logger: createLogger(LogLevel.info),
refreshAfterIndex: true,
});
}

View file

@ -56,6 +56,16 @@ export const HOSTS_VIEW_PATH = 'metrics/hosts';
export const DATE_PICKER_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS';
// synthtrace date constants
export const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z';
export const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z';
export const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:59 PM';
export const DATE_WITH_HOSTS_DATA_FROM = '2023-03-28T18:20:00.000Z';
export const DATE_WITH_HOSTS_DATA_TO = '2023-03-28T18:21:00.000Z';
export const DATE_WITH_HOSTS_DATA = '03/28/2023 6:20:59 PM';
export const DATE_WITH_POD_DATA_FROM = '2023-09-19T07:20:00.000Z';
export const DATE_WITH_POD_DATA_TO = '2023-09-19T07:21:00.000Z';
export const DATE_WITH_POD_DATA = '09/19/2023 7:20:59 AM';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { apm, timerange, infra } from '@kbn/apm-synthtrace-client';
import { apm, timerange, infra, generateShortId, log } from '@kbn/apm-synthtrace-client';
const SERVICE_PREFIX = 'service';
// generates traces, metrics for services
@ -69,3 +69,141 @@ export function generateDockerContainersData({
containers.flatMap((container) => container.metrics().timestamp(timestamp))
);
}
export function generateHostData({
from,
to,
hosts,
}: {
from: string;
to: string;
hosts: Array<{ hostName: string; cpuValue: number }>;
}) {
const range = timerange(from, to);
return range
.interval('30s')
.rate(1)
.generator((timestamp) =>
hosts.flatMap(({ hostName, cpuValue }) => [
infra.host(hostName).cpu({ cpuTotalValue: cpuValue }).timestamp(timestamp),
infra.host(hostName).memory().timestamp(timestamp),
infra.host(hostName).network().timestamp(timestamp),
infra.host(hostName).load().timestamp(timestamp),
infra.host(hostName).filesystem().timestamp(timestamp),
infra.host(hostName).diskio().timestamp(timestamp),
infra.host(hostName).core().timestamp(timestamp),
])
);
}
export function generateHostsWithK8sNodeData({ from, to }: { from: string; to: string }) {
const range = timerange(from, to);
// cpuValue is sent to the generator to simulate different 'system.cpu.total.norm.pct' metric
// that is the default metric in inventory and hosts view and host details page
const hosts = [
{
hostName: 'demo-stack-kubernetes-01',
cpuValue: 0.5,
},
];
return range
.interval('30s')
.rate(1)
.generator((timestamp) =>
hosts.flatMap(({ hostName, cpuValue }) => [
infra.host(hostName).cpu({ cpuTotalValue: cpuValue }).timestamp(timestamp),
infra.host(hostName).memory().timestamp(timestamp),
infra.host(hostName).network().timestamp(timestamp),
infra.host(hostName).load().timestamp(timestamp),
infra.host(hostName).filesystem().timestamp(timestamp),
infra.host(hostName).diskio().timestamp(timestamp),
infra.host(hostName).core().timestamp(timestamp),
infra.host(hostName).node('demo-stack-kubernetes-01').metrics().timestamp(timestamp),
infra.host(hostName).pod('pod-1').metrics().timestamp(timestamp),
])
);
}
export function generatePodsData({
from,
to,
count = 1,
}: {
from: string;
to: string;
count: number;
}) {
const range = timerange(from, to);
const pods = Array(count)
.fill(0)
.map((_, idx) => infra.pod(`pod-${idx}`, `node-name-${idx}`));
return range
.interval('30s')
.rate(1)
.generator((timestamp) =>
pods.flatMap((pod, idx) => [
pod.metrics().timestamp(timestamp),
pod.container(`container-${idx}`).metrics().timestamp(timestamp),
])
);
}
export function generateLogsDataForHosts({
from,
to,
hosts,
}: {
from: string;
to: string;
hosts: Array<{ hostName: string }>;
}) {
const range = timerange(from, to);
// Logs Data logic
const MESSAGE_LOG_LEVELS = [
{ message: 'A simple log', level: 'info' },
{ message: 'Yet another debug log', level: 'debug' },
{ message: 'Error with certificate: "ca_trusted_fingerprint"', level: 'error' },
];
const CLOUD_PROVIDERS = ['gcp', 'aws', 'azure'];
const CLOUD_REGION = ['eu-central-1', 'us-east-1', 'area-51'];
const CLUSTER = [
{ clusterId: generateShortId(), clusterName: 'synth-cluster-1' },
{ clusterId: generateShortId(), clusterName: 'synth-cluster-2' },
{ clusterId: generateShortId(), clusterName: 'synth-cluster-3' },
];
return range
.interval('30s')
.rate(1)
.generator((timestamp) =>
hosts.flatMap(({ hostName }) => {
const index = Math.floor(Math.random() * MESSAGE_LOG_LEVELS.length);
return log
.create()
.message(MESSAGE_LOG_LEVELS[index].message)
.logLevel(MESSAGE_LOG_LEVELS[index].level)
.hostName(hostName)
.defaults({
'trace.id': generateShortId(),
'agent.name': 'synth-agent',
'orchestrator.cluster.name': CLUSTER[index].clusterName,
'orchestrator.cluster.id': CLUSTER[index].clusterId,
'orchestrator.resource.id': generateShortId(),
'cloud.provider': CLOUD_PROVIDERS[index],
'cloud.region': CLOUD_REGION[index],
'cloud.availability_zone': `${CLOUD_REGION[index]}a`,
'cloud.project.id': generateShortId(),
'cloud.instance.id': generateShortId(),
'log.file.path': `/logs/${generateShortId()}/error.txt`,
})
.timestamp(timestamp);
})
);
}

View file

@ -8,25 +8,51 @@
import expect from '@kbn/expect';
import { KUBERNETES_TOUR_STORAGE_KEY } from '@kbn/infra-plugin/public/pages/metrics/inventory_view/components/kubernetes_tour';
import { InfraSynthtraceEsClient } from '@kbn/apm-synthtrace';
import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common';
import { FtrProviderContext } from '../../ftr_provider_context';
import { DATES, INVENTORY_PATH } from './constants';
import { generateDockerContainersData } from './helpers';
import {
INVENTORY_PATH,
DATE_WITH_DOCKER_DATA_FROM,
DATE_WITH_DOCKER_DATA_TO,
DATE_WITH_DOCKER_DATA,
DATE_WITH_HOSTS_DATA_FROM,
DATE_WITH_HOSTS_DATA_TO,
DATE_WITH_HOSTS_DATA,
DATE_WITH_POD_DATA,
DATE_WITH_POD_DATA_FROM,
DATE_WITH_POD_DATA_TO,
} from './constants';
import { generateDockerContainersData, generateHostData, generatePodsData } from './helpers';
import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client';
const DATE_WITH_DATA = DATES.metricsAndLogs.hosts.withData;
const DATE_WITHOUT_DATA = DATES.metricsAndLogs.hosts.withoutData;
const DATE_WITH_POD_WITH_DATA = DATES.metricsAndLogs.pods.withData;
const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z';
const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z';
const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:00 PM';
const DATE_WITHOUT_DATA = '10/09/2018 10:00:00 PM';
const HOSTS = [
{
hostName: 'host-1',
cpuValue: 0.5,
},
{
hostName: 'host-2',
cpuValue: 0.7,
},
{
hostName: 'host-3',
cpuValue: 0.9,
},
{
hostName: 'host-4',
cpuValue: 0.3,
},
{
hostName: 'host-5',
cpuValue: 0.1,
},
];
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
const browser = getService('browser');
const retry = getService('retry');
const esClient = getService('es');
const infraSynthtraceKibanaClient = getService('infraSynthtraceKibanaClient');
const pageObjects = getPageObjects([
'common',
'header',
@ -46,30 +72,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
return !!currentUrl.match(path);
});
const setInfrastructureContainerAssetViewUiSetting = async (value: boolean = true) => {
await kibanaServer.uiSettings.update({ [enableInfrastructureContainerAssetView]: value });
await browser.refresh();
await pageObjects.header.waitUntilLoadingHasFinished();
};
describe('Home page', function () {
this.tags('includeFirefox');
before(async () => {
await kibanaServer.savedObjects.cleanStandardList();
});
describe('without metrics present', () => {
before(
async () =>
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')
);
it('renders an empty data prompt and redirects to the onboarding page', async () => {
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.noDataPromptExists();
await pageObjects.infraHome.noDataPromptAddDataClick();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const currentUrl = await browser.getCurrentUrl();
const parsedUrl = new URL(currentUrl);
const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`;
@ -94,16 +110,33 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
describe('with metrics present', () => {
let synthEsClient: InfraSynthtraceEsClient;
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/pods_only');
synthEsClient = await getInfraSynthtraceEsClient(esClient);
await synthEsClient.clean();
await synthEsClient.index([
generateHostData({
from: DATE_WITH_HOSTS_DATA_FROM,
to: DATE_WITH_HOSTS_DATA_TO,
hosts: HOSTS,
}),
generateDockerContainersData({
from: DATE_WITH_DOCKER_DATA_FROM,
to: DATE_WITH_DOCKER_DATA_TO,
count: 5,
}),
generatePodsData({
from: DATE_WITH_POD_DATA_FROM,
to: DATE_WITH_POD_DATA_TO,
count: 1,
}),
]);
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.waitForLoading();
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/pods_only');
await browser.removeLocalStorageItem(KUBERNETES_TOUR_STORAGE_KEY);
await synthEsClient.clean();
});
it('renders the correct page title', async () => {
@ -137,7 +170,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.ensureKubernetesTourIsClosed();
});
});
@ -146,22 +179,23 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.infraHome.goToTime(DATE_WITHOUT_DATA);
await pageObjects.infraHome.getNoMetricsDataPrompt();
});
it('renders the waffle map and tooltips for dates with data', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
// await pageObjects.infraHome.getWaffleMapTooltips(); see https://github.com/elastic/kibana/issues/137903
});
describe('Asset Details flyout for a host', () => {
before(async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await pageObjects.infraHome.inputAddHostNameFilter('demo-stack-nginx-01');
await pageObjects.infraHome.inputAddHostNameFilter('host-1');
await pageObjects.infraHome.clickOnNode();
});
after(async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.clickCloseFlyoutButton();
});
});
@ -172,10 +206,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
[
{ metric: 'cpuUsage', value: 'N/A' },
{ metric: 'normalizedLoad1m', value: '1.4%' },
{ metric: 'memoryUsage', value: '18.0%' },
{ metric: 'diskUsage', value: '35.0%' },
{ metric: 'cpuUsage', value: '50.0%' },
{ metric: 'normalizedLoad1m', value: '18.8%' },
{ metric: 'memoryUsage', value: '35.0%' },
{ metric: 'diskUsage', value: '1,223.0%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.tryForTime(3 * 1000, async () => {
@ -237,31 +271,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
describe('Asset Details flyout for a container', () => {
let synthEsClient: InfraSynthtraceEsClient;
before(async () => {
await setInfrastructureContainerAssetViewUiSetting(true);
const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion();
await infraSynthtraceKibanaClient.installSystemPackage(version);
synthEsClient = await getInfraSynthtraceEsClient(esClient);
await synthEsClient.index(
generateDockerContainersData({
from: DATE_WITH_DOCKER_DATA_FROM,
to: DATE_WITH_DOCKER_DATA_TO,
count: 5,
})
);
await pageObjects.infraHome.clickDismissKubernetesTourButton();
await pageObjects.infraHome.goToContainer();
await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA);
await pageObjects.infraHome.clickOnFirstNode();
});
after(async () => {
await setInfrastructureContainerAssetViewUiSetting(false);
return await synthEsClient.clean();
});
describe('Overview Tab', () => {
before(async () => {
await pageObjects.assetDetails.clickOverviewTab();
@ -272,7 +287,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
{ metric: 'memoryUsage', value: '20.0%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.tryForTime(3 * 1000, async () => {
await retry.tryForTime(5000, async () => {
const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(
metric
);
@ -327,7 +342,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
after(async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.closeFlyout();
});
});
@ -339,89 +354,85 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
it('shows query suggestions', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.clickQueryBar();
await pageObjects.infraHome.inputQueryData();
await pageObjects.infraHome.ensureSuggestionsPanelVisible();
await pageObjects.infraHome.clearSearchTerm();
});
it.skip('sort nodes by descending value', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
it('sort nodes by descending value', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await pageObjects.infraHome.sortNodesBy('value');
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
{ name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
{ name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' },
{ name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' },
{ name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' },
{ name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' },
{ name: 'host-3', value: 90, color: '#6092c0' },
{ name: 'host-2', value: 70, color: '#82a7cd' },
{ name: 'host-1', value: 50, color: '#a2bcd9' },
{ name: 'host-4', value: 30, color: '#d1ddec' },
{ name: 'host-5', value: 10, color: '#f0f4f9' },
]);
});
});
it.skip('sort nodes by ascending value', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
it('sort nodes by ascending value', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await pageObjects.infraHome.sortNodesBy('value');
await pageObjects.infraHome.toggleReverseSort();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
{ name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' },
{ name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' },
{ name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' },
{ name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' },
{ name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
{ name: 'host-5', value: 10, color: '#f0f4f9' },
{ name: 'host-4', value: 30, color: '#d1ddec' },
{ name: 'host-1', value: 50, color: '#a2bcd9' },
{ name: 'host-2', value: 70, color: '#82a7cd' },
{ name: 'host-3', value: 90, color: '#6092c0' },
]);
});
});
it('group nodes by custom field', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const groups = await pageObjects.infraHome.groupByCustomField('host.os.platform');
expect(groups).to.eql(['ubuntu']);
});
});
it.skip('filter nodes by search term', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
it('filter nodes by search term', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await pageObjects.infraHome.enterSearchTerm('host.name: "demo-stack-apache-01"');
await retry.try(async () => {
await pageObjects.infraHome.enterSearchTerm('host.name: "host-1"');
await retry.tryForTime(5000, async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
{ name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
]);
expect(nodesWithValue).to.eql([{ name: 'host-1', value: 50, color: '#6092c0' }]);
});
await pageObjects.infraHome.clearSearchTerm();
});
it.skip('change color palette', async () => {
it('change color palette', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.openLegendControls();
await pageObjects.infraHome.changePalette('temperature');
await pageObjects.infraHome.applyLegendControls();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
{ name: 'demo-stack-client-01', value: 0.6, color: '#6092c0' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#b5c9df' },
{ name: 'demo-stack-redis-01', value: 1, color: '#f1d9b9' },
{ name: 'demo-stack-nginx-01', value: 1.1, color: '#eec096' },
{ name: 'demo-stack-mysql-01', value: 1.2, color: '#eba47a' },
{ name: 'demo-stack-apache-01', value: 1.4, color: '#e7664c' },
{ name: 'host-5', value: 10, color: '#6092c0' },
{ name: 'host-4', value: 30, color: '#9ab6d5' },
{ name: 'host-1', value: 50, color: '#f1d9b9' },
{ name: 'host-2', value: 70, color: '#eba47a' },
{ name: 'host-3', value: 90, color: '#e7664c' },
]);
});
});
it('toggle the timeline', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.getWaffleMap();
await pageObjects.infraHome.openTimeline();
await pageObjects.infraHome.closeTimeline();
@ -438,62 +449,47 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
it('Should redirect to Host Details page', async () => {
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
await pageObjects.infraHome.goToHost();
await pageObjects.infraHome.clickOnFirstNode();
await pageObjects.infraHome.clickOnNodeDetailsFlyoutOpenAsPage();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain(
'demo-stack-redis-01 - Inventory - Infrastructure - Observability - Elastic'
'host-5 - Inventory - Infrastructure - Observability - Elastic'
);
});
await returnTo(INVENTORY_PATH);
});
it('Should redirect to Pod Details page', async () => {
await pageObjects.infraHome.goToPods();
await pageObjects.infraHome.goToTime(DATE_WITH_POD_WITH_DATA);
await pageObjects.infraHome.clickOnFirstNode();
await pageObjects.infraHome.clickOnGoToNodeDetails();
await retry.try(async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain(
'pod-0 - Inventory - Infrastructure - Observability - Elastic'
);
});
await returnTo(INVENTORY_PATH);
});
describe('Redirect to Container Details page', () => {
let synthEsClient: InfraSynthtraceEsClient;
before(async () => {
const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion();
await infraSynthtraceKibanaClient.installSystemPackage(version);
synthEsClient = await getInfraSynthtraceEsClient(esClient);
await synthEsClient.index(
generateDockerContainersData({
from: DATE_WITH_DOCKER_DATA_FROM,
to: DATE_WITH_DOCKER_DATA_TO,
count: 5,
})
);
});
after(async () => {
return await synthEsClient.clean();
});
it('Should redirect to Container Details page', async () => {
await pageObjects.infraHome.goToContainer();
await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA);
describe('Redirect to Pod Details page', () => {
it('should redirect to Pod Details page', async () => {
await pageObjects.infraHome.goToPods();
await pageObjects.infraHome.goToTime(DATE_WITH_POD_DATA);
await pageObjects.infraHome.clickOnFirstNode();
await pageObjects.infraHome.clickOnGoToNodeDetails();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain(
'pod-0 - Inventory - Infrastructure - Observability - Elastic'
);
});
await returnTo(INVENTORY_PATH);
});
});
describe('Redirect to Container Details page', () => {
it('should redirect to Container Details page', async () => {
await pageObjects.infraHome.goToContainer();
await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA);
await pageObjects.infraHome.clickOnFirstNode();
await pageObjects.infraHome.clickOnNodeDetailsFlyoutOpenAsPage();
await retry.tryForTime(5000, async () => {
const documentTitle = await browser.getTitle();
expect(documentTitle).to.contain(
'container-id-4 - Inventory - Infrastructure - Observability - Elastic'
@ -534,105 +530,96 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
// close
await pageObjects.infraHome.clickCustomMetricDropdown();
});
});
describe('alerts flyouts', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.waitForLoading();
await pageObjects.infraHome.goToTime(DATE_WITH_DATA);
});
after(
async () =>
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')
);
describe('alerts flyouts', () => {
before(async () => {
await pageObjects.common.navigateToApp('infraOps');
await pageObjects.infraHome.waitForLoading();
await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA);
});
it('should open and close inventory alert flyout', async () => {
await pageObjects.infraHome.openInventoryAlertFlyout();
await pageObjects.infraHome.closeAlertFlyout();
});
it('should open and close inventory alert flyout', async () => {
await pageObjects.infraHome.openInventoryAlertFlyout();
await pageObjects.infraHome.closeAlertFlyout();
});
it('should open and close metrics threshold alert flyout', async () => {
await pageObjects.infraHome.openMetricsThresholdAlertFlyout();
await pageObjects.infraHome.closeAlertFlyout();
});
it('should open and close metrics threshold alert flyout', async () => {
await pageObjects.infraHome.openMetricsThresholdAlertFlyout();
await pageObjects.infraHome.closeAlertFlyout();
});
it('should open and close alerts popover using button', async () => {
await pageObjects.infraHome.clickAlertsAndRules();
await pageObjects.infraHome.ensurePopoverOpened();
await pageObjects.infraHome.clickAlertsAndRules();
await retry.try(async () => {
await pageObjects.infraHome.ensurePopoverClosed();
it('should open and close alerts popover using button', async () => {
await pageObjects.infraHome.clickAlertsAndRules();
await pageObjects.infraHome.ensurePopoverOpened();
await pageObjects.infraHome.clickAlertsAndRules();
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.ensurePopoverClosed();
});
});
it('should not have an option to create custom threshold alert', async () => {
await pageObjects.infraHome.clickAlertsAndRules();
await pageObjects.infraHome.ensurePopoverOpened();
await pageObjects.infraHome.ensureCustomThresholdAlertMenuItemIsMissing();
await pageObjects.infraHome.clickAlertsAndRules();
});
});
describe('Saved Views', () => {
before(async () => {
await pageObjects.infraHome.goToMetricExplorer();
});
it('should not have an option to create custom threshold alert', async () => {
await pageObjects.infraHome.clickAlertsAndRules();
await pageObjects.infraHome.ensurePopoverOpened();
await pageObjects.infraHome.ensureCustomThresholdAlertMenuItemIsMissing();
await pageObjects.infraHome.clickAlertsAndRules();
});
});
beforeEach(async () => {
await pageObjects.infraSavedViews.clickSavedViewsButton();
});
afterEach(async () => {
await pageObjects.infraSavedViews.closeSavedViewsPopover();
});
describe('Saved Views', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await pageObjects.infraHome.goToMetricExplorer();
});
it('should render a button with the view name', async () => {
await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view');
});
after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'));
it('should open/close the views popover menu on button click', async () => {
await pageObjects.infraSavedViews.clickSavedViewsButton();
await testSubjects.existOrFail('savedViews-popover');
await pageObjects.infraSavedViews.closeSavedViewsPopover();
});
beforeEach(async () => {
await pageObjects.infraSavedViews.clickSavedViewsButton();
});
afterEach(async () => {
await pageObjects.infraSavedViews.closeSavedViewsPopover();
});
it('should create a new saved view and load it', async () => {
await pageObjects.infraSavedViews.createView('view1');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view1');
});
it('should render a button with the view name', async () => {
await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view');
});
it('should load a clicked view from the manage views section', async () => {
const views = await pageObjects.infraSavedViews.getManageViewsEntries();
await views[0].click();
await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view');
});
it('should open/close the views popover menu on button click', async () => {
await pageObjects.infraSavedViews.clickSavedViewsButton();
await testSubjects.existOrFail('savedViews-popover');
await pageObjects.infraSavedViews.closeSavedViewsPopover();
});
it('should update the current saved view and load it', async () => {
let views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(2);
await pageObjects.infraSavedViews.pressEsc();
it('should create a new saved view and load it', async () => {
await pageObjects.infraSavedViews.createView('view1');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view1');
});
await pageObjects.infraSavedViews.clickSavedViewsButton();
await pageObjects.infraSavedViews.createView('view2');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view2');
it('should load a clicked view from the manage views section', async () => {
const views = await pageObjects.infraSavedViews.getManageViewsEntries();
await views[0].click();
await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view');
});
await pageObjects.infraSavedViews.clickSavedViewsButton();
views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(3);
await pageObjects.infraSavedViews.pressEsc();
it('should update the current saved view and load it', async () => {
let views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(2);
await pageObjects.infraSavedViews.pressEsc();
await pageObjects.infraSavedViews.clickSavedViewsButton();
await pageObjects.infraSavedViews.updateView('view3');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view3');
await pageObjects.infraSavedViews.clickSavedViewsButton();
await pageObjects.infraSavedViews.createView('view2');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view2');
await pageObjects.infraSavedViews.clickSavedViewsButton();
views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(3);
await pageObjects.infraSavedViews.pressEsc();
await pageObjects.infraSavedViews.clickSavedViewsButton();
await pageObjects.infraSavedViews.updateView('view3');
await pageObjects.infraSavedViews.ensureViewIsLoaded('view3');
await pageObjects.infraSavedViews.clickSavedViewsButton();
views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(3);
await pageObjects.infraSavedViews.pressEsc();
await pageObjects.infraSavedViews.clickSavedViewsButton();
views = await pageObjects.infraSavedViews.getManageViewsEntries();
expect(views.length).to.equal(3);
await pageObjects.infraSavedViews.pressEsc();
});
});
});
});

View file

@ -7,11 +7,12 @@
import moment from 'moment';
import expect from '@kbn/expect';
import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
import {
enableInfrastructureAssetCustomDashboards,
enableInfrastructureHostsView,
} from '@kbn/observability-plugin/common';
ApmSynthtraceEsClient,
InfraSynthtraceEsClient,
LogsSynthtraceEsClient,
} from '@kbn/apm-synthtrace';
import { enableInfrastructureAssetCustomDashboards } from '@kbn/observability-plugin/common';
import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils';
import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services';
import { FtrProviderContext } from '../../ftr_provider_context';
@ -20,14 +21,24 @@ import {
HOSTS_LINK_LOCAL_STORAGE_KEY,
HOSTS_VIEW_PATH,
DATE_PICKER_FORMAT,
DATE_WITH_HOSTS_DATA_FROM,
DATE_WITH_HOSTS_DATA_TO,
} from './constants';
import { generateAddServicesToExistingHost } from './helpers';
import {
generateAddServicesToExistingHost,
generateHostData,
generateLogsDataForHosts,
} from './helpers';
import { getApmSynthtraceEsClient } from '../../../common/utils/synthtrace/apm_es_client';
import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client';
import { getLogsSynthtraceEsClient } from '../../../common/utils/synthtrace/logs_es_client';
const START_DATE = moment.utc(DATES.metricsAndLogs.hosts.min);
const END_DATE = moment.utc(DATES.metricsAndLogs.hosts.max);
const START_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataStartDate);
const END_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataEndDate);
// synthtrace data dates
const START_SYNTHTRACE_DATE = moment.utc(DATE_WITH_HOSTS_DATA_FROM);
const END_SYNTHTRACE_DATE = moment.utc(DATE_WITH_HOSTS_DATA_TO);
const tableEntries = [
{
@ -98,6 +109,96 @@ const tableEntries = [
},
];
const synthtraceHostsTableEntries = [
{
title: 'host-1',
cpuUsage: '90%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
{
title: 'host-2',
cpuUsage: '70%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
{
title: 'host-3',
cpuUsage: '50%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
{
title: 'host-4',
cpuUsage: '40%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
{
title: 'host-5',
cpuUsage: '30%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
{
title: 'host-6',
cpuUsage: '10%',
normalizedLoad: '18.8%',
memoryUsage: '35%',
memoryFree: '44.7 GB',
diskSpaceUsage: '1,223%',
rx: '1.5 Mbit/s',
tx: '1.5 Mbit/s',
},
];
const SYNTH_HOSTS = [
{
hostName: 'host-1',
cpuValue: 0.9,
},
{
hostName: 'host-2',
cpuValue: 0.7,
},
{
hostName: 'host-3',
cpuValue: 0.5,
},
{
hostName: 'host-4',
cpuValue: 0.4,
},
{
hostName: 'host-5',
cpuValue: 0.3,
},
{
hostName: 'host-6',
cpuValue: 0.1,
},
];
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const browser = getService('browser');
const security = getService('security');
@ -126,7 +227,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const loginWithReadOnlyUserAndNavigateToHostsFlyout = async () => {
await security.role.create('global_hosts_read_privileges_role', {
elasticsearch: {
indices: [{ names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] }],
indices: [
{ names: ['metrics-*'], privileges: ['read', 'view_index_metadata'] },
{ names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] },
],
},
kibana: [
{
@ -158,8 +262,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.timePicker.setAbsoluteRange(
START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT),
END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT)
START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT),
END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
@ -175,9 +279,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
]);
};
const setHostViewEnabled = (value: boolean = true) =>
kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value });
const setCustomDashboardsEnabled = (value: boolean = true) =>
kibanaServer.uiSettings.update({ [enableInfrastructureAssetCustomDashboards]: value });
@ -198,9 +299,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
);
describe('Hosts View', function () {
let synthEsInfraClient: InfraSynthtraceEsClient;
let syntEsLogsClient: LogsSynthtraceEsClient;
describe('#Onboarding', function () {
before(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
synthEsInfraClient = await getInfraSynthtraceEsClient(esClient);
await synthEsInfraClient.clean();
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
});
@ -208,7 +313,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.infraHome.noDataPromptExists();
await pageObjects.infraHome.noDataPromptAddDataClick();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const currentUrl = await browser.getCurrentUrl();
const parsedUrl = new URL(currentUrl);
const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`;
@ -221,6 +326,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
describe('#With data', function () {
let synthtraceApmClient: ApmSynthtraceEsClient;
before(async () => {
synthEsInfraClient = await getInfraSynthtraceEsClient(esClient);
syntEsLogsClient = await getLogsSynthtraceEsClient(esClient);
const version = (await apmSynthtraceKibanaClient.installApmPackage()).version;
synthtraceApmClient = await getApmSynthtraceEsClient({
client: esClient,
@ -228,19 +335,30 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
const services = generateAddServicesToExistingHost({
from: DATES.metricsAndLogs.hosts.processesDataStartDate,
to: DATES.metricsAndLogs.hosts.processesDataEndDate,
hostName: 'Jennys-MBP.fritz.box',
from: DATE_WITH_HOSTS_DATA_FROM,
to: DATE_WITH_HOSTS_DATA_TO,
hostName: 'host-1',
servicesPerHost: 3,
});
const logs = generateLogsDataForHosts({
from: DATE_WITH_HOSTS_DATA_FROM,
to: DATE_WITH_HOSTS_DATA_TO,
hosts: SYNTH_HOSTS,
});
await browser.setWindowSize(1600, 1200);
return Promise.all([
synthtraceApmClient.index(services),
esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'),
esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'),
synthEsInfraClient.index(
generateHostData({
from: DATE_WITH_HOSTS_DATA_FROM,
to: DATE_WITH_HOSTS_DATA_TO,
hosts: SYNTH_HOSTS,
})
),
syntEsLogsClient.index(logs),
]);
});
@ -248,9 +366,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
return Promise.all([
apmSynthtraceKibanaClient.uninstallApmPackage(),
synthtraceApmClient.clean(),
esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'),
esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'),
synthEsInfraClient.clean(),
browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY),
]);
});
@ -269,7 +385,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
describe('#Single Host Flyout', () => {
before(async () => {
await setHostViewEnabled(true);
await setCustomDashboardsEnabled(true);
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
@ -278,8 +393,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
describe('Tabs', () => {
before(async () => {
await pageObjects.timePicker.setAbsoluteRange(
START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT),
END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT)
START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT),
END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
@ -288,7 +403,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
after(async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.clickCloseFlyoutButton();
});
});
@ -299,13 +414,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
[
{ metric: 'cpuUsage', value: '13.9%' },
{ metric: 'cpuUsage', value: '48.3%' },
{ metric: 'normalizedLoad1m', value: '18.8%' },
{ metric: 'memoryUsage', value: '94.9%' },
{ metric: 'diskUsage', value: 'N/A' },
{ metric: 'memoryUsage', value: '35.0%' },
{ metric: 'diskUsage', value: '1,223.0%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(
metric
);
@ -374,7 +489,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.header.waitUntilLoadingHasFinished();
const addedFilter = await pageObjects.assetDetails.getMetadataAppliedFilter();
expect(addedFilter).to.contain('host.architecture: arm64');
expect(addedFilter).to.contain('host.name: host-1');
const removeFilterExists =
await pageObjects.assetDetails.metadataRemoveFilterExists();
expect(removeFilterExists).to.be(true);
@ -403,8 +518,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.assetDetails.clickProcessesTab();
});
it('should show processes table', async () => {
await pageObjects.assetDetails.processesTableExists();
it('should show processes content', async () => {
await pageObjects.assetDetails.processesContentExist();
});
});
@ -432,10 +547,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
it('should navigate to Host Details page after click', async () => {
await pageObjects.assetDetails.clickOpenAsPageLink();
const dateRange = await pageObjects.timePicker.getTimeConfigAsAbsoluteTimes();
expect(dateRange.start).to.equal(
START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT)
);
expect(dateRange.end).to.equal(END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT));
expect(dateRange.start).to.equal(START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT));
expect(dateRange.end).to.equal(END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT));
await returnTo(HOSTS_VIEW_PATH);
});
@ -443,14 +556,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
describe('#Page Content', () => {
describe('#Page Content without alerts', () => {
before(async () => {
await setHostViewEnabled(true);
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(DATE_PICKER_FORMAT),
END_DATE.format(DATE_PICKER_FORMAT)
START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT),
END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
@ -479,7 +591,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
it('should render the computed metrics for each host entry', async () => {
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
expect(hostRowData).to.eql(tableEntries[i]);
expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]);
}
});
@ -488,8 +600,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.infraHostsView.selectedHostsButtonExist();
expect(selectHostsButtonExistsOnLoad).to.be(false);
await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-client-01', '-');
await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-apache-01', '-');
await pageObjects.infraHostsView.clickHostCheckbox('host-1', 'Linux');
await pageObjects.infraHostsView.clickHostCheckbox('host-2', 'Linux');
const selectHostsButtonExistsOnSelection =
await pageObjects.infraHostsView.selectedHostsButtonExist();
@ -503,7 +615,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(hostRowsAfterFilter.length).to.equal(2);
const deleteFilterButton = await find.byCssSelector(
`[title="Delete host.name: demo-stack-client-01 OR host.name: demo-stack-apache-01"]`
`[title="Delete host.name: host-1 OR host.name: host-2"]`
);
await deleteFilterButton.click();
await pageObjects.header.waitUntilLoadingHasFinished();
@ -518,16 +630,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(DATE_PICKER_FORMAT),
END_DATE.format(DATE_PICKER_FORMAT)
START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT),
END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
});
it('should maintain the selected date range when navigating to the individual host details', async () => {
const start = START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT);
const end = END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT);
const start = START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT);
const end = END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT);
await pageObjects.timePicker.setAbsoluteRange(start, end);
@ -549,13 +661,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
describe('KPIs', () => {
[
{ metric: 'hostsCount', value: '6' },
{ metric: 'cpuUsage', value: 'N/A' },
{ metric: 'normalizedLoad1m', value: '0.3%' },
{ metric: 'memoryUsage', value: '16.8%' },
{ metric: 'diskUsage', value: '35.7%' },
{ metric: 'cpuUsage', value: '48.3%' },
{ metric: 'normalizedLoad1m', value: '18.8%' },
{ metric: 'memoryUsage', value: '35.0%' },
{ metric: 'diskUsage', value: '1,223.0%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const tileValue =
metric === 'hostsCount'
? await pageObjects.infraHostsView.getKPITileValue(metric)
@ -583,7 +695,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
it('should have an option to open the chart in lens', async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHostsView.clickAndValidateMetricChartActionOptions();
await browser.pressKeys(browser.keys.ESCAPE);
});
@ -605,7 +717,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
it('should load the Logs tab with the right columns', async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const columnLabels = await pageObjects.infraHostsView.getLogsTableColumnHeaders();
expect(columnLabels).to.eql(['Timestamp', 'host.name', 'Message']);
@ -613,6 +725,115 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
describe('Pagination and Sorting', () => {
before(async () => {
await browser.scrollTop();
});
after(async () => {
await browser.scrollTop();
});
beforeEach(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHostsView.changePageSize(5);
});
});
it('should show 5 rows on the first page', async () => {
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]);
}
});
it('should paginate to the last page', async () => {
await pageObjects.infraHostsView.paginateTo(2);
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
expect(hostRows.length).to.equal(1);
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostRowData).to.eql(synthtraceHostsTableEntries[5]);
});
it('should show all hosts on the same page', async () => {
await pageObjects.infraHostsView.changePageSize(10);
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]);
}
});
it('should sort by a numeric field asc', async () => {
await pageObjects.infraHostsView.sortByCpuUsage();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[5]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[0]);
});
it('should sort by a numeric field desc', async () => {
await pageObjects.infraHostsView.sortByCpuUsage();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[0]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[5]);
});
it('should sort by text field asc', async () => {
await pageObjects.infraHostsView.sortByTitle();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[0]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[5]);
});
it('should sort by text field desc', async () => {
await pageObjects.infraHostsView.sortByTitle();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[5]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[0]);
});
});
});
describe('#Page Content with alerts', () => {
before(async () => {
return Promise.all([
esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'),
esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
]);
});
after(async () => {
return Promise.all([
esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'),
esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
]);
});
describe('Alerts Tab', () => {
const ACTIVE_ALERTS = 6;
const RECOVERED_ALERTS = 4;
@ -620,6 +841,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const COLUMNS = 11;
before(async () => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(DATE_PICKER_FORMAT),
END_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
await browser.scrollTop();
await pageObjects.infraHostsView.visitAlertTab();
});
@ -641,7 +870,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
describe('#FilterButtonGroup', () => {
it('can be filtered to only show "all" alerts using the filter button', async () => {
await pageObjects.infraHostsView.setAlertStatusFilter();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(ALL_ALERTS);
});
@ -649,7 +878,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
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 () => {
await retry.tryForTime(5000, async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(ACTIVE_ALERTS);
});
@ -657,7 +886,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
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 () => {
await retry.tryForTime(5000, async () => {
const tableRows = await observability.alerts.common.getTableCellsInRows();
expect(tableRows.length).to.be(RECOVERED_ALERTS);
});
@ -671,7 +900,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
it('should renders the correct number of cells', async () => {
await pageObjects.infraHostsView.setAlertStatusFilter();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(ALL_ALERTS * COLUMNS);
});
@ -685,6 +914,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const query = filtererEntries.map((entry) => `host.name :"${entry.title}"`).join(' or ');
before(async () => {
await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH);
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.timePicker.setAbsoluteRange(
START_DATE.format(DATE_PICKER_FORMAT),
END_DATE.format(DATE_PICKER_FORMAT)
);
await waitForPageToLoad();
await browser.scrollTop();
await pageObjects.infraHostsView.submitQuery(query);
await await waitForPageToLoad();
@ -701,7 +938,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(hostRows.length).to.equal(3);
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
const hostRowData = await pageObjects.infraHostsView.getHostsRowDataWithAlerts(
hostRows[i]
);
expect(hostRowData).to.eql(filtererEntries[i]);
}
});
@ -715,7 +954,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
{ metric: 'memoryUsage', value: '17.5%' },
{ metric: 'diskUsage', value: '35.7%' },
].map(async ({ metric, value }) => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const tileValue =
metric === 'hostsCount'
? await pageObjects.infraHostsView.getKPITileValue(metric)
@ -741,7 +980,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.infraHostsView.visitAlertTab();
await pageObjects.infraHostsView.setAlertStatusFilter();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(ALL_ALERTS * COLUMNS);
});
@ -757,104 +996,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await waitForPageToLoad();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await testSubjects.exists('hostsViewTableNoData');
});
});
});
describe('Pagination and Sorting', () => {
before(async () => {
await browser.scrollTop();
});
after(async () => {
await browser.scrollTop();
});
beforeEach(async () => {
await retry.try(async () => {
await pageObjects.infraHostsView.changePageSize(5);
});
});
it('should show 5 rows on the first page', async () => {
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
expect(hostRowData).to.eql(tableEntries[i]);
}
});
it('should paginate to the last page', async () => {
await pageObjects.infraHostsView.paginateTo(2);
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
expect(hostRows.length).to.equal(1);
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostRowData).to.eql(tableEntries[5]);
});
it('should show all hosts on the same page', async () => {
await pageObjects.infraHostsView.changePageSize(10);
const hostRows = await pageObjects.infraHostsView.getHostsTableData();
for (let i = 0; i < hostRows.length; i++) {
const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]);
expect(hostRowData).to.eql(tableEntries[i]);
}
});
it('should sort by a numeric field asc', async () => {
await pageObjects.infraHostsView.sortByMemoryUsage();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(tableEntries[3]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(tableEntries[0]);
});
it('should sort by a numeric field desc', async () => {
await pageObjects.infraHostsView.sortByMemoryUsage();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(tableEntries[0]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(tableEntries[3]);
});
it('should sort by text field asc', async () => {
await pageObjects.infraHostsView.sortByTitle();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(tableEntries[0]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(tableEntries[2]);
});
it('should sort by text field desc', async () => {
await pageObjects.infraHostsView.sortByTitle();
let hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataFirtPage).to.eql(tableEntries[2]);
await pageObjects.infraHostsView.paginateTo(2);
hostRows = await pageObjects.infraHostsView.getHostsTableData();
const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]);
expect(hostDataLastPage).to.eql(tableEntries[0]);
});
});
});
describe('#Permissions: Read Only User - Single Host Flyout', () => {
@ -866,7 +1012,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
after(async () => {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await pageObjects.infraHome.clickCloseFlyoutButton();
});
await logoutAndDeleteReadOnlyUser();
@ -875,7 +1021,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
it('should render dashboards tab splash screen with disabled option to add dashboard', async () => {
await pageObjects.assetDetails.addDashboardExists();
const elementToHover = await pageObjects.assetDetails.getAddDashboardButton();
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await elementToHover.moveMouseTo();
await testSubjects.existOrFail('infraCannotAddDashboardTooltip');
});

File diff suppressed because it is too large Load diff

View file

@ -202,8 +202,8 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
async getMetadataAppliedFilter() {
const filter = await testSubjects.find(
`filter-badge-${stringHash(
'host.architecture: arm64'
)} filter filter-enabled filter-key-host.architecture filter-value-arm64 filter-unpinned filter-id-0`
'host.name: host-1'
)} filter filter-enabled filter-key-host.name filter-value-host-1 filter-unpinned filter-id-0`
);
return filter.getVisibleText();
},
@ -263,6 +263,10 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
return processesListElements[index].findByCssSelector('dt');
},
async processesContentExist() {
return testSubjects.existOrFail('infraAssetDetailsProcessesTabContent');
},
async getProcessesTabContentTotalValue() {
const processesListElements = await testSubjects.findAll(
'infraAssetDetailsProcessesSummaryTableItem'

View file

@ -37,7 +37,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide
},
async getWaffleMap() {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const element = await testSubjects.find('waffleMap');
if (!element) {
throw new Error();
@ -98,13 +98,13 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide
},
async clickOnGoToNodeDetails() {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await testSubjects.click('viewAssetDetailsContextMenuItem');
});
},
async clickOnNodeDetailsFlyoutOpenAsPage() {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
await testSubjects.click('infraAssetDetailsOpenAsPageButton');
});
},
@ -139,7 +139,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide
// wait for input value to echo the input before submitting
// this ensures the React state has caught up with the events
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const value = await input.getAttribute('value');
expect(value).to.eql(query);
});

View file

@ -57,7 +57,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
return table.findAllByTestSubject('hostsView-tableRow');
},
async getHostsRowData(row: WebElementWrapper) {
async getHostsRowDataWithAlerts(row: WebElementWrapper) {
// Find all the row cells
const cells = await row.findAllByCssSelector('[data-test-subj*="hostsView-tableRow-"]');
@ -87,6 +87,26 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
};
},
async getHostsRowData(row: WebElementWrapper) {
// Find all the row cells
const cells = await row.findAllByCssSelector('[data-test-subj*="hostsView-tableRow-"]');
// Retrieve content for each cell
const [title, cpuUsage, normalizedLoad, memoryUsage, memoryFree, diskSpaceUsage, rx, tx] =
await Promise.all(cells.map((cell) => this.getHostsCellContent(cell)));
return {
title,
cpuUsage,
normalizedLoad,
memoryUsage,
memoryFree,
diskSpaceUsage,
rx,
tx,
};
},
async getHostsCellContent(cell: WebElementWrapper) {
const cellContent = await cell.findByClassName('euiTableCellContent');
return cellContent.getVisibleText();
@ -247,17 +267,17 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
},
// Sorting
getMemoryHeader() {
return testSubjects.find('tableHeaderCell_memory_5');
getCpuHeader() {
return testSubjects.find('tableHeaderCell_cpuV2_2');
},
getTitleHeader() {
return testSubjects.find('tableHeaderCell_title_2');
return testSubjects.find('tableHeaderCell_title_1');
},
async sortByMemoryUsage() {
const memory = await this.getMemoryHeader();
const button = await testSubjects.findDescendant('tableHeaderSortButton', memory);
async sortByCpuUsage() {
const cpu = await this.getCpuHeader();
const button = await testSubjects.findDescendant('tableHeaderSortButton', cpu);
await button.click();
},

View file

@ -71,7 +71,7 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) {
},
async ensureViewIsLoaded(name: string) {
await retry.try(async () => {
await retry.tryForTime(5000, async () => {
const subject = await testSubjects.find('savedViews-openPopover');
expect(await subject.getVisibleText()).to.be(name);
});