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

WIP: Enabling test coverage on e2e tests #31787

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -51,7 +51,7 @@ jobs:
- stage: build
name: 'Unminified Build'
script:
- unbuffer node build-system/pr-check/unminified-build.js
- travis wait 30 unbuffer node build-system/pr-check/unminified-build.js
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without this, the longer --coverage build will timeout on Travis

Copy link
Contributor

@rsimha rsimha Jan 6, 2021

Choose a reason for hiding this comment

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

As written, this will increase the time taken by all Travis builds because the "test" stage will now have to wait for (up to) a 30 minute "build" stage.

The good news is that we should be able to solve this problem with the move to CircleCI, which I believe allows for more sophisticated matrices (e.g. create a separate independent "coverage" stage, which starts at the beginning and runs in parallel with the "build" and "test" stages, which run serially.)

I expect to make progress on this in the next week or so, will loop you in when the coast is clear to try this out.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reminding me about this, forgot to note it! My thinking was this would only be viable for something like the Nightly builds, and probably shouldn't be a part of CI during the development day. Even if Circle CI supports splitting the work off, e2e test coverage shouldn't fluctuate massively from one commit to another, and daily data would be sufficient as a metric.

- stage: build
name: 'Checks'
script:
Expand Down
2 changes: 1 addition & 1 deletion build-system/pr-check/e2e-tests.js
Expand Up @@ -67,7 +67,7 @@ async function main() {
) {
downloadDistOutput(FILENAME);
timedExecOrDie('gulp update-packages');
timedExecOrDie('gulp e2e --nobuild --headless --compiled');
timedExecOrDie('gulp e2e --nobuild --headless --compiled --coverage');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should eventually be gated with argv.coverage; likewise with the gulp dist/gulp build commands below, which I had just enabled --coverage on while experimenting/trying to get it to run on Travis.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree. Adding an additional job to the CI matrix isn't that expensive, so we should probably just do all coverage measurements in a parallel job.

} else {
console.log(
`${FILELOGPREFIX} Skipping`,
Expand Down
5 changes: 4 additions & 1 deletion build-system/pr-check/nomodule-build.js
Expand Up @@ -66,7 +66,10 @@ async function main() {
) {
timedExecOrDie('gulp update-packages');

const process = timedExecWithError('gulp dist --fortesting', FILENAME);
const process = timedExecWithError(
'gulp dist --fortesting --coverage',
FILENAME
);
if (process.status !== 0) {
const error = process.error || new Error('unknown error, check logs');
log(colors.red('ERROR'), colors.yellow(error.message));
Expand Down
2 changes: 1 addition & 1 deletion build-system/pr-check/unminified-build.js
Expand Up @@ -60,7 +60,7 @@ function main() {
buildTargets.has('UNIT_TEST')
) {
timedExecOrDie('gulp update-packages');
timedExecOrDie('gulp build --fortesting');
timedExecOrDie('gulp build --fortesting --coverage');
uploadBuildOutput(FILENAME);
} else {
log(
Expand Down
27 changes: 1 addition & 26 deletions build-system/tasks/e2e/describes-e2e.js
Expand Up @@ -19,26 +19,21 @@ require('geckodriver');

const argv = require('minimist')(process.argv.slice(2));
const chrome = require('selenium-webdriver/chrome');
const fetch = require('node-fetch');
const firefox = require('selenium-webdriver/firefox');
const puppeteer = require('puppeteer');
const {
clearLastExpectError,
getLastExpectError,
installBrowserAssertions,
} = require('./expect');
const {
getCoverageObject,
mergeClientCoverage,
} = require('istanbul-middleware/lib/core');
const {
SeleniumWebDriverController,
} = require('./selenium-webdriver-controller');
const {AmpDriver, AmpdocEnvironment} = require('./amp-driver');
const {Builder, Capabilities, logging} = require('selenium-webdriver');
const {HOST, PORT} = require('../serve');
const {installRepl, uninstallRepl} = require('./repl');
const {isTravisBuild} = require('../../common/travis');
const {mergeClientCoverage} = require('istanbul-middleware/lib/core');
const {PuppeteerController} = require('./puppeteer-controller');

/** Should have something in the name, otherwise nothing is shown. */
Expand All @@ -47,7 +42,6 @@ const TEST_TIMEOUT = 40000;
const SETUP_TIMEOUT = 30000;
const SETUP_RETRIES = 3;
const DEFAULT_E2E_INITIAL_RECT = {width: 800, height: 600};
const COV_REPORT_PATH = '/coverage/client';
const supportedBrowsers = new Set(['chrome', 'firefox', 'safari']);
/**
* TODO(cvializ): Firefox now experimentally supports puppeteer.
Expand Down Expand Up @@ -350,19 +344,6 @@ async function updateCoverage(env) {
}
}

/**
* Reports code coverage data to an aggregating endpoint.
* @return {Promise<void>}
*/
async function reportCoverage() {
const coverage = getCoverageObject();
await fetch(`https://${HOST}:${PORT}${COV_REPORT_PATH}`, {
method: 'POST',
body: JSON.stringify(coverage),
headers: {'Content-type': 'application/json'},
});
}

/**
* Returns a wrapped version of Mocha's describe(), it() and only() methods
* that also sets up the provided fixtures and returns the corresponding
Expand Down Expand Up @@ -487,12 +468,6 @@ function describeEnv(factory) {
}
});

after(async () => {
if (argv.coverage) {
await reportCoverage();
}
});

describe(SUB, function () {
fn.call(this, env);
});
Expand Down
17 changes: 17 additions & 0 deletions build-system/tasks/e2e/index.js
Expand Up @@ -20,6 +20,7 @@ const argv = require('minimist')(process.argv.slice(2));
const ciReporter = require('./mocha-ci-reporter');
const config = require('../../test-configs/config');
const dotsReporter = require('./mocha-dots-reporter');
const fetch = require('node-fetch');
const fs = require('fs');
const glob = require('glob');
const http = require('http');
Expand All @@ -33,6 +34,7 @@ const {
} = require('../../common/utils');
const {cyan} = require('ansi-colors');
const {execOrDie} = require('../../common/exec');
const {getCoverageObject} = require('istanbul-middleware/lib/core');
const {HOST, PORT, startServer, stopServer} = require('../serve');
const {isTravisBuild} = require('../../common/travis');
const {maybePrintCoverageMessage} = require('../helpers');
Expand All @@ -42,6 +44,7 @@ const {watch} = require('gulp');
const SLOW_TEST_THRESHOLD_MS = 2500;
const TEST_RETRIES = isTravisBuild() ? 2 : 0;

const COV_REPORT_PATH = '/coverage/client';
const COV_DOWNLOAD_PATH = '/coverage/download';
const COV_OUTPUT_DIR = './test/coverage-e2e';
const COV_OUTPUT_HTML = path.resolve(COV_OUTPUT_DIR, 'lcov-report/index.html');
Expand Down Expand Up @@ -109,6 +112,19 @@ function addMochaFile_(mocha, file) {
mocha.addFile(file);
}

/**
* Reports code coverage data to an aggregating endpoint.
* @return {Promise<void>}
*/
async function reportCoverage_() {
const coverage = getCoverageObject();
await fetch(`http://${HOST}:${PORT}${COV_REPORT_PATH}`, {
method: 'POST',
body: JSON.stringify(coverage),
headers: {'Content-type': 'application/json'},
});
}

/**
* Fetch aggregated coverage data from server.
* @param {string} outDir relative path to coverage files directory.
Expand Down Expand Up @@ -170,6 +186,7 @@ async function runTests_() {
return new Promise((resolve) => {
mocha.run(async (failures) => {
if (argv.coverage) {
await reportCoverage_();
await fetchCoverage_(COV_OUTPUT_DIR);
maybePrintCoverageMessage(COV_OUTPUT_HTML);
}
Expand Down