Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[ftr] Improve FTR error handling for NoSuchSessionError #161025

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions test/functional/services/common/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Key, Origin, WebDriver } from 'selenium-webdriver';
import { modifyUrl } from '@kbn/std';

import sharp from 'sharp';
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';
Expand Down Expand Up @@ -632,8 +633,33 @@ class BrowserService extends FtrService {
return Boolean(result?.state === 'granted');
}

public getClipboardValue(): Promise<string> {
return this.driver.executeAsyncScript('navigator.clipboard.readText().then(arguments[0])');
Comment on lines -635 to -636
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to the main change, but I thought this update doesn't worth a separate PR

public async getClipboardValue(): Promise<string> {
return await this.driver.executeAsyncScript(
'navigator.clipboard.readText().then(arguments[0])'
);
}

/**
* Checks if browser session is active and any browser window exists
* @returns {Promise<boolean>}
*/
public async hasOpenWindow(): Promise<boolean> {
if (this.driver == null) {
return false;
} else {
try {
const windowHandles = await this.driver.getAllWindowHandles();
return windowHandles.length > 0;
} catch (err) {
if (err instanceof NoSuchSessionError) {
// https://developer.mozilla.org/en-US/docs/Web/WebDriver/Errors/InvalidSessionID
this.log.error(
`WebDriver session is no longer valid.\nProbably Chrome process crashed when it tried to use more memory than what was available.`
);
}
return false;
}
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion test/functional/services/common/failure_debugging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ export async function FailureDebuggingProvider({ getService }: FtrProviderContex

async function onFailure(_: any, test: Test) {
const name = FtrScreenshotFilename.create(test.fullTitle(), { ext: false });
await Promise.all([screenshots.takeForFailure(name), logCurrentUrl(), savePageHtml(name)]);
const hasOpenWindow = await browser.hasOpenWindow();
if (hasOpenWindow) {
await Promise.all([screenshots.takeForFailure(name), logCurrentUrl(), savePageHtml(name)]);
} else {
log.error('Browser is closed, no artifacts were captured for the failure');
}
}

lifecycle.testFailure.add(onFailure);
Expand Down
20 changes: 4 additions & 16 deletions test/functional/services/common/screenshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import { resolve, dirname } from 'path';
import { writeFile, readFileSync, mkdir } from 'fs';
import { promisify } from 'util';
import { NoSuchSessionError } from 'selenium-webdriver/lib/error';

import del from 'del';

Expand Down Expand Up @@ -85,20 +84,9 @@ export class ScreenshotsService extends FtrService {
}

private async capture(path: string, el?: WebElementWrapper) {
try {
this.log.info(`Taking screenshot "${path}"`);
const screenshot = await (el ? el.takeScreenshot() : this.browser.takeScreenshot());
await mkdirAsync(dirname(path), { recursive: true });
await writeFileAsync(path, screenshot, 'base64');
} catch (err) {
this.log.error('SCREENSHOT FAILED');
this.log.error(err);
if (err instanceof NoSuchSessionError) {
// https://developer.mozilla.org/en-US/docs/Web/WebDriver/Errors/InvalidSessionID
this.log.error(
`WebDriver session is no longer valid.\nProbably Chrome process crashed when it tried to use more memory than what was available.`
);
}
}
this.log.info(`Taking ${el ? 'element' : 'window'} screenshot "${path}"`);
const screenshot = await (el ? el.takeScreenshot() : this.browser.takeScreenshot());
await mkdirAsync(dirname(path), { recursive: true });
await writeFileAsync(path, screenshot, 'base64');
}
}
30 changes: 25 additions & 5 deletions test/functional/services/remote/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
* Side Public License, v 1.
*/

import { NoSuchSessionError } from 'selenium-webdriver/lib/error';
import { FtrProviderContext } from '../../ftr_provider_context';
import { initWebDriver, BrowserConfig } from './webdriver';

import { Browsers } from './browsers';

export async function RemoteProvider({ getService }: FtrProviderContext) {
Expand All @@ -27,6 +29,20 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
}
};

const tryWebDriverCall = async (command: () => Promise<void>) => {
// Since WebDriver session may be deleted, we fail silently. Use only in after hooks.
try {
await command();
} catch (err) {
if (err instanceof NoSuchSessionError) {
// https://developer.mozilla.org/en-US/docs/Web/WebDriver/Errors/InvalidSessionID
log.error('WebDriver session is no longer valid');
} else {
log.error(err);
}
}
};

const browserConfig: BrowserConfig = {
logPollingMs: config.get('browser.logPollingMs'),
acceptInsecureCerts: config.get('browser.acceptInsecureCerts'),
Expand Down Expand Up @@ -72,14 +88,18 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
});

lifecycle.afterTestSuite.add(async () => {
const { width, height } = windowSizeStack.shift()!;
await driver.manage().window().setRect({ width, height });
await clearBrowserStorage('sessionStorage');
await clearBrowserStorage('localStorage');
await tryWebDriverCall(async () => {
const { width, height } = windowSizeStack.shift()!;
await driver.manage().window().setRect({ width, height });
await clearBrowserStorage('sessionStorage');
await clearBrowserStorage('localStorage');
});
});

lifecycle.cleanup.add(async () => {
await driver.quit();
await tryWebDriverCall(async () => {
await driver.quit();
});
});

return { driver, browserType, consoleLog$ };
Expand Down