| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library test_helper; | 5 library test_helper; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'package:observatory/service_io.dart'; | 10 import 'package:observatory/service_io.dart'; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 bool killedByTester = false; | 84 bool killedByTester = false; |
| 85 | 85 |
| 86 _ServiceTesteeLauncher() : | 86 _ServiceTesteeLauncher() : |
| 87 args = [Platform.script.toFilePath()] {} | 87 args = [Platform.script.toFilePath()] {} |
| 88 | 88 |
| 89 // Spawn the testee process. | 89 // Spawn the testee process. |
| 90 Future<Process> _spawnProcess(bool pause_on_start, | 90 Future<Process> _spawnProcess(bool pause_on_start, |
| 91 bool pause_on_exit, | 91 bool pause_on_exit, |
| 92 bool pause_on_unhandled_exceptions, | 92 bool pause_on_unhandled_exceptions, |
| 93 bool trace_service, | 93 bool trace_service, |
| 94 bool trace_compiler) { | 94 bool trace_compiler, |
| 95 bool testeeControlsServer) { |
| 95 assert(pause_on_start != null); | 96 assert(pause_on_start != null); |
| 96 assert(pause_on_exit != null); | 97 assert(pause_on_exit != null); |
| 97 assert(pause_on_unhandled_exceptions != null); | 98 assert(pause_on_unhandled_exceptions != null); |
| 98 assert(trace_service != null); | 99 assert(trace_service != null); |
| 99 assert(trace_compiler != null); | 100 assert(trace_compiler != null); |
| 101 assert(testeeControlsServer != null); |
| 100 | 102 |
| 101 if (_shouldLaunchSkyShell()) { | 103 if (_shouldLaunchSkyShell()) { |
| 102 return _spawnSkyProcess(pause_on_start, | 104 return _spawnSkyProcess(pause_on_start, |
| 103 pause_on_exit, | 105 pause_on_exit, |
| 104 pause_on_unhandled_exceptions, | 106 pause_on_unhandled_exceptions, |
| 105 trace_service, | 107 trace_service, |
| 106 trace_compiler); | 108 trace_compiler, |
| 109 testeeControlsServer); |
| 107 } else { | 110 } else { |
| 108 return _spawnDartProcess(pause_on_start, | 111 return _spawnDartProcess(pause_on_start, |
| 109 pause_on_exit, | 112 pause_on_exit, |
| 110 pause_on_unhandled_exceptions, | 113 pause_on_unhandled_exceptions, |
| 111 trace_service, | 114 trace_service, |
| 112 trace_compiler); | 115 trace_compiler, |
| 116 testeeControlsServer); |
| 113 } | 117 } |
| 114 } | 118 } |
| 115 | 119 |
| 116 Future<Process> _spawnDartProcess(bool pause_on_start, | 120 Future<Process> _spawnDartProcess(bool pause_on_start, |
| 117 bool pause_on_exit, | 121 bool pause_on_exit, |
| 118 bool pause_on_unhandled_exceptions, | 122 bool pause_on_unhandled_exceptions, |
| 119 bool trace_service, | 123 bool trace_service, |
| 120 bool trace_compiler) { | 124 bool trace_compiler, |
| 125 bool testeeControlsServer) { |
| 121 assert(!_shouldLaunchSkyShell()); | 126 assert(!_shouldLaunchSkyShell()); |
| 122 | 127 |
| 123 String dartExecutable = Platform.executable; | 128 String dartExecutable = Platform.executable; |
| 124 | 129 |
| 125 var fullArgs = []; | 130 var fullArgs = []; |
| 126 if (trace_service) { | 131 if (trace_service) { |
| 127 fullArgs.add('--trace-service'); | 132 fullArgs.add('--trace-service'); |
| 128 fullArgs.add('--trace-service-verbose'); | 133 fullArgs.add('--trace-service-verbose'); |
| 129 } | 134 } |
| 130 if (trace_compiler) { | 135 if (trace_compiler) { |
| 131 fullArgs.add('--trace-compiler'); | 136 fullArgs.add('--trace-compiler'); |
| 132 } | 137 } |
| 133 if (pause_on_start) { | 138 if (pause_on_start) { |
| 134 fullArgs.add('--pause-isolates-on-start'); | 139 fullArgs.add('--pause-isolates-on-start'); |
| 135 } | 140 } |
| 136 if (pause_on_exit) { | 141 if (pause_on_exit) { |
| 137 fullArgs.add('--pause-isolates-on-exit'); | 142 fullArgs.add('--pause-isolates-on-exit'); |
| 138 } | 143 } |
| 139 if (pause_on_unhandled_exceptions) { | 144 if (pause_on_unhandled_exceptions) { |
| 140 fullArgs.add('--pause-isolates-on-unhandled-exceptions'); | 145 fullArgs.add('--pause-isolates-on-unhandled-exceptions'); |
| 141 } | 146 } |
| 142 | 147 |
| 143 fullArgs.addAll(Platform.executableArguments); | 148 fullArgs.addAll(Platform.executableArguments); |
| 144 fullArgs.add('--enable-vm-service:0'); | 149 if (!testeeControlsServer) { |
| 150 fullArgs.add('--enable-vm-service:0'); |
| 151 } |
| 145 fullArgs.addAll(args); | 152 fullArgs.addAll(args); |
| 146 | 153 |
| 147 return _spawnCommon(dartExecutable, fullArgs); | 154 return _spawnCommon(dartExecutable, fullArgs); |
| 148 } | 155 } |
| 149 | 156 |
| 150 Future<Process> _spawnSkyProcess(bool pause_on_start, | 157 Future<Process> _spawnSkyProcess(bool pause_on_start, |
| 151 bool pause_on_exit, | 158 bool pause_on_exit, |
| 152 bool pause_on_unhandled_exceptions, | 159 bool pause_on_unhandled_exceptions, |
| 153 bool trace_service, | 160 bool trace_service, |
| 154 bool trace_compiler) { | 161 bool trace_compiler) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 172 if (pause_on_exit) { | 179 if (pause_on_exit) { |
| 173 dartFlags.add('--pause_isolates_on_exit'); | 180 dartFlags.add('--pause_isolates_on_exit'); |
| 174 } | 181 } |
| 175 if (pause_on_unhandled_exceptions) { | 182 if (pause_on_unhandled_exceptions) { |
| 176 dartFlags.add('--pause_isolates_on_unhandled_exceptions'); | 183 dartFlags.add('--pause_isolates_on_unhandled_exceptions'); |
| 177 } | 184 } |
| 178 // Override mirrors. | 185 // Override mirrors. |
| 179 dartFlags.add('--enable_mirrors=true'); | 186 dartFlags.add('--enable_mirrors=true'); |
| 180 | 187 |
| 181 fullArgs.addAll(Platform.executableArguments); | 188 fullArgs.addAll(Platform.executableArguments); |
| 182 fullArgs.add('--observatory-port=0'); | 189 if (!testeeControlsServer) { |
| 190 fullArgs.add('--observatory-port=0'); |
| 191 } |
| 183 fullArgs.add('--dart-flags=${dartFlags.join(' ')}'); | 192 fullArgs.add('--dart-flags=${dartFlags.join(' ')}'); |
| 184 fullArgs.addAll(args); | 193 fullArgs.addAll(args); |
| 185 | 194 |
| 186 return _spawnCommon(dartExecutable, fullArgs); | 195 return _spawnCommon(dartExecutable, fullArgs); |
| 187 } | 196 } |
| 188 | 197 |
| 189 Future<Process> _spawnCommon(String executable, List<String> arguments) { | 198 Future<Process> _spawnCommon(String executable, List<String> arguments) { |
| 190 var environment = _TESTEE_SPAWN_ENV; | 199 var environment = _TESTEE_SPAWN_ENV; |
| 191 var bashEnvironment = new StringBuffer(); | 200 var bashEnvironment = new StringBuffer(); |
| 192 environment.forEach((k, v) => bashEnvironment.write("$k=$v ")); | 201 environment.forEach((k, v) => bashEnvironment.write("$k=$v ")); |
| 193 print('** Launching $bashEnvironment$executable ${arguments.join(' ')}'); | 202 print('** Launching $bashEnvironment$executable ${arguments.join(' ')}'); |
| 194 return Process.start(executable, arguments, environment: environment); | 203 return Process.start(executable, arguments, environment: environment); |
| 195 } | 204 } |
| 196 | 205 |
| 197 Future<int> launch(bool pause_on_start, | 206 Future<Uri> launch(bool pause_on_start, |
| 198 bool pause_on_exit, | 207 bool pause_on_exit, |
| 199 bool pause_on_unhandled_exceptions, | 208 bool pause_on_unhandled_exceptions, |
| 200 bool trace_service, | 209 bool trace_service, |
| 201 bool trace_compiler) { | 210 bool trace_compiler, |
| 211 bool testeeControlsServer) { |
| 202 return _spawnProcess(pause_on_start, | 212 return _spawnProcess(pause_on_start, |
| 203 pause_on_exit, | 213 pause_on_exit, |
| 204 pause_on_unhandled_exceptions, | 214 pause_on_unhandled_exceptions, |
| 205 trace_service, | 215 trace_service, |
| 206 trace_compiler).then((p) { | 216 trace_compiler, |
| 207 Completer completer = new Completer(); | 217 testeeControlsServer).then((p) { |
| 218 Completer<Uri> completer = new Completer<Uri>(); |
| 208 process = p; | 219 process = p; |
| 209 var portNumber; | 220 Uri uri; |
| 210 var blank; | 221 var blank; |
| 211 var first = true; | 222 var first = true; |
| 212 process.stdout.transform(UTF8.decoder) | 223 process.stdout.transform(UTF8.decoder) |
| 213 .transform(new LineSplitter()).listen((line) { | 224 .transform(new LineSplitter()).listen((line) { |
| 214 if (line.startsWith('Observatory listening on http://')) { | 225 const kObservatoryListening = 'Observatory listening on '; |
| 215 RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); | 226 if (line.startsWith(kObservatoryListening)) { |
| 216 var port = portExp.firstMatch(line).group(1); | 227 uri = Uri.parse(line.substring(kObservatoryListening.length)); |
| 217 portNumber = int.parse(port); | |
| 218 } | 228 } |
| 219 if (pause_on_start || line == '') { | 229 if (pause_on_start || line == '') { |
| 220 // Received blank line. | 230 // Received blank line. |
| 221 blank = true; | 231 blank = true; |
| 222 } | 232 } |
| 223 if (portNumber != null && blank == true && first == true) { | 233 if ((uri != null) && (blank == true) && (first == true)) { |
| 224 completer.complete(portNumber); | 234 completer.complete(uri); |
| 225 // Stop repeat completions. | 235 // Stop repeat completions. |
| 226 first = false; | 236 first = false; |
| 227 print('** Signaled to run test queries on $portNumber'); | 237 print('** Signaled to run test queries on $uri'); |
| 228 } | 238 } |
| 229 print('>testee>out> $line'); | 239 print('>testee>out> $line'); |
| 230 }); | 240 }); |
| 231 process.stderr.transform(UTF8.decoder) | 241 process.stderr.transform(UTF8.decoder) |
| 232 .transform(new LineSplitter()).listen((line) { | 242 .transform(new LineSplitter()).listen((line) { |
| 233 print('>testee>err> $line'); | 243 print('>testee>err> $line'); |
| 234 }); | 244 }); |
| 235 process.exitCode.then((exitCode) { | 245 process.exitCode.then((exitCode) { |
| 236 if ((exitCode != 0) && !killedByTester) { | 246 if ((exitCode != 0) && !killedByTester) { |
| 237 throw "Testee exited with $exitCode"; | 247 throw "Testee exited with $exitCode"; |
| 238 } | 248 } |
| 239 print("** Process exited"); | 249 print("** Process exited"); |
| 240 }); | 250 }); |
| 241 return completer.future; | 251 return completer.future; |
| 242 }); | 252 }); |
| 243 } | 253 } |
| 244 | 254 |
| 245 void requestExit() { | 255 void requestExit() { |
| 246 print('** Killing script'); | 256 print('** Killing script'); |
| 247 if (process.kill()) { | 257 if (process.kill()) { |
| 248 killedByTester = true; | 258 killedByTester = true; |
| 249 } | 259 } |
| 250 } | 260 } |
| 251 } | 261 } |
| 252 | 262 |
| 253 // A tester runner that doesn't spawn a process but instead connects to | 263 void setupAddresses(Uri serverAddress) { |
| 254 // an already running flutter application running on a device. Assumes | 264 serviceWebsocketAddress = |
| 255 // port 8100. This is only useful for debugging. | 265 'ws://${serverAddress.authority}${serverAddress.path}ws'; |
| 256 class _FlutterDeviceServiceTesterRunner { | 266 serviceHttpAddress = |
| 257 void run({List<String> mainArgs, | 267 'http://${serverAddress.authority}${serverAddress.path}'; |
| 258 List<VMTest> vmTests, | |
| 259 List<IsolateTest> isolateTests, | |
| 260 bool pause_on_start: false, | |
| 261 bool pause_on_exit: false, | |
| 262 bool trace_service: false, | |
| 263 bool trace_compiler: false, | |
| 264 bool verbose_vm: false, | |
| 265 bool pause_on_unhandled_exceptions: false}) { | |
| 266 var port = 8100; | |
| 267 serviceWebsocketAddress = 'ws://localhost:$port/ws'; | |
| 268 serviceHttpAddress = 'http://localhost:$port'; | |
| 269 var name = Platform.script.pathSegments.last; | |
| 270 Chain.capture(() async { | |
| 271 var vm = | |
| 272 new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress)); | |
| 273 print('Loading VM...'); | |
| 274 await vm.load(); | |
| 275 print('Done loading VM'); | |
| 276 | |
| 277 // Run vm tests. | |
| 278 if (vmTests != null) { | |
| 279 var testIndex = 1; | |
| 280 var totalTests = vmTests.length; | |
| 281 for (var test in vmTests) { | |
| 282 vm.verbose = verbose_vm; | |
| 283 print('Running $name [$testIndex/$totalTests]'); | |
| 284 testIndex++; | |
| 285 await test(vm); | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 // Run isolate tests. | |
| 290 if (isolateTests != null) { | |
| 291 var isolate = await vm.isolates.first.load(); | |
| 292 var testIndex = 1; | |
| 293 var totalTests = isolateTests.length; | |
| 294 for (var test in isolateTests) { | |
| 295 vm.verbose = verbose_vm; | |
| 296 print('Running $name [$testIndex/$totalTests]'); | |
| 297 testIndex++; | |
| 298 await test(isolate); | |
| 299 } | |
| 300 } | |
| 301 }, onError: (error, stackTrace) { | |
| 302 print('Unexpected exception in service tests: $error\n$stackTrace'); | |
| 303 }); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 void suppressWarning() { | |
| 308 new _FlutterDeviceServiceTesterRunner(); | |
| 309 } | 268 } |
| 310 | 269 |
| 311 class _ServiceTesterRunner { | 270 class _ServiceTesterRunner { |
| 312 void run({List<String> mainArgs, | 271 void run({List<String> mainArgs, |
| 313 List<VMTest> vmTests, | 272 List<VMTest> vmTests, |
| 314 List<IsolateTest> isolateTests, | 273 List<IsolateTest> isolateTests, |
| 315 bool pause_on_start: false, | 274 bool pause_on_start: false, |
| 316 bool pause_on_exit: false, | 275 bool pause_on_exit: false, |
| 317 bool trace_service: false, | 276 bool trace_service: false, |
| 318 bool trace_compiler: false, | 277 bool trace_compiler: false, |
| 319 bool verbose_vm: false, | 278 bool verbose_vm: false, |
| 320 bool pause_on_unhandled_exceptions: false}) { | 279 bool pause_on_unhandled_exceptions: false, |
| 280 bool testeeControlsServer: false}) { |
| 321 var process = new _ServiceTesteeLauncher(); | 281 var process = new _ServiceTesteeLauncher(); |
| 322 process.launch(pause_on_start, pause_on_exit, | 282 process.launch(pause_on_start, pause_on_exit, |
| 323 pause_on_unhandled_exceptions, | 283 pause_on_unhandled_exceptions, |
| 324 trace_service, trace_compiler).then((port) async { | 284 trace_service, trace_compiler, |
| 285 testeeControlsServer).then((Uri serverAddress) async { |
| 325 if (mainArgs.contains("--gdb")) { | 286 if (mainArgs.contains("--gdb")) { |
| 326 var pid = process.process.pid; | 287 var pid = process.process.pid; |
| 327 var wait = new Duration(seconds: 10); | 288 var wait = new Duration(seconds: 10); |
| 328 print("Testee has pid $pid, waiting $wait before continuing"); | 289 print("Testee has pid $pid, waiting $wait before continuing"); |
| 329 sleep(wait); | 290 sleep(wait); |
| 330 } | 291 } |
| 331 serviceWebsocketAddress = 'ws://localhost:$port/ws'; | 292 setupAddresses(serverAddress); |
| 332 serviceHttpAddress = 'http://localhost:$port'; | |
| 333 var name = Platform.script.pathSegments.last; | 293 var name = Platform.script.pathSegments.last; |
| 334 Chain.capture(() async { | 294 Chain.capture(() async { |
| 335 var vm = | 295 var vm = |
| 336 new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress)); | 296 new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress)); |
| 337 print('Loading VM...'); | 297 print('Loading VM...'); |
| 338 await vm.load(); | 298 await vm.load(); |
| 339 print('Done loading VM'); | 299 print('Done loading VM'); |
| 340 | 300 |
| 341 // Run vm tests. | 301 // Run vm tests. |
| 342 if (vmTests != null) { | 302 if (vmTests != null) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 /// to run tests or testee in this invokation of the script. | 339 /// to run tests or testee in this invokation of the script. |
| 380 Future runIsolateTests(List<String> mainArgs, | 340 Future runIsolateTests(List<String> mainArgs, |
| 381 List<IsolateTest> tests, | 341 List<IsolateTest> tests, |
| 382 {testeeBefore(), | 342 {testeeBefore(), |
| 383 testeeConcurrent(), | 343 testeeConcurrent(), |
| 384 bool pause_on_start: false, | 344 bool pause_on_start: false, |
| 385 bool pause_on_exit: false, | 345 bool pause_on_exit: false, |
| 386 bool trace_service: false, | 346 bool trace_service: false, |
| 387 bool trace_compiler: false, | 347 bool trace_compiler: false, |
| 388 bool verbose_vm: false, | 348 bool verbose_vm: false, |
| 389 bool pause_on_unhandled_exceptions: false}) async { | 349 bool pause_on_unhandled_exceptions: false, |
| 350 bool testeeControlsServer: false}) async { |
| 390 assert(!pause_on_start || testeeBefore == null); | 351 assert(!pause_on_start || testeeBefore == null); |
| 391 if (_isTestee()) { | 352 if (_isTestee()) { |
| 392 new _ServiceTesteeRunner().run(testeeBefore: testeeBefore, | 353 new _ServiceTesteeRunner().run(testeeBefore: testeeBefore, |
| 393 testeeConcurrent: testeeConcurrent, | 354 testeeConcurrent: testeeConcurrent, |
| 394 pause_on_start: pause_on_start, | 355 pause_on_start: pause_on_start, |
| 395 pause_on_exit: pause_on_exit); | 356 pause_on_exit: pause_on_exit); |
| 396 } else { | 357 } else { |
| 397 new _ServiceTesterRunner().run( | 358 new _ServiceTesterRunner().run( |
| 398 mainArgs: mainArgs, | 359 mainArgs: mainArgs, |
| 399 isolateTests: tests, | 360 isolateTests: tests, |
| 400 pause_on_start: pause_on_start, | 361 pause_on_start: pause_on_start, |
| 401 pause_on_exit: pause_on_exit, | 362 pause_on_exit: pause_on_exit, |
| 402 trace_service: trace_service, | 363 trace_service: trace_service, |
| 403 trace_compiler: trace_compiler, | 364 trace_compiler: trace_compiler, |
| 404 verbose_vm: verbose_vm, | 365 verbose_vm: verbose_vm, |
| 405 pause_on_unhandled_exceptions: pause_on_unhandled_exceptions); | 366 pause_on_unhandled_exceptions: pause_on_unhandled_exceptions, |
| 367 testeeControlsServer: testeeControlsServer); |
| 406 } | 368 } |
| 407 } | 369 } |
| 408 | 370 |
| 409 /// Runs [tests] in sequence, each of which should take an [Isolate] and | 371 /// Runs [tests] in sequence, each of which should take an [Isolate] and |
| 410 /// return a [Future]. Code for setting up state can run before and/or | 372 /// return a [Future]. Code for setting up state can run before and/or |
| 411 /// concurrently with the tests. Uses [mainArgs] to determine whether | 373 /// concurrently with the tests. Uses [mainArgs] to determine whether |
| 412 /// to run tests or testee in this invokation of the script. | 374 /// to run tests or testee in this invokation of the script. |
| 413 /// | 375 /// |
| 414 /// This is a special version of this test harness specifically for the | 376 /// This is a special version of this test harness specifically for the |
| 415 /// pause_on_unhandled_exceptions_test, which cannot properly function | 377 /// pause_on_unhandled_exceptions_test, which cannot properly function |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 mainArgs: mainArgs, | 431 mainArgs: mainArgs, |
| 470 vmTests: tests, | 432 vmTests: tests, |
| 471 pause_on_start: pause_on_start, | 433 pause_on_start: pause_on_start, |
| 472 pause_on_exit: pause_on_exit, | 434 pause_on_exit: pause_on_exit, |
| 473 trace_service: trace_service, | 435 trace_service: trace_service, |
| 474 trace_compiler: trace_compiler, | 436 trace_compiler: trace_compiler, |
| 475 verbose_vm: verbose_vm, | 437 verbose_vm: verbose_vm, |
| 476 pause_on_unhandled_exceptions: pause_on_unhandled_exceptions); | 438 pause_on_unhandled_exceptions: pause_on_unhandled_exceptions); |
| 477 } | 439 } |
| 478 } | 440 } |
| OLD | NEW |