Fix code coverage for functional tests (#53297)

* update build scripts to not set inline source-maps for code coverage run

* [ftr] browser console log processing cleanup

* get last coverage piece directly via webdriver

* more cleanup

* review feedback
This commit is contained in:
Dmitry Lemeshko 2019-12-19 08:23:30 +01:00 committed by GitHub
parent a1e92446b5
commit 745188b378
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 54 deletions

View file

@ -55,7 +55,9 @@ run(
'--extensions',
'.ts,.js,.tsx',
...(flags.watch ? ['--watch'] : ['--quiet']),
...(flags['source-maps'] ? ['--source-maps', 'inline'] : []),
...(!flags['source-maps'] || !!process.env.CODE_COVERAGE
? []
: ['--source-maps', 'inline']),
],
wait: true,
env: {

View file

@ -55,7 +55,9 @@ run(
'--extensions',
'.ts,.js,.tsx',
...(flags.watch ? ['--watch'] : ['--quiet']),
...(flags['source-maps'] ? ['--source-maps', 'inline'] : []),
...(!flags['source-maps'] || !!process.env.CODE_COVERAGE
? []
: ['--source-maps', 'inline']),
],
wait: true,
env: {

View file

@ -30,13 +30,7 @@ import { Browsers } from './remote/browsers';
export async function BrowserProvider({ getService }: FtrProviderContext) {
const log = getService('log');
const { driver, browserType, consoleLog$ } = await getService('__webdriver__').init();
consoleLog$.subscribe(({ message, level }) => {
log[level === 'SEVERE' || level === 'error' ? 'error' : 'debug'](
`browser[${level}] ${message}`
);
});
const { driver, browserType } = await getService('__webdriver__').init();
const isW3CEnabled = (driver as any).executor_.w3c === true;

View file

@ -20,14 +20,11 @@
import Fs from 'fs';
import { resolve } from 'path';
import * as Rx from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { logging } from 'selenium-webdriver';
import { FtrProviderContext } from '../../ftr_provider_context';
import { initWebDriver } from './webdriver';
import { Browsers } from './browsers';
import { pollForLogEntry$ } from './poll_for_log_entry';
export async function RemoteProvider({ getService }: FtrProviderContext) {
const lifecycle = getService('lifecycle');
@ -37,7 +34,7 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
const collectCoverage: boolean = !!process.env.CODE_COVERAGE;
const coveragePrefix = 'coveragejson:';
const coverageDir = resolve(__dirname, '../../../../target/kibana-coverage/functional');
let logSubscription: undefined | Rx.Subscription;
let coverageCounter = 1;
type BrowserStorage = 'sessionStorage' | 'localStorage';
const clearBrowserStorage = async (storageType: BrowserStorage) => {
@ -50,6 +47,14 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
}
};
const writeCoverage = (coverageJson: string) => {
const id = coverageCounter++;
const timestamp = Date.now();
const path = resolve(coverageDir, `${id}.${timestamp}.coverage.json`);
log.info('writing coverage to', path);
Fs.writeFileSync(path, JSON.stringify(JSON.parse(coverageJson), null, 2));
};
const { driver, By, until, consoleLog$ } = await initWebDriver(
log,
browserType,
@ -69,46 +74,35 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
caps.get('chrome').chromedriverVersion
}, w3c=${isW3CEnabled}, codeCoverage=${collectCoverage}`
);
if (collectCoverage) {
let coverageCounter = 1;
// We are running xpack tests with different configs and cleanup will delete collected coverage
// del.sync(coverageDir);
Fs.mkdirSync(coverageDir, { recursive: true });
logSubscription = pollForLogEntry$(
driver,
logging.Type.BROWSER,
config.get('browser.logPollingMs'),
lifecycle.cleanup.after$
)
.pipe(
mergeMap(logEntry => {
if (logEntry.message.includes(coveragePrefix)) {
const id = coverageCounter++;
const timestamp = Date.now();
const path = resolve(coverageDir, `${id}.${timestamp}.coverage.json`);
const [, coverageJsonBase64] = logEntry.message.split(coveragePrefix);
const coverageJson = Buffer.from(coverageJsonBase64, 'base64').toString('utf8');
log.info('writing coverage to', path);
Fs.writeFileSync(path, JSON.stringify(JSON.parse(coverageJson), null, 2));
// filter out this message
return [];
}
return [logEntry];
})
)
.subscribe({
next({ message, level: { name: level } }) {
const msg = message.replace(/\\n/g, '\n');
log[level === 'SEVERE' ? 'error' : 'debug'](`browser[${level}] ${msg}`);
},
});
}
}
// code coverage is supported only in Chrome browser
if (collectCoverage) {
// We are running xpack tests with different configs and cleanup will delete collected coverage
// del.sync(coverageDir);
Fs.mkdirSync(coverageDir, { recursive: true });
}
consoleLog$
.pipe(
mergeMap(logEntry => {
if (collectCoverage && logEntry.message.includes(coveragePrefix)) {
const [, coverageJsonBase64] = logEntry.message.split(coveragePrefix);
const coverageJson = Buffer.from(coverageJsonBase64, 'base64').toString('utf8');
writeCoverage(coverageJson);
// filter out this message
return [];
}
return [logEntry];
})
)
.subscribe({
next({ message, level }) {
const msg = message.replace(/\\n/g, '\n');
log[level === 'SEVERE' ? 'error' : 'debug'](`browser[${level}] ${msg}`);
},
});
lifecycle.beforeTests.add(async () => {
// hard coded default, can be overridden per suite using `browser.setWindowSize()`
@ -144,8 +138,15 @@ export async function RemoteProvider({ getService }: FtrProviderContext) {
});
lifecycle.cleanup.add(async () => {
if (logSubscription) {
await new Promise(r => logSubscription!.add(r));
// Getting the last piece of code coverage before closing browser
if (collectCoverage) {
const coverageJson = await driver
.executeScript('return window.__coverage__')
.catch(() => undefined)
.then(coverage => coverage && JSON.stringify(coverage));
if (coverageJson) {
writeCoverage(coverageJson);
}
}
await driver.quit();