Revert "Skip costly tests" (#35197)

* Revert "Skip costly tests"

* fix package.json format
This commit is contained in:
Nathan Shively-Sanders 2019-11-19 12:59:09 -08:00 committed by GitHub
parent af0d5d33b6
commit 0bbeab6e61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 5 additions and 147 deletions

View file

@ -477,7 +477,6 @@ task("runtests-parallel").flags = {
" --workers=<number>": "The number of parallel workers to use.",
" --timeout=<ms>": "Overrides the default test timeout.",
" --built": "Compile using the built version of the compiler.",
" --skipPercent=<number>": "Skip expensive tests with <percent> chance to miss an edit. Default 5%.",
" --shards": "Total number of shards running tests (default: 1)",
" --shardId": "1-based ID of this shard (default: 1)",
};

View file

@ -92,7 +92,6 @@
"prex": "^0.4.3",
"q": "latest",
"remove-internal": "^2.9.2",
"simple-git": "^1.113.0",
"source-map-support": "latest",
"through2": "latest",
"travis-fold": "latest",
@ -117,8 +116,7 @@
"lint:ci": "gulp lint --ci",
"lint:compiler": "gulp lint-compiler",
"lint:scripts": "gulp lint-scripts",
"setup-hooks": "node scripts/link-hooks.js",
"update-costly-tests": "node scripts/costly-tests.js"
"setup-hooks": "node scripts/link-hooks.js"
},
"browser": {
"fs": false,

View file

@ -14,7 +14,6 @@ module.exports = minimist(process.argv.slice(2), {
"ru": "runners", "runner": "runners",
"r": "reporter",
"c": "colors", "color": "colors",
"skip-percent": "skipPercent",
"skippercent": "skipPercent",
"w": "workers",
"f": "fix"

View file

@ -31,7 +31,6 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
const inspect = cmdLineOptions.inspect;
const runners = cmdLineOptions.runners;
const light = cmdLineOptions.light;
const skipPercent = process.env.CI === "true" ? 0 : cmdLineOptions.skipPercent;
const stackTraceLimit = cmdLineOptions.stackTraceLimit;
const testConfigFile = "test.config";
const failed = cmdLineOptions.failed;
@ -65,8 +64,8 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
testTimeout = 400000;
}
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || skipPercent !== undefined || shards || shardId) {
writeTestConfigFile(tests, runners, light, skipPercent, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId);
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) {
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId);
}
const colors = cmdLineOptions.colors;
@ -161,7 +160,6 @@ exports.cleanTestDirs = cleanTestDirs;
* @param {string} tests
* @param {string} runners
* @param {boolean} light
* @param {string} skipPercent
* @param {string} [taskConfigsFolder]
* @param {string | number} [workerCount]
* @param {string} [stackTraceLimit]
@ -170,12 +168,11 @@ exports.cleanTestDirs = cleanTestDirs;
* @param {number | undefined} [shards]
* @param {number | undefined} [shardId]
*/
function writeTestConfigFile(tests, runners, light, skipPercent, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed, shards, shardId) {
function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed, shards, shardId) {
const testConfigContents = JSON.stringify({
test: tests ? [tests] : undefined,
runners: runners ? runners.split(",") : undefined,
light,
skipPercent,
workerCount,
stackTraceLimit,
taskConfigsFolder,

View file

@ -1,103 +0,0 @@
// @ts-check
const fs = require("fs");
const git = require('simple-git/promise')('.')
const readline = require('readline')
/** @typedef {{ [s: string]: number}} Histogram */
async function main() {
/** @type {Histogram} */
const edits = Object.create(null)
/** @type {Histogram} */
const perf = JSON.parse(fs.readFileSync('.parallelperf.json', 'utf8'))
await collectCommits(git, "release-2.3", "master", /*author*/ undefined, files => fillMap(files, edits))
const totalTime = Object.values(perf).reduce((n,m) => n + m, 0)
const untouched = Object.values(perf).length - Object.values(edits).length
const totalEdits = Object.values(edits).reduce((n,m) => n + m, 0) + untouched + Object.values(edits).length
let i = 0
/** @type {{ name: string, time: number, edits: number, cost: number }[]} */
let data = []
for (const k in perf) {
const otherk = k.replace(/tsrunner-[a-z-]+?:\/\//, '')
const percentTime = perf[k] / totalTime
const percentHits = (1 + (edits[otherk] || 0)) / totalEdits
const cost = 5 + Math.log(percentTime / percentHits)
data.push({ name: otherk, time: perf[k], edits: 1 + (edits[otherk] || 0), cost})
if (edits[otherk])
i++
}
const output = {
totalTime,
totalEdits,
data: data.sort((x,y) => y.cost - x.cost).map(x => ({ ...x, cost: x.cost.toFixed(2) }))
}
fs.writeFileSync('tests/.test-cost.json', JSON.stringify(output), 'utf8')
}
main().catch(e => {
console.log(e);
process.exit(1);
})
/**
* @param {string[]} files
* @param {Histogram} histogram
*/
function fillMap(files, histogram) {
// keep edits to test cases (but not /users), and not file moves
const tests = files.filter(f => f.startsWith('tests/cases/') && !f.startsWith('tests/cases/user') && !/=>/.test(f))
for (const test of tests) {
histogram[test] = (histogram[test] || 0) + 1
}
}
/**
* @param {string} s
*/
function isSquashMergeMessage(s) {
return /\(#[0-9]+\)$/.test(s)
}
/**
* @param {string} s
*/
function isMergeCommit(s) {
return /Merge pull request #[0-9]+/.test(s)
}
/**
* @param {string} s
*/
function parseFiles(s) {
const lines = s.split('\n')
// Note that slice(2) only works for merge commits, which have an empty newline after the title
return lines.slice(2, lines.length - 2).map(line => line.split("|")[0].trim())
}
/**
* @param {import('simple-git/promise').SimpleGit} git
* @param {string} from
* @param {string} to
* @param {string | undefined} author - only include commits from this author
* @param {(files: string[]) => void} update
*/
async function collectCommits(git, from, to, author, update) {
let i = 0
for (const commit of (await git.log({ from, to })).all) {
i++
if ((!author || commit.author_name === author) && isMergeCommit(commit.message) || isSquashMergeMessage(commit.message)) {
readline.clearLine(process.stdout, /*left*/ -1)
readline.cursorTo(process.stdout, 0)
process.stdout.write(i + ": " + commit.date)
const files = parseFiles(await git.show([commit.hash, "--stat=1000,960,40", "--pretty=oneline"]))
update(files)
}
}
}

View file

@ -11,7 +11,7 @@ namespace Harness.Parallel.Host {
const isatty = tty.isatty(1) && tty.isatty(2);
const path = require("path") as typeof import("path");
const { fork } = require("child_process") as typeof import("child_process");
const { statSync, readFileSync } = require("fs") as typeof import("fs");
const { statSync } = require("fs") as typeof import("fs");
// NOTE: paths for module and types for FailedTestReporter _do not_ line up due to our use of --outFile for run.js
const FailedTestReporter = require(path.resolve(__dirname, "../../scripts/failed-tests")) as typeof import("../../../scripts/failed-tests");
@ -186,31 +186,6 @@ namespace Harness.Parallel.Host {
return `tsrunner-${runner}://${test}`;
}
function skipCostlyTests(tasks: Task[]) {
if (statSync("tests/.test-cost.json")) {
const costs = JSON.parse(readFileSync("tests/.test-cost.json", "utf8")) as {
totalTime: number,
totalEdits: number,
data: { name: string, time: number, edits: number, costs: number }[]
};
let skippedEdits = 0;
let skippedTime = 0;
const skippedTests = new Set<string>();
let i = 0;
for (; i < costs.data.length && (skippedEdits / costs.totalEdits) < (skipPercent / 100); i++) {
skippedEdits += costs.data[i].edits;
skippedTime += costs.data[i].time;
skippedTests.add(costs.data[i].name);
}
console.log(`Skipped ${i} expensive tests; estimated time savings of ${(skippedTime / costs.totalTime * 100).toFixed(2)}% with --skipPercent=${skipPercent.toFixed(2)} chance of missing a test.`);
return tasks.filter(t => !skippedTests.has(t.file));
}
else {
console.log("No cost analysis discovered.");
return tasks;
}
}
function startDelayed(perfData: { [testHash: string]: number } | undefined, totalCost: number) {
console.log(`Discovered ${tasks.length} unittest suites` + (newTasks.length ? ` and ${newTasks.length} new suites.` : "."));
console.log("Discovering runner-based tests...");
@ -250,7 +225,6 @@ namespace Harness.Parallel.Host {
}
tasks.sort((a, b) => a.size - b.size);
tasks = tasks.concat(newTasks);
tasks = skipCostlyTests(tasks);
const batchCount = workerCount;
const packfraction = 0.9;
const chunkSize = 1000; // ~1KB or 1s for sending batches near the end of a test

View file

@ -67,7 +67,6 @@ let runUnitTests: boolean | undefined;
let stackTraceLimit: number | "full" | undefined;
let noColors = false;
let keepFailed = false;
let skipPercent = 5;
interface TestConfig {
light?: boolean;
@ -81,7 +80,6 @@ interface TestConfig {
noColors?: boolean;
timeout?: number;
keepFailed?: boolean;
skipPercent?: number;
shardId?: number;
shards?: number;
}
@ -115,9 +113,6 @@ function handleTestConfig() {
if (testConfig.keepFailed) {
keepFailed = true;
}
if (testConfig.skipPercent !== undefined) {
skipPercent = testConfig.skipPercent;
}
if (testConfig.shardId) {
shardId = testConfig.shardId;
}

File diff suppressed because one or more lines are too long