From e05c0b3bedda8a1dec869368fe5a53f010fa8624 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 21 Nov 2023 17:56:16 +0100 Subject: [PATCH 01/10] [ftr/remote] improve poll_for_log_entry --- .../services/remote/poll_for_log_entry.ts | 46 +++++++------------ test/functional/services/remote/webdriver.ts | 14 +----- 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index 49de29381e87f9..a6fad727ad7d2a 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -8,40 +8,20 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; -import { mergeMap, catchError, mergeMapTo, delay, first } from 'rxjs/operators'; +import { mergeMap, catchError, mergeMapTo, delay } from 'rxjs/operators'; +import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; /** * Create an observable that emits log entries representing the calls to log messages * available for a specific logger. */ -export function pollForLogEntry$( - driver: WebDriver, - type: string, - ms: number, - stop$: Rx.Observable -) { +export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { const logCtrl = driver.manage().logs(); const poll$ = new Rx.BehaviorSubject(undefined); const FINAL_MSG = '@@final@@'; return new Rx.Observable((subscriber) => { - subscriber.add( - stop$.pipe(first()).subscribe(() => { - driver - .executeScript( - ` - if (window.flushCoverageToLog) { - window.flushCoverageToLog(); - } - - console.log(${JSON.stringify(FINAL_MSG)}) - ` - ) - .catch((error) => subscriber.error(error)); - }) - ); - subscriber.add( poll$ .pipe( @@ -79,13 +59,21 @@ export function pollForLogEntry$( }), catchError((error, resubscribe) => { - return Rx.concat( - // log error as a log entry - [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], + if (error instanceof NoSuchSessionError) { + return Rx.concat( + // Without Webdriver session we can't fetch logs, stopping + [new logging.Entry('SEVERE', `WEBDRIVER SESSION IS OVER: ${error.message}`)], + Rx.of(undefined) + ); + } else { + return Rx.concat( + // log error as a log entry + [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], - // pause 10 seconds then resubscribe - Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) - ); + // pause 10 seconds then resubscribe + Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) + ); + } }) ) .subscribe(subscriber) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 702f674b3c10d0..873ddec9de31f5 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -175,12 +175,7 @@ async function attemptToCreateCommand( return { session, - consoleLog$: pollForLogEntry$( - session, - logging.Type.BROWSER, - config.logPollingMs, - lifecycle.cleanup.after$ - ).pipe( + consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( takeUntil(lifecycle.cleanup.after$), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), @@ -203,12 +198,7 @@ async function attemptToCreateCommand( .build(); return { session, - consoleLog$: pollForLogEntry$( - session, - logging.Type.BROWSER, - config.logPollingMs, - lifecycle.cleanup.after$ - ).pipe( + consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( takeUntil(lifecycle.cleanup.after$), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), From d1560673905e98dbcb2881e90e2da628c7466d6f Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Wed, 22 Nov 2023 11:55:00 +0100 Subject: [PATCH 02/10] use takeWhile for logs polling --- .../services/remote/poll_for_log_entry.ts | 34 ++++++++----------- test/functional/services/remote/webdriver.ts | 8 +++-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index a6fad727ad7d2a..a908b3fb47e043 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -8,9 +8,11 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; -import { mergeMap, catchError, mergeMapTo, delay } from 'rxjs/operators'; +import { mergeMap, delay } from 'rxjs/operators'; import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; +export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS OVER'; + /** * Create an observable that emits log entries representing the calls to log messages * available for a specific logger. @@ -27,7 +29,17 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { .pipe( delay(ms), - mergeMap(async () => await logCtrl.get(type)), + mergeMap(async () => { + let entries: logging.Entry[] = []; + try { + entries = await logCtrl.get(type); + } catch (error) { + if (error instanceof NoSuchSessionError) { + return [new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`)]; + } + } + return entries; + }), // filter and flatten list of entries mergeMap((entries) => { @@ -56,24 +68,6 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { } return filtered; - }), - - catchError((error, resubscribe) => { - if (error instanceof NoSuchSessionError) { - return Rx.concat( - // Without Webdriver session we can't fetch logs, stopping - [new logging.Entry('SEVERE', `WEBDRIVER SESSION IS OVER: ${error.message}`)], - Rx.of(undefined) - ); - } else { - return Rx.concat( - // log error as a log entry - [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], - - // pause 10 seconds then resubscribe - Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) - ); - } }) ) .subscribe(subscriber) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 873ddec9de31f5..1fb65d074eb43f 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; import Fs from 'fs'; import * as Rx from 'rxjs'; -import { mergeMap, map, takeUntil, catchError, ignoreElements } from 'rxjs/operators'; +import { mergeMap, map, takeUntil, catchError, ignoreElements, takeWhile } from 'rxjs/operators'; import { Lifecycle } from '@kbn/test'; import { ToolingLog } from '@kbn/tooling-log'; import chromeDriver from 'chromedriver'; @@ -25,7 +25,7 @@ import { getLogger } from 'selenium-webdriver/lib/logging'; import { installDriver } from 'ms-chromium-edge-driver'; import { REPO_ROOT } from '@kbn/repo-info'; -import { pollForLogEntry$ } from './poll_for_log_entry'; +import { FINAL_LOG_ENTRY_PREFIX, pollForLogEntry$ } from './poll_for_log_entry'; import { createStdoutSocket } from './create_stdout_stream'; import { preventParallelCalls } from './prevent_parallel_calls'; @@ -176,7 +176,9 @@ async function attemptToCreateCommand( return { session, consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeUntil(lifecycle.cleanup.after$), + takeWhile((loggingEntry: logging.Entry) => + loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) + ), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), level, From 782c8b1f02b0ce2d771abe9ede5fdac372551c99 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Wed, 22 Nov 2023 12:08:24 +0100 Subject: [PATCH 03/10] fix condition --- test/functional/services/remote/webdriver.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 1fb65d074eb43f..53408a15eaed37 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -176,8 +176,9 @@ async function attemptToCreateCommand( return { session, consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeWhile((loggingEntry: logging.Entry) => - loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) + takeWhile( + (loggingEntry: logging.Entry) => + !loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) ), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), From 6763ce7b04a546501ff09748a1e635ff68defb1d Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 21 Nov 2023 17:56:16 +0100 Subject: [PATCH 04/10] [ftr/remote] improve poll_for_log_entry --- .../services/remote/poll_for_log_entry.ts | 46 +++++++------------ test/functional/services/remote/webdriver.ts | 14 +----- 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index 49de29381e87f9..a6fad727ad7d2a 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -8,40 +8,20 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; -import { mergeMap, catchError, mergeMapTo, delay, first } from 'rxjs/operators'; +import { mergeMap, catchError, mergeMapTo, delay } from 'rxjs/operators'; +import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; /** * Create an observable that emits log entries representing the calls to log messages * available for a specific logger. */ -export function pollForLogEntry$( - driver: WebDriver, - type: string, - ms: number, - stop$: Rx.Observable -) { +export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { const logCtrl = driver.manage().logs(); const poll$ = new Rx.BehaviorSubject(undefined); const FINAL_MSG = '@@final@@'; return new Rx.Observable((subscriber) => { - subscriber.add( - stop$.pipe(first()).subscribe(() => { - driver - .executeScript( - ` - if (window.flushCoverageToLog) { - window.flushCoverageToLog(); - } - - console.log(${JSON.stringify(FINAL_MSG)}) - ` - ) - .catch((error) => subscriber.error(error)); - }) - ); - subscriber.add( poll$ .pipe( @@ -79,13 +59,21 @@ export function pollForLogEntry$( }), catchError((error, resubscribe) => { - return Rx.concat( - // log error as a log entry - [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], + if (error instanceof NoSuchSessionError) { + return Rx.concat( + // Without Webdriver session we can't fetch logs, stopping + [new logging.Entry('SEVERE', `WEBDRIVER SESSION IS OVER: ${error.message}`)], + Rx.of(undefined) + ); + } else { + return Rx.concat( + // log error as a log entry + [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], - // pause 10 seconds then resubscribe - Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) - ); + // pause 10 seconds then resubscribe + Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) + ); + } }) ) .subscribe(subscriber) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 702f674b3c10d0..873ddec9de31f5 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -175,12 +175,7 @@ async function attemptToCreateCommand( return { session, - consoleLog$: pollForLogEntry$( - session, - logging.Type.BROWSER, - config.logPollingMs, - lifecycle.cleanup.after$ - ).pipe( + consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( takeUntil(lifecycle.cleanup.after$), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), @@ -203,12 +198,7 @@ async function attemptToCreateCommand( .build(); return { session, - consoleLog$: pollForLogEntry$( - session, - logging.Type.BROWSER, - config.logPollingMs, - lifecycle.cleanup.after$ - ).pipe( + consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( takeUntil(lifecycle.cleanup.after$), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), From 9a06de9c905c50bd82d0229fd10b41ac79e71434 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Wed, 22 Nov 2023 11:55:00 +0100 Subject: [PATCH 05/10] use takeWhile for logs polling --- .../services/remote/poll_for_log_entry.ts | 34 ++++++++----------- test/functional/services/remote/webdriver.ts | 8 +++-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index a6fad727ad7d2a..a908b3fb47e043 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -8,9 +8,11 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; -import { mergeMap, catchError, mergeMapTo, delay } from 'rxjs/operators'; +import { mergeMap, delay } from 'rxjs/operators'; import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; +export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS OVER'; + /** * Create an observable that emits log entries representing the calls to log messages * available for a specific logger. @@ -27,7 +29,17 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { .pipe( delay(ms), - mergeMap(async () => await logCtrl.get(type)), + mergeMap(async () => { + let entries: logging.Entry[] = []; + try { + entries = await logCtrl.get(type); + } catch (error) { + if (error instanceof NoSuchSessionError) { + return [new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`)]; + } + } + return entries; + }), // filter and flatten list of entries mergeMap((entries) => { @@ -56,24 +68,6 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { } return filtered; - }), - - catchError((error, resubscribe) => { - if (error instanceof NoSuchSessionError) { - return Rx.concat( - // Without Webdriver session we can't fetch logs, stopping - [new logging.Entry('SEVERE', `WEBDRIVER SESSION IS OVER: ${error.message}`)], - Rx.of(undefined) - ); - } else { - return Rx.concat( - // log error as a log entry - [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], - - // pause 10 seconds then resubscribe - Rx.of(1).pipe(delay(10 * 1000), mergeMapTo(resubscribe)) - ); - } }) ) .subscribe(subscriber) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 873ddec9de31f5..1fb65d074eb43f 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; import Fs from 'fs'; import * as Rx from 'rxjs'; -import { mergeMap, map, takeUntil, catchError, ignoreElements } from 'rxjs/operators'; +import { mergeMap, map, takeUntil, catchError, ignoreElements, takeWhile } from 'rxjs/operators'; import { Lifecycle } from '@kbn/test'; import { ToolingLog } from '@kbn/tooling-log'; import chromeDriver from 'chromedriver'; @@ -25,7 +25,7 @@ import { getLogger } from 'selenium-webdriver/lib/logging'; import { installDriver } from 'ms-chromium-edge-driver'; import { REPO_ROOT } from '@kbn/repo-info'; -import { pollForLogEntry$ } from './poll_for_log_entry'; +import { FINAL_LOG_ENTRY_PREFIX, pollForLogEntry$ } from './poll_for_log_entry'; import { createStdoutSocket } from './create_stdout_stream'; import { preventParallelCalls } from './prevent_parallel_calls'; @@ -176,7 +176,9 @@ async function attemptToCreateCommand( return { session, consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeUntil(lifecycle.cleanup.after$), + takeWhile((loggingEntry: logging.Entry) => + loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) + ), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), level, From c99e3fa6b6ced7175f55f2e632e728693010f3d1 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Wed, 22 Nov 2023 12:08:24 +0100 Subject: [PATCH 06/10] fix condition --- test/functional/services/remote/webdriver.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 1fb65d074eb43f..53408a15eaed37 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -176,8 +176,9 @@ async function attemptToCreateCommand( return { session, consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeWhile((loggingEntry: logging.Entry) => - loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) + takeWhile( + (loggingEntry: logging.Entry) => + !loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) ), map(({ message, level: { name: level } }) => ({ message: message.replace(/\\n/g, '\n'), From bb1815f2f58912a422fbb607f8076234ae6e3942 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 28 Nov 2023 12:49:50 +0100 Subject: [PATCH 07/10] unify logs polling for chrome/edge --- test/functional/services/remote/webdriver.ts | 35 +++++++++----------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 53408a15eaed37..49a43817efc62c 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -10,11 +10,11 @@ import { resolve } from 'path'; import Fs from 'fs'; import * as Rx from 'rxjs'; -import { mergeMap, map, takeUntil, catchError, ignoreElements, takeWhile } from 'rxjs/operators'; +import { mergeMap, map, catchError, ignoreElements, takeWhile } from 'rxjs/operators'; import { Lifecycle } from '@kbn/test'; import { ToolingLog } from '@kbn/tooling-log'; import chromeDriver from 'chromedriver'; -import { Builder, logging } from 'selenium-webdriver'; +import { Builder, logging, WebDriver } from 'selenium-webdriver'; import chrome from 'selenium-webdriver/chrome'; import firefox from 'selenium-webdriver/firefox'; import edge from 'selenium-webdriver/edge'; @@ -139,6 +139,18 @@ function initChromiumOptions(browserType: Browsers, acceptInsecureCerts: boolean return options; } +function pollForChromiumLogs$(session: WebDriver, logPollingMs: number) { + return pollForLogEntry$(session, logging.Type.BROWSER, logPollingMs).pipe( + takeWhile( + (loggingEntry: logging.Entry) => !loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) + ), + map(({ message, level: { name: level } }) => ({ + message: message.replace(/\\n/g, '\n'), + level, + })) + ); +} + let attemptCounter = 0; let edgePaths: { driverPath: string | undefined; browserPath: string | undefined }; async function attemptToCreateCommand( @@ -175,16 +187,7 @@ async function attemptToCreateCommand( return { session, - consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeWhile( - (loggingEntry: logging.Entry) => - !loggingEntry.message.startsWith(FINAL_LOG_ENTRY_PREFIX) - ), - map(({ message, level: { name: level } }) => ({ - message: message.replace(/\\n/g, '\n'), - level, - })) - ), + consoleLog$: pollForChromiumLogs$(session, config.logPollingMs), }; } @@ -201,13 +204,7 @@ async function attemptToCreateCommand( .build(); return { session, - consoleLog$: pollForLogEntry$(session, logging.Type.BROWSER, config.logPollingMs).pipe( - takeUntil(lifecycle.cleanup.after$), - map(({ message, level: { name: level } }) => ({ - message: message.replace(/\\n/g, '\n'), - level, - })) - ), + consoleLog$: pollForChromiumLogs$(session, config.logPollingMs), }; } else { throw new Error( From 1f58fca7f6121b95e793c0402bc1dfe235892a35 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Tue, 2 Jan 2024 18:00:51 +0100 Subject: [PATCH 08/10] update msg & check --- test/functional/services/remote/poll_for_log_entry.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/services/remote/poll_for_log_entry.ts b/test/functional/services/remote/poll_for_log_entry.ts index a908b3fb47e043..dbd5631cb57fbc 100644 --- a/test/functional/services/remote/poll_for_log_entry.ts +++ b/test/functional/services/remote/poll_for_log_entry.ts @@ -11,7 +11,7 @@ import * as Rx from 'rxjs'; import { mergeMap, delay } from 'rxjs/operators'; import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; -export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS OVER'; +export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS STOPPED'; /** * Create an observable that emits log entries representing the calls to log messages @@ -35,6 +35,7 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { entries = await logCtrl.get(type); } catch (error) { if (error instanceof NoSuchSessionError) { + // WebDriver session is invalid, sending the last log message return [new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`)]; } } @@ -62,7 +63,7 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { return true; }); - if (!poll$.isStopped) { + if (!poll$.closed) { // schedule next poll poll$.next(undefined); } From 4ba42b40980c04520753f3ea914646f98262c5d0 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Thu, 11 Jan 2024 17:04:51 +0100 Subject: [PATCH 09/10] simplify logic --- .../services/remote/poll_for_log_entry.ts | 89 ++++++++----------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts index dbd5631cb57fbc..0a38514cedb74d 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts @@ -8,7 +8,7 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; -import { mergeMap, delay } from 'rxjs/operators'; +import { mergeMap, catchError, delay, repeat } from 'rxjs/operators'; import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS STOPPED'; @@ -19,59 +19,48 @@ export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS STOPPED'; */ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { const logCtrl = driver.manage().logs(); - const poll$ = new Rx.BehaviorSubject(undefined); - const FINAL_MSG = '@@final@@'; + // setup log polling + return Rx.defer(async () => await logCtrl.get(type)).pipe( + // filter and flatten list of entries + mergeMap((entries) => + entries.filter((entry) => { + // ignore react devtools + if (entry.message.includes('Download the React DevTools')) { + return false; + } - return new Rx.Observable((subscriber) => { - subscriber.add( - poll$ - .pipe( - delay(ms), + // down-level inline script errors + if (entry.message.includes('Refused to execute inline script')) { + entry.level = logging.getLevel('INFO'); + } - mergeMap(async () => { - let entries: logging.Entry[] = []; - try { - entries = await logCtrl.get(type); - } catch (error) { - if (error instanceof NoSuchSessionError) { - // WebDriver session is invalid, sending the last log message - return [new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`)]; - } - } - return entries; - }), + return true; + }) + ), - // filter and flatten list of entries - mergeMap((entries) => { - const filtered = entries.filter((entry) => { - if (entry.message.includes(FINAL_MSG)) { - poll$.complete(); - return false; - } + // resubscribe when parent completes with delay by `ms` milliseconds + repeat(), + delay(ms), - // ignore react devtools - if (entry.message.includes('Download the React DevTools')) { - return false; - } + catchError((error, resubscribe) => { + if (error instanceof NoSuchSessionError) { + // WebDriver session is invalid, sending the last log message + return Rx.concat([ + new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`), + ]); + } else { + return Rx.concat( + // log error as a log entry + [new logging.Entry('SEVERE', `ERROR FETCHING BROWSR LOGS: ${error.message}`)], - // down-level inline script errors - if (entry.message.includes('Refused to execute inline script')) { - entry.level = logging.getLevel('INFO'); - } - - return true; - }); - - if (!poll$.closed) { - // schedule next poll - poll$.next(undefined); - } - - return filtered; - }) - ) - .subscribe(subscriber) - ); - }); + // pause 10 seconds then resubscribe + Rx.of(1).pipe( + delay(10 * 1000), + mergeMap(() => resubscribe) + ) + ); + } + }) + ); } From be2b33d4865f4343c4aab4279a206a65bfc2b385 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Fri, 12 Jan 2024 14:53:05 +0100 Subject: [PATCH 10/10] add more errors to stop logs pulling after --- .../services/remote/poll_for_log_entry.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts index 0a38514cedb74d..133b3da2785f2b 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/poll_for_log_entry.ts @@ -9,7 +9,7 @@ import { WebDriver, logging } from 'selenium-webdriver'; import * as Rx from 'rxjs'; import { mergeMap, catchError, delay, repeat } from 'rxjs/operators'; -import { NoSuchSessionError } from 'selenium-webdriver/lib/error'; +import { NoSuchSessionError, NoSuchWindowError } from 'selenium-webdriver/lib/error'; export const FINAL_LOG_ENTRY_PREFIX = 'WEBDRIVER SESSION IS STOPPED'; @@ -44,7 +44,11 @@ export function pollForLogEntry$(driver: WebDriver, type: string, ms: number) { delay(ms), catchError((error, resubscribe) => { - if (error instanceof NoSuchSessionError) { + if ( + error instanceof NoSuchSessionError || // session is invalid + error instanceof NoSuchWindowError || // browser window crashed + error?.message.startsWith('ECONNREFUSED') // webdriver server is not responding, often after one of previous errors + ) { // WebDriver session is invalid, sending the last log message return Rx.concat([ new logging.Entry('SEVERE', `${FINAL_LOG_ENTRY_PREFIX}: ${error.message}`),