| 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 |