OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /** The default pipeline code for running a test file. */ | |
6 library pipeline; | |
7 import 'dart:async'; | |
8 import 'dart:io'; | |
9 import 'dart:isolate'; | |
10 import 'dart:math'; | |
11 part 'pipeline_utils.dart'; | |
12 | |
13 /** | |
14 * The configuration passed in to the pipeline runner; this essentially | |
15 * contains all the command line arguments passded to testrunner plus some | |
16 * synthesized ones. | |
17 */ | |
18 Map config; | |
19 | |
20 /** Paths to the various generated temporary files. */ | |
21 String tempDartFile = null; | |
22 String tempHtmlFile = null; | |
23 String tempChildDartFile = null; | |
24 String tempJsFile = null; | |
25 String tempChildJsFile = null; | |
26 | |
27 /** | |
28 * Path to the Dart script file referenced from the HTML wrapper (or | |
29 * that is compiled to a Javascript file referenced from the HTML wrapper). | |
30 */ | |
31 String sourceFile = null; | |
32 | |
33 /** Path to the script file referenced from the HTML wrapper (Dart or JS). */ | |
34 String scriptFile = null; | |
35 | |
36 /** MIME type of the script. */ | |
37 String scriptType; | |
38 | |
39 /** Process id for the HTTP server. */ | |
40 int serverId; | |
41 | |
42 /** Port used by HTTP server. */ | |
43 int serverPort; | |
44 | |
45 /** Root directory for static files used by HTTP server. */ | |
46 String serverRoot; | |
47 | |
48 /** Path of the HTTP server script. */ | |
49 String serverPath; | |
50 | |
51 /** Number of attempts we will make to start the HTTP server. */ | |
52 const int MAX_SERVER_TRIES = 10; | |
53 | |
54 /** Pipeline output. */ | |
55 List stdout; | |
56 | |
57 /** Pipeline errors. */ | |
58 List stderr; | |
59 | |
60 /** Directory where test wrappers are created. */ | |
61 String tmpDir; | |
62 | |
63 void main(List<String> args, SendPort replyTo) { | |
64 var port = new ReceivePort(); | |
65 replyTo.send(port); | |
66 port.first.then((message) { | |
67 config = message[0]; | |
68 var replyPort = message[1]; | |
69 stdout = new List(); | |
70 stderr = new List(); | |
71 initPipeline(replyPort); | |
72 startHTTPServerStage(); | |
73 }); | |
74 } | |
75 | |
76 /** Initial pipeline stage - starts the HTTP server, if appropriate. */ | |
77 startHTTPServerStage() { | |
78 if (config["server"]) { | |
79 serverPath = config["testfile"]; | |
80 // Replace .dart with _server.dart to get test's server file, if any. | |
81 var truncLen = serverPath.length - '.dart'.length; | |
82 serverPath = '${serverPath.substring(0, truncLen)}_server.dart'; | |
83 var serverFile = new File(serverPath); | |
84 if (!serverFile.existsSync()) { | |
85 // No custom server; run the default server. | |
86 serverPath = '${config["runnerDir"]}/http_server_runner.dart'; | |
87 } | |
88 if (serverPath != null) { | |
89 serverRoot = config["root"]; | |
90 if (serverRoot == null) { | |
91 // Set the root to be the directory containing the test file. | |
92 serverRoot = getDirectory(config["testfile"]); | |
93 } | |
94 | |
95 if (config["port"] == null) { | |
96 // In this case we have to choose a random port and we need | |
97 // to see if the server starts successfully on that port. | |
98 var r = new Random(); | |
99 tryStartHTTPServer(r, MAX_SERVER_TRIES); | |
100 } else { | |
101 serverPort = int.parse(config["port"]); | |
102 // Start the HTTP server. | |
103 serverId = startProcess(config["dart"], | |
104 [ serverPath, '--port=$serverPort', '--root=$serverRoot'], | |
105 stdout, stderr); | |
106 } | |
107 } | |
108 } | |
109 wrapStage(); | |
110 } | |
111 | |
112 void tryStartHTTPServer(Random r, int remainingAttempts) { | |
113 // Pick a port from 1024 to 32767. | |
114 serverPort = 1024 + r.nextInt(32768 - 1024); | |
115 logMessage('Trying ${config["dart"]} $serverPath --port=$serverPort ' | |
116 '--root=$serverRoot'); | |
117 serverId = startProcess(config["dart"], | |
118 [ serverPath, '--port=$serverPort', '--root=$serverRoot'], | |
119 stdout, stderr, | |
120 (line) { | |
121 if (line.startsWith('Server listening')) { | |
122 wrapStage(); | |
123 } else if (remainingAttempts == 0) { | |
124 print('Failed to start HTTP server after $MAX_SERVER_TRIES' | |
125 ' attempts; aborting.'); | |
126 exit(1); | |
127 } else { | |
128 tryStartHTTPServer(r, remainingAttempts - 1); | |
129 } | |
130 }); | |
131 } | |
132 | |
133 /** Initial pipeline stage - generates Dart and HTML wrapper files. */ | |
134 wrapStage() { | |
135 tmpDir = config["targetDir"]; | |
136 var testFile = config["testfile"]; | |
137 | |
138 // Generate names for the generated wrapper files. | |
139 tempDartFile = createTempName(tmpDir, testFile, '.dart'); | |
140 if (config["runtime"] != 'vm') { | |
141 tempHtmlFile = createTempName(tmpDir, testFile, '.html'); | |
142 if (config["layout"]) { | |
143 tempChildDartFile = | |
144 createTempName(tmpDir, testFile, '-child.dart'); | |
145 } | |
146 if (config["runtime"] == 'drt-js') { | |
147 tempJsFile = createTempName(tmpDir, testFile, '.js'); | |
148 if (config["layout"]) { | |
149 tempChildJsFile = | |
150 createTempName(tmpDir, testFile, '-child.js'); | |
151 } | |
152 } | |
153 } | |
154 | |
155 // Create the test controller Dart wrapper. | |
156 var directives, extras; | |
157 | |
158 if (config["layout"]) { | |
159 directives = ''' | |
160 import 'dart:async'; | |
161 import 'dart:io'; | |
162 import 'dart:math'; | |
163 part '${normalizePath('${config["runnerDir"]}/layout_test_controller.dart')}'; | |
164 '''; | |
165 extras = ''' | |
166 baseUrl = 'file://${normalizePath('$tempHtmlFile')}'; | |
167 tprint = (msg) => print('###\$msg'); | |
168 notifyDone = (e) => exit(e); | |
169 '''; | |
170 } else if (config["runtime"] == "vm") { | |
171 directives = ''' | |
172 import 'dart:async'; | |
173 import 'dart:io'; | |
174 import 'dart:isolate'; | |
175 import 'package:unittest/unittest.dart'; | |
176 import '${normalizePath('${config["testfile"]}')}' as test; | |
177 part '${normalizePath('${config["runnerDir"]}/standard_test_runner.dart')}'; | |
178 '''; | |
179 extras = ''' | |
180 includeFilters = ${config["include"]}; | |
181 excludeFilters = ${config["exclude"]}; | |
182 tprint = (msg) => print('###\$msg'); | |
183 notifyDone = (e) { exit(e); }; | |
184 '''; | |
185 } else { | |
186 directives = ''' | |
187 import 'dart:async'; | |
188 import 'dart:html'; | |
189 import 'dart:isolate'; | |
190 import 'package:unittest/unittest.dart'; | |
191 import '${normalizePath('${config["testfile"]}')}' as test; | |
192 part '${normalizePath('${config["runnerDir"]}/standard_test_runner.dart')}'; | |
193 '''; | |
194 extras = ''' | |
195 includeFilters = ${config["include"]}; | |
196 excludeFilters = ${config["exclude"]}; | |
197 tprint = (msg) => query('#console').appendText('###\$msg\\n'); | |
198 notifyDone = (e) => window.postMessage('done', '*'); | |
199 '''; | |
200 } | |
201 | |
202 var action = 'process(test.main, runTests)'; | |
203 if (config["layout-text"]) { | |
204 action = 'runTextLayoutTests()'; | |
205 } else if (config["layout-pixel"]) { | |
206 action = 'runPixelLayoutTests()'; | |
207 } else if (config["list-tests"]) { | |
208 action = 'process(test.main, listTests)'; | |
209 } else if (config["list-groups"]) { | |
210 action = 'process(test.main, listGroups)'; | |
211 } else if (config["isolate"]) { | |
212 action = 'process(test.main, runIsolateTests)'; | |
213 } | |
214 | |
215 logMessage('Creating $tempDartFile'); | |
216 writeFile(tempDartFile, ''' | |
217 library test_controller; | |
218 $directives | |
219 | |
220 main() { | |
221 immediate = ${config["immediate"]}; | |
222 includeTime = ${config["time"]}; | |
223 passFormat = '${config["pass-format"]}'; | |
224 failFormat = '${config["fail-format"]}'; | |
225 errorFormat = '${config["error-format"]}'; | |
226 listFormat = '${config["list-format"]}'; | |
227 regenerate = ${config["regenerate"]}; | |
228 summarize = ${config["summary"]}; | |
229 testfile = '${testFile.replaceAll("\\","\\\\")}'; | |
230 drt = '${config["drt"].replaceAll("\\","\\\\")}'; | |
231 $extras | |
232 $action; | |
233 } | |
234 '''); | |
235 | |
236 // Create the child wrapper for layout tests. | |
237 if (config["layout"]) { | |
238 logMessage('Creating $tempChildDartFile'); | |
239 writeFile(tempChildDartFile, ''' | |
240 library layout_test; | |
241 import 'dart:math'; | |
242 import 'dart:isolate'; | |
243 import 'dart:html'; | |
244 import 'package:unittest/unittest.dart' as unittest; | |
245 import '${normalizePath('$testFile')}' as test; | |
246 part '${normalizePath('${config["runnerDir"]}/layout_test_runner.dart')}'; | |
247 | |
248 main() { | |
249 includeFilters = ${config["include"]}; | |
250 excludeFilters = ${config["exclude"]}; | |
251 runTests(test.main); | |
252 } | |
253 '''); | |
254 } | |
255 | |
256 // Create the HTML wrapper and compile to Javascript if necessary. | |
257 var isJavascript = config["runtime"] == 'drt-js'; | |
258 if (config["runtime"] == 'drt-dart' || isJavascript) { | |
259 var bodyElements, runAsText; | |
260 | |
261 if (config["layout"]) { | |
262 sourceFile = tempChildDartFile; | |
263 scriptFile = isJavascript ? tempChildJsFile : tempChildDartFile; | |
264 bodyElements = ''; | |
265 } else { | |
266 sourceFile = tempDartFile; | |
267 scriptFile = isJavascript ? tempJsFile : tempDartFile; | |
268 bodyElements = '<div id="container"></div><pre id="console"></pre>'; | |
269 runAsText = "testRunner.dumpAsText();"; | |
270 } | |
271 scriptType = isJavascript ? 'text/javascript' : 'application/dart'; | |
272 | |
273 if (config["runtime"] == 'drt-dart' || isJavascript) { | |
274 logMessage('Creating $tempHtmlFile'); | |
275 writeFile(tempHtmlFile, ''' | |
276 <!DOCTYPE html> | |
277 <html> | |
278 <head> | |
279 <meta charset="utf-8"> | |
280 <title>$testFile</title> | |
281 <link rel="stylesheet" href="${config["runnerDir"]}/testrunner.css"> | |
282 <script type='text/javascript'> | |
283 var testRunner = window.testRunner || window.layoutTestController; | |
284 if (testRunner) { | |
285 function handleMessage(m) { | |
286 if (m.data == 'done') { | |
287 testRunner.notifyDone(); | |
288 } | |
289 } | |
290 testRunner.waitUntilDone(); | |
291 $runAsText | |
292 window.addEventListener("message", handleMessage, false); | |
293 } | |
294 </script> | |
295 </head> | |
296 <body> | |
297 $bodyElements | |
298 <script type='$scriptType' src='$scriptFile'></script> | |
299 </script> | |
300 </body> | |
301 </html> | |
302 '''); | |
303 } | |
304 } | |
305 compileStage(isJavascript); | |
306 } | |
307 | |
308 /** Second stage of pipeline - compiles Dart to Javascript if needed. */ | |
309 compileStage(isJavascript) { | |
310 if (isJavascript) { // Compile the Dart file. | |
311 var cmd = config["dart2js"]; | |
312 var input = sourceFile.replaceAll('/', Platform.pathSeparator); | |
313 var output = scriptFile.replaceAll('/', Platform.pathSeparator); | |
314 if (config["checked"]) { | |
315 runCommand(cmd, [ '-c', '-o$output', '$input' ], stdout, stderr) | |
316 .then(runTestStage); | |
317 } else { | |
318 runCommand(cmd, [ '-o$output', '$input' ], stdout, stderr) | |
319 .then(runTestStage); | |
320 } | |
321 } else { | |
322 runTestStage(0); | |
323 } | |
324 } | |
325 | |
326 /** Third stage of pipeline - runs the tests. */ | |
327 runTestStage(_) { | |
328 var cmd, args; | |
329 if (config["runtime"] == 'vm' || config["layout"]) { // Run the tests. | |
330 if (config["checked"]) { | |
331 cmd = config["dart"]; | |
332 args = [ '--enable_asserts', '--enable_type_checks', tempDartFile ]; | |
333 } else { | |
334 cmd = config["dart"]; | |
335 args = [ tempDartFile ]; | |
336 } | |
337 } else { | |
338 cmd = config["drt"]; | |
339 args = [ '--no-timeout', tempHtmlFile ]; | |
340 } | |
341 runCommand(cmd, args, stdout, stderr, config["timeout"]).then(cleanupStage); | |
342 } | |
343 | |
344 /** | |
345 * Final stage of the pipeline - clean up generated files and notify | |
346 * the originator that started the isolate. | |
347 */ | |
348 cleanupStage(exitcode) { | |
349 if (config["server"]) { // Stop the HTTP server. | |
350 stopProcess(serverId); | |
351 } | |
352 | |
353 if (config["clean-files"]) { // Remove the temporary files. | |
354 cleanup(tempDartFile); | |
355 cleanup(tempHtmlFile); | |
356 cleanup(tempJsFile); | |
357 cleanup(tempChildDartFile); | |
358 cleanup(tempChildJsFile); | |
359 cleanup(createTempName(tmpDir, "pubspec", "yaml")); | |
360 cleanup(createTempName(tmpDir, "pubspec", "lock")); | |
361 cleanupDir(createTempName(tmpDir, "packages")); | |
362 } | |
363 completePipeline(stdout, stderr, exitcode); | |
364 } | |
OLD | NEW |