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

test(perf): add benchmark for jest runner #2618

Merged
merged 15 commits into from Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from 14 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
5 changes: 5 additions & 0 deletions .github/workflows/performance.yml
Expand Up @@ -24,3 +24,8 @@ jobs:
run: npm run perf
env:
PERF_TEST_GLOB_PATTERN: ${{ github.event.inputs.PERF_TEST_GLOB_PATTERN }}
- name: Store reports
uses: actions/upload-artifact@v2
with:
name: mutation-testing-reports
path: perf/test/*/reports/mutation
3 changes: 3 additions & 0 deletions .gitmodules
@@ -1,3 +1,6 @@
[submodule "perf/test/express"]
path = perf/test/express
url = https://github.com/expressjs/express.git
[submodule "perf/test/lighthouse"]
path = perf/test/lighthouse
url = https://github.com/GoogleChrome/lighthouse.git
9 changes: 0 additions & 9 deletions perf/config/express/package.json

This file was deleted.

24 changes: 24 additions & 0 deletions perf/config/lighthouse/stryker.conf.json
@@ -0,0 +1,24 @@
{
"$schema": "../../../packages/core/schema/stryker-schema.json",
"packageManager": "yarn",
"reporters": [
"html",
"clear-text",
"progress",
"json"
],
"jest": {
"config": {
"testMatch": ["**/lighthouse-core/test/audits/**/*-test.js"],
"setupFilesAfterEnv": ["./lighthouse-core/test/test-utils.js"],
"testEnvironment": "node",
"transform": {},
"collectCoverage": false
}
},
"mutate": [
"lighthouse-core/audits/**/*.js"
],
"testRunner": "jest",
"coverageAnalysis": "off"
}
4 changes: 2 additions & 2 deletions perf/package.json
Expand Up @@ -6,9 +6,9 @@
"ts-node": "~8.10.2"
},
"scripts": {
"postinstall": "npm run merge-config && npm run bootstrap",
"merge-config": "ts-node -p tasks/merge-config.ts",
"postinstall": "npm run merge-config && node ../node_modules/lerna/cli.js bootstrap --no-ci && npm run install-local-dependencies",
"install-local-dependencies": "ts-node -p tasks/install-local-dependencies.ts",
"bootstrap": "ts-node -p tasks/install.ts",
"test": "ts-node tasks/run-perf-tests.ts"
}
}
6 changes: 0 additions & 6 deletions perf/tasks/install-local-dependencies.ts

This file was deleted.

44 changes: 44 additions & 0 deletions perf/tasks/install.ts
@@ -0,0 +1,44 @@
import * as fs from 'fs';
import * as minimatch from 'minimatch';
import * as path from 'path';
import * as execa from 'execa';

const testRootDir = path.resolve(__dirname, '..', 'test');

installAll()
.then(() => console.log('Done'))
.catch((err) => {
console.error(err);
process.exit(1);
});

/**
* Installs all packages under the "test" directory, while respecting their preferred package manager (yarn vs npm 🙄)
*/
async function installAll() {
const globPattern = process.env.PERF_TEST_GLOB_PATTERN || '*';
const testDirs = fs.readdirSync(testRootDir).filter((testDir) => minimatch(testDir, globPattern));
if (testDirs.length) {
console.log(`Installing ${testDirs.join(', ')} (matched with glob pattern "${globPattern}")`);
} else {
console.warn(`No tests match glob expression ${globPattern}`);
}
await Promise.all(testDirs.map(install));
}

async function install(testDir: string) {
const strykerConfig = require(`../test/${testDir}/stryker.conf`);
const packageManager: string | undefined = strykerConfig.packageManager;
let command = 'npm';
let args: string[] = [];
if (packageManager === 'yarn') {
command = 'yarn';
args.push('install', '--frozen-lockfile');
} else if(fs.existsSync(path.resolve(testRootDir, testDir, 'package-lock.json'))) {
args.push('ci');
} else {
args.push('install');
}
console.log(`[${testDir}] ${command} ${args.join(' ')}`);
await execa(command, args, { cwd: path.resolve(testRootDir, testDir) });
}
10 changes: 5 additions & 5 deletions perf/tasks/merge-config.ts
@@ -1,16 +1,16 @@
import { promises as fs } from 'fs';
import path = require("path");
import path = require('path');

const testRootDir = path.resolve(__dirname, '..', 'test');
const configRootDir = path.resolve(__dirname, '..', 'config');

