data-provider-temporary
Version:
Library that helps with server-to-client synchronization of data
116 lines (87 loc) • 3.6 kB
JavaScript
;
const fs = require('fs'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const getCacheFilePath = require('jest-haste-map').getCacheFilePath;const FAIL = 0;const SUCCESS = 1;
class TestSequencer {
constructor() {
this._cache = new Map();
}
_getCachePath(context) {const
config = context.config;
return getCacheFilePath(config.cacheDirectory, 'perf-cache-' + config.name);
}
_getCache(test) {const
context = test.context;
if (!this._cache.has(context) && context.config.cache) {
const cachePath = this._getCachePath(context);
if (fs.existsSync(cachePath)) {
try {
this._cache.set(
context,
JSON.parse(fs.readFileSync(cachePath, 'utf8')));
} catch (e) {}
}
}
let cache = this._cache.get(context);
if (!cache) {
cache = {};
this._cache.set(context, cache);
}
return cache;
}
// When running more tests than we have workers available, sort the tests
// by size - big test files usually take longer to complete, so we run
// them first in an effort to minimize worker idle time at the end of a
// long test run.
//
// After a test run we store the time it took to run a test and on
// subsequent runs we use that to run the slowest tests first, yielding the
// fastest results.
sort(tests) {
const stats = {};
const fileSize = test =>
stats[test.path] || (stats[test.path] = fs.statSync(test.path).size);
const hasFailed = (cache, test) =>
cache[test.path] && cache[test.path][0] === FAIL;
const time = (cache, test) => cache[test.path] && cache[test.path][1];
tests.forEach(test => test.duration = time(this._getCache(test), test));
return tests.sort((testA, testB) => {
const cacheA = this._getCache(testA);
const cacheB = this._getCache(testB);
const failedA = hasFailed(cacheA, testA);
const failedB = hasFailed(cacheB, testB);
const hasTimeA = testA.duration != null;
if (failedA !== failedB) {
return failedA ? -1 : 1;
} else if (hasTimeA != (testB.duration != null)) {
// Check if only one of two tests has timing information
return hasTimeA != null ? 1 : -1;
} else if (testA.duration != null && testB.duration != null) {
return testA.duration < testB.duration ? 1 : -1;
} else {
return fileSize(testA) < fileSize(testB) ? 1 : -1;
}
});
}
cacheResults(tests, results) {
const map = Object.create(null);
tests.forEach(test => map[test.path] = test);
results.testResults.forEach(testResult => {
if (testResult && map[testResult.testFilePath] && !testResult.skipped) {
const cache = this._getCache(map[testResult.testFilePath]);
const perf = testResult.perfStats;
cache[testResult.testFilePath] = [
testResult.numFailingTests ? FAIL : SUCCESS,
perf.end - perf.start || 0];
}
});
this._cache.forEach((cache, context) =>
fs.writeFileSync(this._getCachePath(context), JSON.stringify(cache)));
}}
module.exports = TestSequencer;