diff --git a/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts b/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts index e4ac2346b5893..02e1e7656bf78 100644 --- a/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts +++ b/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts @@ -62,7 +62,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(event.properties.value4).to.be.a('number'); expect(event.properties.value5).to.be.a('number'); - if (browser.isChromium) { + if (browser.isChromium()) { // Kibana Loaded memory expect(meta).to.have.property('jsHeapSizeLimit'); expect(meta.jsHeapSizeLimit).to.be.a('number'); diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index 393f093d54189..fd46e5ac1448b 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -7,8 +7,9 @@ */ import { setTimeout as setTimeoutAsync } from 'timers/promises'; -import { cloneDeepWith } from 'lodash'; +import { cloneDeepWith, isString } from 'lodash'; import { Key, Origin, WebDriver } from 'selenium-webdriver'; +import { Driver as ChromiumWebDriver } from 'selenium-webdriver/chrome'; import { modifyUrl } from '@kbn/std'; import sharp from 'sharp'; @@ -16,6 +17,7 @@ import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; import { WebElementWrapper } from '../lib/web_element_wrapper'; import { FtrProviderContext, FtrService } from '../../ftr_provider_context'; import { Browsers } from '../remote/browsers'; +import { NetworkOptions, NetworkProfile, NETWORK_PROFILES } from '../remote/network_profiles'; export type Browser = BrowserService; @@ -25,19 +27,20 @@ class BrowserService extends FtrService { */ public readonly keys = Key; public readonly isFirefox: boolean; - public readonly isChromium: boolean; private readonly log = this.ctx.getService('log'); constructor( ctx: FtrProviderContext, public readonly browserType: string, - private readonly driver: WebDriver + protected readonly driver: WebDriver | ChromiumWebDriver ) { super(ctx); this.isFirefox = this.browserType === Browsers.Firefox; - this.isChromium = - this.browserType === Browsers.Chrome || this.browserType === Browsers.ChromiumEdge; + } + + public isChromium(): this is { driver: ChromiumWebDriver } { + return this.driver instanceof ChromiumWebDriver; } /** @@ -661,6 +664,68 @@ class BrowserService extends FtrService { } } } + + /** + * Get the network simulation for chromium browsers if available. + * https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/chrome_exports_Driver.html#getNetworkConditions + * + * @return {Promise} + */ + public async getNetworkConditions() { + if (this.isChromium()) { + return this.driver.getNetworkConditions().catch(() => undefined); // Return undefined instead of throwing if no conditions are set. + } else { + const message = + 'WebDriver does not support the .getNetworkConditions method.\nProbably the browser in used is not chromium based.'; + this.log.error(message); + throw new Error(message); + } + } + + /** + * Delete the network simulation for chromium browsers if available. + * + * @return {Promise} + */ + public async restoreNetworkConditions() { + this.log.debug('Restore network conditions simulation.'); + return this.setNetworkConditions('NO_THROTTLING'); + } + + /** + * Set the network conditions for chromium browsers if available. + * + * __Sample Usage:__ + * + * browser.setNetworkConditions('FAST_3G') + * browser.setNetworkConditions('SLOW_3G') + * browser.setNetworkConditions('OFFLINE') + * browser.setNetworkConditions({ + * offline: false, + * latency: 5, // Additional latency (ms). + * download_throughput: 500 * 1024, // Maximal aggregated download throughput. + * upload_throughput: 500 * 1024, // Maximal aggregated upload throughput. + * }); + * + * https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/chrome_exports_Driver.html#setNetworkConditions + * + * @return {Promise} + */ + public async setNetworkConditions(profileOrOptions: NetworkProfile | NetworkOptions) { + const networkOptions = isString(profileOrOptions) + ? NETWORK_PROFILES[profileOrOptions] + : profileOrOptions; + + if (this.isChromium()) { + this.log.debug(`Set network conditions with profile "${profileOrOptions}".`); + return this.driver.setNetworkConditions(networkOptions); + } else { + const message = + 'WebDriver does not support the .setNetworkCondition method.\nProbably the browser in used is not chromium based.'; + this.log.error(message); + throw new Error(message); + } + } } export async function BrowserProvider(ctx: FtrProviderContext) { diff --git a/test/functional/services/remote/network_profiles.ts b/test/functional/services/remote/network_profiles.ts index cb4076686270c..29e4a0feeaace 100644 --- a/test/functional/services/remote/network_profiles.ts +++ b/test/functional/services/remote/network_profiles.ts @@ -6,10 +6,13 @@ * Side Public License, v 1. */ -interface NetworkOptions { - DOWNLOAD: number; - UPLOAD: number; - LATENCY: number; +export type NetworkProfile = 'NO_THROTTLING' | 'FAST_3G' | 'SLOW_3G' | 'OFFLINE' | 'CLOUD_USER'; + +export interface NetworkOptions { + offline: boolean; + latency: number; + download_throughput: number; + upload_throughput: number; } const sec = 10 ** 3; @@ -17,6 +20,36 @@ const MBps = 10 ** 6 / 8; // megabyte per second (MB/s) (can be abbreviated as M // Selenium uses B/s (bytes) for network throttling // Download (B/s) Upload (B/s) Latency (ms) -export const NETWORK_PROFILES: { [key: string]: NetworkOptions } = { - CLOUD_USER: { DOWNLOAD: 6 * MBps, UPLOAD: 6 * MBps, LATENCY: 0.1 * sec }, + +export const NETWORK_PROFILES: Record = { + NO_THROTTLING: { + offline: false, + latency: 0, + download_throughput: -1, + upload_throughput: -1, + }, + FAST_3G: { + offline: false, + latency: 0.56 * sec, + download_throughput: 1.44 * MBps, + upload_throughput: 0.7 * MBps, + }, + SLOW_3G: { + offline: false, + latency: 2 * sec, + download_throughput: 0.4 * MBps, + upload_throughput: 0.4 * MBps, + }, + OFFLINE: { + offline: true, + latency: 0, + download_throughput: 0, + upload_throughput: 0, + }, + CLOUD_USER: { + offline: false, + latency: 0.1 * sec, + download_throughput: 6 * MBps, + upload_throughput: 6 * MBps, + }, }; diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 1486d02656d12..702f674b3c10d 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -30,7 +30,7 @@ import { createStdoutSocket } from './create_stdout_stream'; import { preventParallelCalls } from './prevent_parallel_calls'; import { Browsers } from './browsers'; -import { NETWORK_PROFILES } from './network_profiles'; +import { NetworkProfile, NETWORK_PROFILES } from './network_profiles'; const throttleOption: string = process.env.TEST_THROTTLE_NETWORK as string; const headlessBrowser: string = process.env.TEST_BROWSER_HEADLESS as string; @@ -300,22 +300,17 @@ async function attemptToCreateCommand( const { session, consoleLog$ } = await buildDriverInstance(); if (throttleOption === '1' && browserType === 'chrome') { - const { KBN_NETWORK_TEST_PROFILE = 'CLOUD_USER' } = process.env; + const KBN_NETWORK_TEST_PROFILE = (process.env.KBN_NETWORK_TEST_PROFILE ?? + 'CLOUD_USER') as NetworkProfile; const profile = - KBN_NETWORK_TEST_PROFILE in Object.keys(NETWORK_PROFILES) - ? KBN_NETWORK_TEST_PROFILE - : 'CLOUD_USER'; + KBN_NETWORK_TEST_PROFILE in NETWORK_PROFILES ? KBN_NETWORK_TEST_PROFILE : 'CLOUD_USER'; - const { - DOWNLOAD: downloadThroughput, - UPLOAD: uploadThroughput, - LATENCY: latency, - } = NETWORK_PROFILES[`${profile}`]; + const networkProfileOptions = NETWORK_PROFILES[profile]; // Only chrome supports this option. log.debug( - `NETWORK THROTTLED with profile ${profile}: ${downloadThroughput} B/s down, ${uploadThroughput} B/s up, ${latency} ms latency.` + `NETWORK THROTTLED with profile ${profile}: ${networkProfileOptions.download_throughput} B/s down, ${networkProfileOptions.upload_throughput} B/s up, ${networkProfileOptions.latency} ms latency.` ); if (noCache) { @@ -326,12 +321,7 @@ async function attemptToCreateCommand( } // @ts-expect-error - session.setNetworkConditions({ - offline: false, - latency, - download_throughput: downloadThroughput, - upload_throughput: uploadThroughput, - }); + session.setNetworkConditions(networkProfileOptions); } if (attemptId !== attemptCounter) {