]>
Commit | Line | Data |
---|---|---|
6a06907d XL |
1 | // This package needs to be install: |
2 | // | |
3 | // ``` | |
4 | // npm install browser-ui-test | |
5 | // ``` | |
94222f64 | 6 | |
17df50a5 XL |
7 | const fs = require("fs"); |
8 | const path = require("path"); | |
94222f64 | 9 | const os = require('os'); |
6a06907d XL |
10 | const {Options, runTest} = require('browser-ui-test'); |
11 | ||
12 | function showHelp() { | |
13 | console.log("rustdoc-js options:"); | |
14 | console.log(" --doc-folder [PATH] : location of the generated doc folder"); | |
136023e0 XL |
15 | console.log(" --file [PATH] : file to run (can be repeated)"); |
16 | console.log(" --debug : show extra information about script run"); | |
17 | console.log(" --show-text : render font in pages"); | |
18 | console.log(" --no-headless : disable headless mode"); | |
923072b8 | 19 | console.log(" --no-sandbox : disable sandbox mode"); |
6a06907d | 20 | console.log(" --help : show this message then quit"); |
17df50a5 | 21 | console.log(" --tests-folder [PATH] : location of the .GOML tests folder"); |
94222f64 | 22 | console.log(" --jobs [NUMBER] : number of threads to run tests on"); |
923072b8 | 23 | console.log(" --executable-path [PATH] : path of the browser's executable to be used"); |
94222f64 XL |
24 | } |
25 | ||
26 | function isNumeric(s) { | |
27 | return /^\d+$/.test(s); | |
6a06907d XL |
28 | } |
29 | ||
30 | function parseOptions(args) { | |
31 | var opts = { | |
32 | "doc_folder": "", | |
17df50a5 | 33 | "tests_folder": "", |
136023e0 XL |
34 | "files": [], |
35 | "debug": false, | |
36 | "show_text": false, | |
37 | "no_headless": false, | |
94222f64 | 38 | "jobs": -1, |
923072b8 FG |
39 | "executable_path": null, |
40 | "no_sandbox": false, | |
6a06907d XL |
41 | }; |
42 | var correspondances = { | |
43 | "--doc-folder": "doc_folder", | |
17df50a5 | 44 | "--tests-folder": "tests_folder", |
136023e0 XL |
45 | "--debug": "debug", |
46 | "--show-text": "show_text", | |
47 | "--no-headless": "no_headless", | |
923072b8 FG |
48 | "--executable-path": "executable_path", |
49 | "--no-sandbox": "no_sandbox", | |
6a06907d XL |
50 | }; |
51 | ||
52 | for (var i = 0; i < args.length; ++i) { | |
53 | if (args[i] === "--doc-folder" | |
136023e0 | 54 | || args[i] === "--tests-folder" |
94222f64 | 55 | || args[i] === "--file" |
923072b8 FG |
56 | || args[i] === "--jobs" |
57 | || args[i] === "--executable-path") { | |
6a06907d XL |
58 | i += 1; |
59 | if (i >= args.length) { | |
60 | console.log("Missing argument after `" + args[i - 1] + "` option."); | |
61 | return null; | |
62 | } | |
94222f64 XL |
63 | if (args[i - 1] === "--jobs") { |
64 | if (!isNumeric(args[i])) { | |
65 | console.log( | |
66 | "`--jobs` option expects a positive number, found `" + args[i] + "`"); | |
67 | return null; | |
68 | } | |
69 | opts["jobs"] = parseInt(args[i]); | |
70 | } else if (args[i - 1] !== "--file") { | |
136023e0 XL |
71 | opts[correspondances[args[i - 1]]] = args[i]; |
72 | } else { | |
73 | opts["files"].push(args[i]); | |
74 | } | |
6a06907d XL |
75 | } else if (args[i] === "--help") { |
76 | showHelp(); | |
77 | process.exit(0); | |
923072b8 FG |
78 | } else if (args[i] === "--no-sandbox") { |
79 | console.log("`--no-sandbox` is being used. Be very careful!"); | |
80 | opts[correspondances[args[i]]] = true; | |
136023e0 XL |
81 | } else if (correspondances[args[i]]) { |
82 | opts[correspondances[args[i]]] = true; | |
6a06907d XL |
83 | } else { |
84 | console.log("Unknown option `" + args[i] + "`."); | |
85 | console.log("Use `--help` to see the list of options"); | |
86 | return null; | |
87 | } | |
88 | } | |
17df50a5 XL |
89 | if (opts["tests_folder"].length < 1) { |
90 | console.log("Missing `--tests-folder` option."); | |
6a06907d XL |
91 | } else if (opts["doc_folder"].length < 1) { |
92 | console.log("Missing `--doc-folder` option."); | |
93 | } else { | |
94 | return opts; | |
95 | } | |
96 | return null; | |
97 | } | |
98 | ||
94222f64 XL |
99 | /// Print single char status information without \n |
100 | function char_printer(n_tests) { | |
101 | const max_per_line = 10; | |
102 | let current = 0; | |
103 | return { | |
104 | successful: function() { | |
105 | current += 1; | |
106 | if (current % max_per_line === 0) { | |
107 | process.stdout.write(`. (${current}/${n_tests})${os.EOL}`); | |
108 | } else { | |
109 | process.stdout.write("."); | |
110 | } | |
111 | }, | |
112 | erroneous: function() { | |
113 | current += 1; | |
114 | if (current % max_per_line === 0) { | |
115 | process.stderr.write(`F (${current}/${n_tests})${os.EOL}`); | |
116 | } else { | |
117 | process.stderr.write("F"); | |
118 | } | |
119 | }, | |
120 | finish: function() { | |
121 | if (current % max_per_line === 0) { | |
122 | // Don't output if we are already at a matching line end | |
123 | console.log(""); | |
124 | } else { | |
125 | const spaces = " ".repeat(max_per_line - (current % max_per_line)); | |
126 | process.stdout.write(`${spaces} (${current}/${n_tests})${os.EOL}${os.EOL}`); | |
127 | } | |
128 | }, | |
129 | }; | |
130 | } | |
131 | ||
132 | /// Sort array by .file_name property | |
133 | function by_filename(a, b) { | |
134 | return a.file_name - b.file_name; | |
135 | } | |
136 | ||
17df50a5 XL |
137 | async function main(argv) { |
138 | let opts = parseOptions(argv.slice(2)); | |
6a06907d XL |
139 | if (opts === null) { |
140 | process.exit(1); | |
141 | } | |
142 | ||
94222f64 XL |
143 | // Print successful tests too |
144 | let debug = false; | |
145 | // Run tests in sequentially | |
a2a8927a | 146 | let headless = true; |
6a06907d XL |
147 | const options = new Options(); |
148 | try { | |
149 | // This is more convenient that setting fields one by one. | |
136023e0 | 150 | let args = [ |
04454e1e | 151 | "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error", |
136023e0 XL |
152 | ]; |
153 | if (opts["debug"]) { | |
94222f64 | 154 | debug = true; |
136023e0 XL |
155 | args.push("--debug"); |
156 | } | |
157 | if (opts["show_text"]) { | |
158 | args.push("--show-text"); | |
159 | } | |
923072b8 FG |
160 | if (opts["no_sandbox"]) { |
161 | args.push("--no-sandbox"); | |
162 | } | |
136023e0 XL |
163 | if (opts["no_headless"]) { |
164 | args.push("--no-headless"); | |
a2a8927a | 165 | headless = false; |
136023e0 | 166 | } |
923072b8 FG |
167 | if (opts["executable_path"] !== null) { |
168 | args.push("--executable-path"); | |
169 | args.push(opts["executable_path"]); | |
170 | } | |
136023e0 | 171 | options.parseArguments(args); |
6a06907d XL |
172 | } catch (error) { |
173 | console.error(`invalid argument: ${error}`); | |
174 | process.exit(1); | |
175 | } | |
176 | ||
17df50a5 | 177 | let failed = false; |
136023e0 XL |
178 | let files; |
179 | if (opts["files"].length === 0) { | |
94222f64 | 180 | files = fs.readdirSync(opts["tests_folder"]); |
136023e0 | 181 | } else { |
94222f64 XL |
182 | files = opts["files"]; |
183 | } | |
184 | files = files.filter(file => path.extname(file) == ".goml"); | |
185 | if (files.length === 0) { | |
186 | console.error("rustdoc-gui: No test selected"); | |
187 | process.exit(2); | |
136023e0 | 188 | } |
17df50a5 | 189 | files.sort(); |
94222f64 | 190 | |
a2a8927a XL |
191 | if (!headless) { |
192 | opts["jobs"] = 1; | |
193 | console.log("`--no-headless` option is active, disabling concurrency for running tests."); | |
194 | } | |
195 | ||
c295e0f8 | 196 | console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`); |
94222f64 XL |
197 | |
198 | if (opts["jobs"] < 1) { | |
199 | process.setMaxListeners(files.length + 1); | |
a2a8927a | 200 | } else if (headless) { |
94222f64 XL |
201 | process.setMaxListeners(opts["jobs"] + 1); |
202 | } | |
203 | ||
f2b60f7d FG |
204 | // We catch this "event" to display a nicer message in case of unexpected exit (because of a |
205 | // missing `--no-sandbox`). | |
206 | const exitHandling = (code) => { | |
207 | if (!opts["no_sandbox"]) { | |
208 | console.log(""); | |
209 | console.log( | |
210 | "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \ | |
211 | --no-sandbox` at the end. For example: `x.py test src/test/rustdoc-gui --test-args --no-sandbox`"); | |
212 | console.log(""); | |
213 | } | |
214 | }; | |
215 | process.on('exit', exitHandling); | |
216 | ||
94222f64 XL |
217 | const tests_queue = []; |
218 | let results = { | |
219 | successful: [], | |
220 | failed: [], | |
221 | errored: [], | |
222 | }; | |
223 | const status_bar = char_printer(files.length); | |
224 | for (let i = 0; i < files.length; ++i) { | |
225 | const file_name = files[i]; | |
226 | const testPath = path.join(opts["tests_folder"], file_name); | |
227 | const callback = runTest(testPath, options) | |
228 | .then(out => { | |
229 | const [output, nb_failures] = out; | |
230 | results[nb_failures === 0 ? "successful" : "failed"].push({ | |
3c0e092e | 231 | file_name: testPath, |
94222f64 XL |
232 | output: output, |
233 | }); | |
234 | if (nb_failures > 0) { | |
235 | status_bar.erroneous(); | |
236 | failed = true; | |
237 | } else { | |
238 | status_bar.successful(); | |
239 | } | |
240 | }) | |
241 | .catch(err => { | |
242 | results.errored.push({ | |
3c0e092e | 243 | file_name: testPath + file_name, |
94222f64 XL |
244 | output: err, |
245 | }); | |
246 | status_bar.erroneous(); | |
17df50a5 | 247 | failed = true; |
94222f64 XL |
248 | }) |
249 | .finally(() => { | |
250 | // We now remove the promise from the tests_queue. | |
251 | tests_queue.splice(tests_queue.indexOf(callback), 1); | |
252 | }); | |
253 | tests_queue.push(callback); | |
a2a8927a | 254 | if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) { |
94222f64 XL |
255 | await Promise.race(tests_queue); |
256 | } | |
257 | } | |
a2a8927a | 258 | if (tests_queue.length > 0) { |
94222f64 XL |
259 | await Promise.all(tests_queue); |
260 | } | |
261 | status_bar.finish(); | |
262 | ||
f2b60f7d FG |
263 | // We don't need this listener anymore. |
264 | process.removeListener("exit", exitHandling); | |
265 | ||
94222f64 XL |
266 | if (debug) { |
267 | results.successful.sort(by_filename); | |
268 | results.successful.forEach(r => { | |
269 | console.log(r.output); | |
270 | }); | |
271 | } | |
272 | ||
273 | if (results.failed.length > 0) { | |
274 | console.log(""); | |
275 | results.failed.sort(by_filename); | |
276 | results.failed.forEach(r => { | |
3c0e092e | 277 | console.log(r.file_name, r.output); |
94222f64 XL |
278 | }); |
279 | } | |
280 | if (results.errored.length > 0) { | |
281 | console.log(os.EOL); | |
282 | // print run errors on the bottom so developers see them better | |
283 | results.errored.sort(by_filename); | |
284 | results.errored.forEach(r => { | |
3c0e092e | 285 | console.error(r.file_name, r.output); |
17df50a5 XL |
286 | }); |
287 | } | |
94222f64 | 288 | |
17df50a5 | 289 | if (failed) { |
6a06907d | 290 | process.exit(1); |
17df50a5 | 291 | } |
6a06907d XL |
292 | } |
293 | ||
294 | main(process.argv); |