Added parallel support for runtests-file

This commit is contained in:
Ron Buckton 2016-05-26 01:16:29 -07:00
parent f36ffb9103
commit 754bdccebe

View file

@ -245,7 +245,7 @@ var librarySourceMap = [
{ target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] },
{ target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] },
{ target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] },
// JavaScript + all host library
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
@ -749,7 +749,7 @@ function deleteTemporaryProjectOutput() {
}
}
function runTestsAndWriteOutput(file) {
function runTestsAndWriteOutput(file, defaultSubsets) {
cleanTestDirs();
var tests = process.env.test || process.env.tests || process.env.t;
var light = process.env.light || false;
@ -764,114 +764,231 @@ function runTestsAndWriteOutput(file) {
testTimeout = 100000;
}
var args = [];
args.push("-R", "tap");
args.push("--no-colors");
args.push("-t", testTimeout);
if (tests) {
args.push("-g", '"' + tests + '"');
var subsetRegexes;
var subsets;
if (defaultSubsets.length === 0) {
subsetRegexes = [tests];
subsets = [tests];
}
else {
subsets = tests ? tests.split("|") : defaultSubsets;
subsetRegexes = subsets.map(function (sub) { return "^" + sub + ".*$"; });
subsetRegexes.push("^(?!" + subsets.join("|") + ").*$");
subsets.push("other");
}
args.push(run);
var cmd = "mocha " + args.join(" ");
console.log(cmd);
var p = child_process.spawn(
process.platform === "win32" ? "cmd" : "/bin/sh",
process.platform === "win32" ? ["/c", cmd] : ["-c", cmd], {
windowsVerbatimArguments: true
});
var out = fs.createWriteStream(file);
var outFileNames = subsetRegexes.length !== 1 ? [] : undefined;
var tapRange = /^(\d+)\.\.(\d+)(?:$|\r\n?|\n)/;
var tapOk = /^ok\s/;
var tapNotOk = /^not\sok\s/;
var tapComment = /^#/;
var tapComment = /^#(?: (tests|pass|fail) (\d+)$)?/;
var typeError = /^\s+TypeError:/;
var debugError = /^\s+Error:\sDebug\sFailure\./;
var progress = new ProgressBar("Running tests...");
var expectedTestCount = 0;
var testCount = 0;
var failureCount = 0;
var successCount = 0;
var comments = [];
var typeErrorCount = 0;
var debugErrorCount = 0;
var rl = readline.createInterface({
input: p.stdout,
terminal: false
});
function updateProgress(percentComplete) {
progress.update(percentComplete,
/*foregroundColor*/ failureCount > 0
? "red"
: successCount === expectedTestCount
? "green"
: "cyan",
/*backgroundColor*/ "gray"
);
}
rl.on("line", function (line) {
var m = tapRange.exec(line);
if (m) {
expectedTestCount = parseInt(m[2]);
return;
}
if (tapOk.test(line)) {
out.write(line.replace(/^ok\s+\d+\s+/, "ok ") + os.EOL);
successCount++;
}
else if (tapNotOk.test(line)) {
out.write(line.replace(/^not\s+ok\s+\d+\s+/, "not ok ") + os.EOL);
failureCount++;
var progress = new ProgressBar();
var totalTypeErrorCount = 0;
var totalDebugErrorCount = 0;
var totalReportedTestCount = 0;
var totalReportedPassCount = 0;
var totalReportedFailCount = 0;
var counter = subsetRegexes.length;
var errorStatus;
subsetRegexes.forEach(function (subsetRegex, i) {
var expectedTestCount = 0;
var testCount = 0;
var failureCount = 0;
var successCount = 0;
var reportedTestCount = 0;
var reportedPassCount = 0;
var reportedFailCount = 0;
var comments = [];
var typeErrorCount = 0;
var debugErrorCount = 0;
var outFileName;
var outFile;
if (subsetRegexes.length === 1) {
outFile = out;
}
else {
out.write(line + os.EOL);
if (tapComment.test(line)) {
comments.push(line);
outFileName = path.join(os.tmpdir(), path.basename(file) + "." + i);
outFileNames[i] = outFileName;
outFile = fs.createWriteStream(outFileName);
}
var args = [];
args.push("-R", "tap");
args.push("--no-colors");
args.push("-t", testTimeout);
if (subsetRegex) {
args.push("-g", '"' + subsetRegex + '"');
}
args.push(run);
var cmd = "mocha " + args.join(" ");
if (subsetRegexes.length === 1) {
console.log(cmd);
}
updateProgress(0);
var p = child_process.spawn(
process.platform === "win32" ? "cmd" : "/bin/sh",
process.platform === "win32" ? ["/c", cmd] : ["-c", cmd], {
windowsVerbatimArguments: true,
env: { NODE_ENV: "development" }
});
var rl = readline.createInterface({
input: p.stdout,
terminal: false
});
var start;
var end;
rl.on("line", function (line) {
if (!start) start = Date.now();
var m = tapRange.exec(line);
if (m) {
expectedTestCount = parseInt(m[2]);
return;
}
else if (typeError.test(line)) {
typeErrorCount++;
if (tapOk.test(line)) {
outFile.write(line.replace(/^ok\s+\d+\s+/, "ok ") + os.EOL);
successCount++;
}
else if (debugError.test(line)) {
debugErrorCount++;
else if (tapNotOk.test(line)) {
outFile.write(line.replace(/^not\s+ok\s+\d+\s+/, "not ok ") + os.EOL);
failureCount++;
}
else {
m = tapComment.exec(line);
if (m) {
if (m[1] === "tests") {
end = Date.now();
reportedTestCount = parseInt(m[2]);
}
else if (m[1] === "pass") {
reportedPassCount = parseInt(m[2]);
}
else if (m[1] === "fail") {
reportedFailCount = parseInt(m[2]);
}
else {
outFile.write(line + os.EOL);
}
}
else {
outFile.write(line + os.EOL);
if (typeError.test(line)) {
typeErrorCount++;
}
else if (debugError.test(line)) {
debugErrorCount++;
}
}
return;
}
testCount++;
var percentComplete = testCount * 100 / expectedTestCount;
updateProgress(percentComplete);
});
p.on("exit", function (status) {
totalReportedTestCount += reportedTestCount;
totalReportedPassCount += reportedPassCount;
totalReportedFailCount += reportedFailCount;
totalTypeErrorCount += typeErrorCount;
totalDebugErrorCount += debugErrorCount;
var duration = end - start;
var summary =
"pass: " + reportedPassCount + "/" + reportedTestCount +
", duration: " + (duration / 1000).toFixed(2) + "s";
updateProgress(100, summary);
if (subsetRegexes.length !== 1) {
outFile.close();
}
if (status && !errorStatus) {
errorStatus = status;
}
counter--;
if (counter === 0) {
if (subsetRegexes.length !== 1) {
concatenate();
}
else {
finish();
}
}
});
function updateProgress(percentComplete, status) {
var title = status || (percentComplete < 100 ? "running..." : "done");
if (subsetRegexes.length !== 1) {
title = "[" + subsets[i] + "] " + title;
}
progress.update(percentComplete,
/*foregroundColor*/ failureCount > 0
? "red"
: successCount === expectedTestCount
? "green"
: "cyan",
/*backgroundColor*/ "gray",
title,
i
);
}
});
function concatenate() {
if (outFileNames.length > 0) {
var outFileName = outFileNames.shift();
var outFile = fs.createReadStream(outFileName);
outFile.pipe(out, { end: false });
outFile.on("end", function () {
fs.unlinkSync(outFileName);
concatenate();
});
return;
}
testCount++;
finish();
}
var percentComplete = testCount * 100 / expectedTestCount;
updateProgress(percentComplete);
});
function finish() {
out.write(
"# tests " + totalReportedTestCount + os.EOL +
"# pass " + totalReportedPassCount + os.EOL +
"# fail " + totalReportedFailCount + os.EOL);
console.log("# tests " + totalReportedTestCount);
console.log("# pass " + totalReportedPassCount);
console.log("# fail " + totalReportedFailCount);
p.on("exit", function (status) {
if (progress.visible) {
updateProgress(100);
process.stdout.write("done." + os.EOL);
if (totalTypeErrorCount) {
console.log("# type errors " + totalTypeErrorCount);
}
console.log(comments.join(os.EOL));
if (typeErrorCount) {
console.log("# type errors: %s", typeErrorCount);
}
if (debugErrorCount) {
console.log("# debug errors: %s", debugErrorCount);
if (totalDebugErrorCount) {
console.log("# debug errors " + totalDebugErrorCount);
}
deleteTemporaryProjectOutput();
if (status) {
fail("Process exited with code " + status);
if (totalReportedFailCount) {
fail("Test failures reported: " + totalReportedFailCount);
}
else {
complete();
}
});
}
}
function runConsoleTests(defaultReporter, defaultSubsets, dirty) {
@ -963,7 +1080,10 @@ task("runtests", ["build-rules", "tests", builtLocalDirectory], function() {
}, {async: true});
task("runtests-file", ["build-rules", "tests", builtLocalDirectory], function () {
runTestsAndWriteOutput("tests/baselines/local/testresults.tap");
runTestsAndWriteOutput("tests/baselines/local/testresults.tap", []);
}, { async: true });
task("runtests-file-parallel", ["build-rules", "tests", builtLocalDirectory], function () {
runTestsAndWriteOutput("tests/baselines/local/testresults.tap", ["conformance", "compiler", "Projects", "fourslash"]);
}, { async: true });
task("runtests-dirty", ["build-rules", "tests", builtLocalDirectory], function () {
runConsoleTests("mocha-fivemat-progress-reporter", [], /*dirty*/ true);
@ -1250,8 +1370,9 @@ task("lint-server", ["build-rules"], function() {
}
});
function ProgressBar(title) {
this.title = title;
function ProgressBar() {
this._progress = [];
this._lineCount = 0;
}
ProgressBar.prototype = {
progressChars: ["\u0020", "\u2591", "\u2592", "\u2593", "\u2588"],
@ -1280,7 +1401,9 @@ ProgressBar.prototype = {
},
reset: "\u001b[0m"
},
update: function (percentComplete, foregroundColor, backgroundColor) {
update: function (percentComplete, foregroundColor, backgroundColor, title, index) {
if (index === undefined) index = 0;
var progress = "";
for (var i = 0; i < 100; i += 4) {
progress += this.progressChars[Math.floor(Math.max(0, Math.min(4, percentComplete - i)))];
@ -1299,20 +1422,13 @@ ProgressBar.prototype = {
progress += this.colors.reset;
}
if (this._lastProgress !== progress || !this.visible) {
this._print(progress);
if (title) {
progress += " " + title;
}
},
hide: function () {
if (this.visible) {
this._savedProgress = this._lastProgress;
this.clear();
}
},
show: function () {
if (this._savedProgress && !this.visible) {
this._print(this._savedProgress);
this._savedProgress = undefined;
if (this._progress[index] !== progress) {
this._progress[index] = progress;
this._print(index);
}
},
clear: function () {
@ -1323,12 +1439,22 @@ ProgressBar.prototype = {
this.visible = false;
}
},
_print: function (progress) {
readline.moveCursor(process.stdout, -process.stdout.columns, 0);
process.stdout.write(this.title ? progress + " " + this.title : progress);
readline.clearLine(process.stdout, 1);
this._lastProgress = progress;
this.visible = true;
_print: function (index) {
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
var lineCount = 0;
for (var i = 0; i < this._progress.length; i++) {
if (i === index) {
readline.clearLine(process.stdout, 1);
process.stdout.write(this._progress[i] + os.EOL);
}
else {
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
}
lineCount++;
}
this._lineCount = lineCount;
}
};