tachometer
Version:
Web benchmark runner
209 lines • 7.69 kB
JavaScript
/**
* @license
* Copyright (c) 2019 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt The complete set of authors may be found
* at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
* be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
* Google as part of the polymer project is also subject to an additional IP
* rights grant found at http://polymer.github.io/PATENTS.txt
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeBackSchemaIfNeeded = exports.parseConfigFile = exports.defaultWindowHeight = exports.defaultWindowWidth = void 0;
const fsExtra = require("fs-extra");
const jsonschema = require("jsonschema");
const browser_1 = require("./browser");
const config_1 = require("./config");
const defaults = require("./defaults");
const util_1 = require("./util");
exports.defaultWindowWidth = 1024;
exports.defaultWindowHeight = 768;
/**
* Validate the given JSON object parsed from a config file, and expand it into
* a fully specified configuration.
*/
async function parseConfigFile(parsedJson) {
const schema = require('../config.schema.json');
const result = jsonschema.validate(parsedJson, schema, { propertyName: 'config' });
if (result.errors.length > 0) {
throw new Error(result.errors[0].toString());
}
const validated = parsedJson;
const root = validated.root || '.';
const benchmarks = [];
for (const benchmark of validated.benchmarks) {
for (const expanded of applyExpansions(benchmark)) {
benchmarks.push(applyDefaults(await parseBenchmark(expanded, root)));
}
}
return {
root,
sampleSize: validated.sampleSize,
timeout: validated.timeout,
horizons: validated.horizons !== undefined ?
config_1.parseHorizons(validated.horizons) :
undefined,
benchmarks,
resolveBareModules: validated.resolveBareModules,
};
}
exports.parseConfigFile = parseConfigFile;
async function parseBenchmark(benchmark, root) {
const spec = {};
if (benchmark.name !== undefined) {
spec.name = benchmark.name;
}
if (benchmark.browser !== undefined) {
let browser;
if (typeof benchmark.browser === 'string') {
browser = Object.assign(Object.assign({}, browser_1.parseBrowserConfigString(benchmark.browser)), { windowSize: {
width: exports.defaultWindowWidth,
height: exports.defaultWindowHeight,
} });
}
else {
browser = parseBrowserObject(benchmark.browser);
}
browser_1.validateBrowserConfig(browser);
spec.browser = browser;
}
if (benchmark.measurement !== undefined) {
spec.measurement = benchmark.measurement;
}
if (spec.measurement === 'global' &&
benchmark.measurementExpression !== undefined) {
spec.measurementExpression = benchmark.measurementExpression;
}
const url = benchmark.url;
if (url !== undefined) {
if (util_1.isHttpUrl(url)) {
spec.url = {
kind: 'remote',
url,
};
}
else {
let urlPath, queryString;
const q = url.indexOf('?');
if (q !== -1) {
urlPath = url.substring(0, q);
queryString = url.substring(q);
}
else {
urlPath = url;
queryString = '';
}
spec.url = {
kind: 'local',
urlPath: await config_1.urlFromLocalPath(root, urlPath),
queryString,
};
if (benchmark.packageVersions !== undefined) {
spec.url.version = {
label: benchmark.packageVersions.label,
dependencyOverrides: benchmark.packageVersions.dependencies,
};
}
}
}
return spec;
}
function parseBrowserObject(config) {
const parsed = {
name: config.name,
headless: ('headless' in config && config.headless) || false,
windowSize: ('windowSize' in config && config.windowSize) || {
width: exports.defaultWindowWidth,
height: exports.defaultWindowHeight,
},
};
if ('cpuThrottlingRate' in config) {
parsed.cpuThrottlingRate = config.cpuThrottlingRate;
}
if (config.remoteUrl) {
parsed.remoteUrl = config.remoteUrl;
}
if ('binary' in config && config.binary) {
parsed.binary = config.binary;
}
if ('addArguments' in config && config.addArguments) {
parsed.addArguments = config.addArguments;
}
if ('removeArguments' in config && config.removeArguments) {
parsed.removeArguments = config.removeArguments;
}
if ('preferences' in config && config.preferences) {
parsed.preferences = config.preferences;
}
return parsed;
}
function applyExpansions(bench) {
if (bench.expand === undefined || bench.expand.length === 0) {
return [bench];
}
const expanded = [];
for (const expansion of bench.expand) {
for (const expandedBench of applyExpansions(expansion)) {
expanded.push(Object.assign(Object.assign({}, bench), expandedBench));
}
}
return expanded;
}
function applyDefaults(partialSpec) {
const url = partialSpec.url;
let { name, measurement, browser } = partialSpec;
if (url === undefined) {
// Note we can't validate this with jsonschema, because we only need to
// ensure we have a URL after recursive expansion; so at any given level
// the URL could be optional.
throw new Error('No URL specified');
}
if (url.kind === 'remote') {
if (name === undefined) {
name = url.url;
}
}
else {
if (name === undefined) {
name = url.urlPath + url.queryString;
}
}
if (browser === undefined) {
browser = {
name: defaults.browserName,
headless: false,
windowSize: {
width: exports.defaultWindowWidth,
height: exports.defaultWindowHeight,
},
};
}
if (measurement === undefined) {
measurement = defaults.measurement(url);
}
const spec = { name, url, browser, measurement };
if (measurement === 'global') {
if (partialSpec.measurementExpression === undefined) {
spec.measurementExpression = defaults.measurementExpression;
}
else {
spec.measurementExpression = partialSpec.measurementExpression;
}
}
return spec;
}
async function writeBackSchemaIfNeeded(rawConfigObj, configFile) {
// Add the $schema field to the original config file if it's absent.
// We only want to do this if the file validated though, so we don't mutate
// a file that's not actually a tachometer config file.
if (!('$schema' in rawConfigObj)) {
const $schema = 'https://raw.githubusercontent.com/Polymer/tachometer/master/config.schema.json';
// Extra IDE features can be activated if the config file has a schema.
const withSchema = Object.assign({ $schema }, rawConfigObj);
const contents = JSON.stringify(withSchema, null, 2);
await fsExtra.writeFile(configFile, contents, { encoding: 'utf-8' });
}
}
exports.writeBackSchemaIfNeeded = writeBackSchemaIfNeeded;
//# sourceMappingURL=configfile.js.map
;