mergeConfiguration().catch(error => {
mergeConfiguration().catch((error) => {
console.error(error);
process.exitCode = 1;
});

async function mergeConfiguration() {
const testDirs = (await fs.readdir(testRootDir, { withFileTypes: true })).filter(testDir => testDir.isDirectory());
const testDirs = (await fs.readdir(testRootDir, { withFileTypes: true })).filter((testDir) => testDir.isDirectory());
for await (const testDir of testDirs) {
const configOverrideDir = path.resolve(configRootDir, testDir.name);
try {
Expand All @@ -21,7 +21,7 @@ async function mergeConfiguration() {
try {
const overrides = require(overridePackageFileName);
const original = require(path.resolve(testRootDir, testDir.name, 'package.json'));
await fs.writeFile(path.resolve(testRootDir, testDir.name, 'package.json'), JSON.stringify({ ...original, ...overrides }, null, 2))
await fs.writeFile(path.resolve(testRootDir, testDir.name, 'package.json'), JSON.stringify({ ...original, ...overrides }, null, 2));
} catch {
console.log(`Note: no overrides found at ${overridePackageFileName}`);
}
Expand All @@ -31,7 +31,7 @@ async function mergeConfiguration() {
console.log(`Note: no stryker.conf.json file ${overrideStrykerConfigFileName}`);
}
}
console.log(`✅ Merged config for ${testDir.name}`)
console.log(`✅ Merged config for ${testDir.name}`);
} catch {
console.log(`Note: no config override directory found at ${configOverrideDir}`);
}
Expand Down
45 changes: 29 additions & 16 deletions perf/tasks/run-perf-tests.ts
Expand Up @@ -9,16 +9,16 @@ const testRootDir = path.resolve(__dirname, '..', 'test');

runPerfTests()
.then(() => console.log('Done'))
.catch(err => {
.catch((err) => {
console.error(err);
process.exit(1);
});

async function runPerfTests() {
const globPattern = process.env.PERF_TEST_GLOB_PATTERN || '*';
const testDirs = fs.readdirSync(testRootDir).filter(testDir => minimatch(testDir, globPattern));
const testDirs = fs.readdirSync(testRootDir).filter((testDir) => minimatch(testDir, globPattern));
if (testDirs.length) {
console.log(`Running performance tests on ${testDirs.join(', ')} (matched with glob pattern "${globPattern}")`)
console.log(`Running performance tests on ${testDirs.join(', ')} (matched with glob pattern "${globPattern}")`);
} else {
console.warn(`No test files match glob expression ${globPattern}`);
}
Expand All @@ -32,24 +32,37 @@ async function runPerfTests() {

async function runTest(testDir: string) {
console.time(testDir);
await npx(['stryker', 'run'], testDir).pipe(
throttleTime(60000),
tap(logMessage => console.timeLog(testDir, 'last log message: ', logMessage))
).toPromise();
await runStryker(testDir)
.pipe(
throttleTime(60000),
tap((logMessage) => console.timeLog(testDir, 'last log message: ', logMessage))
)
.toPromise();
console.timeEnd(testDir);
}

function npx(args: string[], testDir: string): Observable<string> {
function runStryker(testDir: string): Observable<string> {
const strykerBin = require.resolve('../../packages/core/bin/stryker');
const args = [
'run',
'--plugins',
[
require.resolve('../../packages/mocha-runner'),
require.resolve('../../packages/karma-runner'),
require.resolve('../../packages/jest-runner'),
require.resolve('../../packages/jasmine-runner'),
require.resolve('../../packages/mocha-runner'),
require.resolve('../../packages/typescript-checker'),
].join(','),
];
const currentTestDir = path.resolve(testRootDir, testDir);
console.log(`Exec ${testDir} npx ${args.join(' ')}`);
console.log(`(${testDir}) exec "${strykerBin} ${args.join(' ')}"`);

return new Observable(observer => {
const testProcess = execa('npx', args, { timeout: 0, cwd: currentTestDir, stdio: 'pipe' });
return new Observable((observer) => {
const testProcess = execa(strykerBin, args, { timeout: 0, cwd: currentTestDir, stdio: 'pipe' });
let stderr = '';
testProcess.stderr?.on('data', chunk => stderr += chunk.toString());
testProcess.stdout?.on('data', chunk => observer.next(chunk.toString().trim()));
testProcess
.then(() => observer.complete())
.catch(error => observer.error(error));
testProcess.stderr?.on('data', (chunk) => (stderr += chunk.toString()));
testProcess.stdout?.on('data', (chunk) => observer.next(chunk.toString().trim()));
testProcess.then(() => observer.complete()).catch((error) => observer.error(error));
});
}
3 changes: 1 addition & 2 deletions perf/test/angular-cli/angular.json
Expand Up @@ -67,8 +67,7 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "FEWebwinkel:build",
"proxyConfig": "proxy.conf.json"
"browserTarget": "FEWebwinkel:build"
},
"configurations": {
"production": {
Expand Down