Skip to content

Commit eca29f5

Browse files
Rollup merge of rust-lang#86692 - dns2utf8:parallelize_rustdoc-gui_tests, r=GuillaumeGomez
Run rustdoc-gui tests in parallel I hid the passing tests and only show the failed ones in alphabetical order: ![image](https://user-images.githubusercontent.com/739070/123663020-84e63100-d825-11eb-9b35-0a8c30cd219c.png) Also this PR cuts down the execution time from ~40 to ~9 seconds
2 parents 40db258 + 7f2b52b commit eca29f5

File tree

1 file changed

+113
-13
lines changed

1 file changed

+113
-13
lines changed

src/tools/rustdoc-gui/tester.js

+113-13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// ```
66
const fs = require("fs");
77
const path = require("path");
8+
const os = require('os');
89
const {Options, runTest} = require('browser-ui-test');
910

1011
function showHelp() {
@@ -70,12 +71,49 @@ function parseOptions(args) {
7071
return null;
7172
}
7273

74+
/// Print single char status information without \n
75+
function char_printer(n_tests) {
76+
const max_per_line = 10;
77+
let current = 0;
78+
return {
79+
successful: function() {
80+
current += 1;
81+
if (current % max_per_line === 0) {
82+
process.stdout.write(`. (${current}/${n_tests})${os.EOL}`);
83+
} else {
84+
process.stdout.write(".");
85+
}
86+
},
87+
erroneous: function() {
88+
current += 1;
89+
if (current % max_per_line === 0) {
90+
process.stderr.write(`F (${current}/${n_tests})${os.EOL}`);
91+
} else {
92+
process.stderr.write("F");
93+
}
94+
},
95+
finish: function() {
96+
const spaces = " ".repeat(max_per_line - (current % max_per_line));
97+
process.stdout.write(`${spaces} (${current}/${n_tests})${os.EOL}${os.EOL}`);
98+
},
99+
};
100+
}
101+
102+
/// Sort array by .file_name property
103+
function by_filename(a, b) {
104+
return a.file_name - b.file_name;
105+
}
106+
73107
async function main(argv) {
74108
let opts = parseOptions(argv.slice(2));
75109
if (opts === null) {
76110
process.exit(1);
77111
}
78112

113+
// Print successful tests too
114+
let debug = false;
115+
// Run tests in sequentially
116+
let no_headless = false;
79117
const options = new Options();
80118
try {
81119
// This is more convenient that setting fields one by one.
@@ -84,13 +122,15 @@ async function main(argv) {
84122
"--variable", "DOC_PATH", opts["doc_folder"],
85123
];
86124
if (opts["debug"]) {
125+
debug = true;
87126
args.push("--debug");
88127
}
89128
if (opts["show_text"]) {
90129
args.push("--show-text");
91130
}
92131
if (opts["no_headless"]) {
93132
args.push("--no-headless");
133+
no_headless = true;
94134
}
95135
options.parseArguments(args);
96136
} catch (error) {
@@ -101,25 +141,85 @@ async function main(argv) {
101141
let failed = false;
102142
let files;
103143
if (opts["files"].length === 0) {
104-
files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml");
144+
files = fs.readdirSync(opts["tests_folder"]);
105145
} else {
106-
files = opts["files"].filter(file => path.extname(file) == ".goml");
146+
files = opts["files"];
147+
}
148+
files = files.filter(file => path.extname(file) == ".goml");
149+
if (files.length === 0) {
150+
console.error("rustdoc-gui: No test selected");
151+
process.exit(2);
107152
}
108-
109153
files.sort();
110-
for (var i = 0; i < files.length; ++i) {
111-
const testPath = path.join(opts["tests_folder"], files[i]);
112-
await runTest(testPath, options).then(out => {
113-
const [output, nb_failures] = out;
114-
console.log(output);
115-
if (nb_failures > 0) {
154+
155+
console.log(`Running ${files.length} rustdoc-gui tests...`);
156+
process.setMaxListeners(files.length + 1);
157+
let tests = [];
158+
let results = {
159+
successful: [],
160+
failed: [],
161+
errored: [],
162+
};
163+
const status_bar = char_printer(files.length);
164+
for (let i = 0; i < files.length; ++i) {
165+
const file_name = files[i];
166+
const testPath = path.join(opts["tests_folder"], file_name);
167+
tests.push(
168+
runTest(testPath, options)
169+
.then(out => {
170+
const [output, nb_failures] = out;
171+
results[nb_failures === 0 ? "successful" : "failed"].push({
172+
file_name: file_name,
173+
output: output,
174+
});
175+
if (nb_failures > 0) {
176+
status_bar.erroneous()
177+
failed = true;
178+
} else {
179+
status_bar.successful()
180+
}
181+
})
182+
.catch(err => {
183+
results.errored.push({
184+
file_name: file_name,
185+
output: err,
186+
});
187+
status_bar.erroneous();
116188
failed = true;
117-
}
118-
}).catch(err => {
119-
console.error(err);
120-
failed = true;
189+
})
190+
);
191+
if (no_headless) {
192+
await tests[i];
193+
}
194+
}
195+
if (!no_headless) {
196+
await Promise.all(tests);
197+
}
198+
status_bar.finish();
199+
200+
if (debug) {
201+
results.successful.sort(by_filename);
202+
results.successful.forEach(r => {
203+
console.log(r.output);
121204
});
122205
}
206+
207+
if (results.failed.length > 0) {
208+
console.log("");
209+
results.failed.sort(by_filename);
210+
results.failed.forEach(r => {
211+
console.log(r.output);
212+
});
213+
}
214+
if (results.errored.length > 0) {
215+
console.log(os.EOL);
216+
// print run errors on the bottom so developers see them better
217+
results.errored.sort(by_filename);
218+
results.errored.forEach(r => {
219+
console.error(r.output);
220+
});
221+
}
222+
123223
if (failed) {
124224
process.exit(1);
125225
}

0 commit comments

Comments
 (0)