| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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.integration.analysis; | 5 library test.integration.analysis; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:convert'; | 9 import 'dart:convert'; |
| 10 import 'dart:io'; | 10 import 'dart:io'; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 * If [skipShutdown] is not set, shut down the server. | 167 * If [skipShutdown] is not set, shut down the server. |
| 168 */ | 168 */ |
| 169 Future shutdownIfNeeded() { | 169 Future shutdownIfNeeded() { |
| 170 if (skipShutdown) { | 170 if (skipShutdown) { |
| 171 return new Future.value(); | 171 return new Future.value(); |
| 172 } | 172 } |
| 173 // Give the server a short time to comply with the shutdown request; if it | 173 // Give the server a short time to comply with the shutdown request; if it |
| 174 // doesn't exit, then forcibly terminate it. | 174 // doesn't exit, then forcibly terminate it. |
| 175 sendServerShutdown(); | 175 sendServerShutdown(); |
| 176 return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () { | 176 return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () { |
| 177 return server.kill(); | 177 return server.kill('server failed to exit'); |
| 178 }); | 178 }); |
| 179 } | 179 } |
| 180 | 180 |
| 181 /** | 181 /** |
| 182 * Convert the given [relativePath] to an absolute path, by interpreting it | 182 * Convert the given [relativePath] to an absolute path, by interpreting it |
| 183 * relative to [sourceDirectory]. On Windows any forward slashes in | 183 * relative to [sourceDirectory]. On Windows any forward slashes in |
| 184 * [relativePath] are converted to backslashes. | 184 * [relativePath] are converted to backslashes. |
| 185 */ | 185 */ |
| 186 String sourcePath(String relativePath) { | 186 String sourcePath(String relativePath) { |
| 187 return join(sourceDirectory.path, relativePath.replaceAll('/', separator)); | 187 return join(sourceDirectory.path, relativePath.replaceAll('/', separator)); |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 * Return a future that will complete when all commands that have been sent | 484 * Return a future that will complete when all commands that have been sent |
| 485 * to the server so far have been flushed to the OS buffer. | 485 * to the server so far have been flushed to the OS buffer. |
| 486 */ | 486 */ |
| 487 Future flushCommands() { | 487 Future flushCommands() { |
| 488 return _process.stdin.flush(); | 488 return _process.stdin.flush(); |
| 489 } | 489 } |
| 490 | 490 |
| 491 /** | 491 /** |
| 492 * Stop the server. | 492 * Stop the server. |
| 493 */ | 493 */ |
| 494 Future kill() { | 494 Future kill(String reason) { |
| 495 debugStdio(); | 495 debugStdio(); |
| 496 _recordStdio('PROCESS FORCIBLY TERMINATED'); | 496 _recordStdio('FORCIBLY TERMINATING PROCESS: $reason'); |
| 497 _process.kill(); | 497 _process.kill(); |
| 498 return _process.exitCode; | 498 return _process.exitCode; |
| 499 } | 499 } |
| 500 | 500 |
| 501 /** | 501 /** |
| 502 * Start listening to output from the server, and deliver notifications to | 502 * Start listening to output from the server, and deliver notifications to |
| 503 * [notificationProcessor]. | 503 * [notificationProcessor]. |
| 504 */ | 504 */ |
| 505 void listenToOutput(NotificationProcessor notificationProcessor) { | 505 void listenToOutput(NotificationProcessor notificationProcessor) { |
| 506 _process.stdout | 506 _process.stdout |
| 507 .transform((new Utf8Codec()).decoder) | 507 .transform((new Utf8Codec()).decoder) |
| 508 .transform(new LineSplitter()) | 508 .transform(new LineSplitter()) |
| 509 .listen((String line) { | 509 .listen((String line) { |
| 510 lastCommunicationTime = currentElapseTime; | 510 lastCommunicationTime = currentElapseTime; |
| 511 String trimmedLine = line.trim(); | 511 String trimmedLine = line.trim(); |
| 512 _recordStdio('RECV: $trimmedLine'); | 512 _recordStdio('RECV: $trimmedLine'); |
| 513 var message; | 513 var message; |
| 514 try { | 514 try { |
| 515 message = JSON.decoder.convert(trimmedLine); | 515 message = JSON.decoder.convert(trimmedLine); |
| 516 } catch (exception) { | 516 } catch (exception) { |
| 517 _badDataFromServer(); | 517 _badDataFromServer('JSON decode failure: $exception'); |
| 518 return; | 518 return; |
| 519 } | 519 } |
| 520 expect(message, isMap); | 520 expect(message, isMap); |
| 521 Map messageAsMap = message; | 521 Map messageAsMap = message; |
| 522 if (messageAsMap.containsKey('id')) { | 522 if (messageAsMap.containsKey('id')) { |
| 523 expect(messageAsMap['id'], isString); | 523 expect(messageAsMap['id'], isString); |
| 524 String id = message['id']; | 524 String id = message['id']; |
| 525 Completer completer = _pendingCommands[id]; | 525 Completer completer = _pendingCommands[id]; |
| 526 if (completer == null) { | 526 if (completer == null) { |
| 527 fail('Unexpected response from server: id=$id'); | 527 fail('Unexpected response from server: id=$id'); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 550 // event of an error. | 550 // event of an error. |
| 551 expect(message, isNotification); | 551 expect(message, isNotification); |
| 552 } | 552 } |
| 553 }); | 553 }); |
| 554 _process.stderr | 554 _process.stderr |
| 555 .transform((new Utf8Codec()).decoder) | 555 .transform((new Utf8Codec()).decoder) |
| 556 .transform(new LineSplitter()) | 556 .transform(new LineSplitter()) |
| 557 .listen((String line) { | 557 .listen((String line) { |
| 558 String trimmedLine = line.trim(); | 558 String trimmedLine = line.trim(); |
| 559 _recordStdio('ERR: $trimmedLine'); | 559 _recordStdio('ERR: $trimmedLine'); |
| 560 _badDataFromServer(); | 560 _badDataFromServer('Message received on stderr', silent: true); |
| 561 }); | 561 }); |
| 562 } | 562 } |
| 563 | 563 |
| 564 /** | 564 /** |
| 565 * Send a command to the server. An 'id' will be automatically assigned. | 565 * Send a command to the server. An 'id' will be automatically assigned. |
| 566 * The returned [Future] will be completed when the server acknowledges the | 566 * The returned [Future] will be completed when the server acknowledges the |
| 567 * command with a response. If the server acknowledges the command with a | 567 * command with a response. If the server acknowledges the command with a |
| 568 * normal (non-error) response, the future will be completed with the 'result' | 568 * normal (non-error) response, the future will be completed with the 'result' |
| 569 * field from the response. If the server acknowledges the command with an | 569 * field from the response. If the server acknowledges the command with an |
| 570 * error response, the future will be completed with an error. | 570 * error response, the future will be completed with an error. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 arguments.add(diagnosticPort.toString()); | 623 arguments.add(diagnosticPort.toString()); |
| 624 } | 624 } |
| 625 if (useAnalysisHighlight2) { | 625 if (useAnalysisHighlight2) { |
| 626 arguments.add('--useAnalysisHighlight2'); | 626 arguments.add('--useAnalysisHighlight2'); |
| 627 } | 627 } |
| 628 // print('Launching $serverPath'); | 628 // print('Launching $serverPath'); |
| 629 // print('$dartBinary ${arguments.join(' ')}'); | 629 // print('$dartBinary ${arguments.join(' ')}'); |
| 630 return Process.start(dartBinary, arguments).then((Process process) { | 630 return Process.start(dartBinary, arguments).then((Process process) { |
| 631 _process = process; | 631 _process = process; |
| 632 process.exitCode.then((int code) { | 632 process.exitCode.then((int code) { |
| 633 _recordStdio('TERMINATED WITH EXIT CODE $code'); | |
| 634 if (code != 0) { | 633 if (code != 0) { |
| 635 _badDataFromServer(); | 634 _badDataFromServer('server terminated with exit code $code'); |
| 636 } | 635 } |
| 637 }); | 636 }); |
| 638 }); | 637 }); |
| 639 } | 638 } |
| 640 | 639 |
| 641 /** | 640 /** |
| 642 * Deal with bad data received from the server. | 641 * Deal with bad data received from the server. |
| 643 */ | 642 */ |
| 644 void _badDataFromServer() { | 643 void _badDataFromServer(String details, {bool silent: false}) { |
| 644 if (!silent) { |
| 645 _recordStdio('BAD DATA FROM SERVER: $details'); |
| 646 } |
| 645 if (_receivedBadDataFromServer) { | 647 if (_receivedBadDataFromServer) { |
| 646 // We're already dealing with it. | 648 // We're already dealing with it. |
| 647 return; | 649 return; |
| 648 } | 650 } |
| 649 _receivedBadDataFromServer = true; | 651 _receivedBadDataFromServer = true; |
| 650 debugStdio(); | 652 debugStdio(); |
| 651 // Give the server 1 second to continue outputting bad data before we kill | 653 // Give the server 1 second to continue outputting bad data before we kill |
| 652 // the test. This is helpful if the server has had an unhandled exception | 654 // the test. This is helpful if the server has had an unhandled exception |
| 653 // and is outputting a stacktrace, because it ensures that we see the | 655 // and is outputting a stacktrace, because it ensures that we see the |
| 654 // entire stacktrace. Use expectAsync() to prevent the test from | 656 // entire stacktrace. Use expectAsync() to prevent the test from |
| 655 // ending during this 1 second. | 657 // ending during this 1 second. |
| 656 new Future.delayed(new Duration(seconds: 1), expectAsync(() { | 658 new Future.delayed(new Duration(seconds: 1), expectAsync(() { |
| 657 fail('Bad data received from server'); | 659 fail('Bad data received from server: $details'); |
| 658 })); | 660 })); |
| 659 } | 661 } |
| 660 | 662 |
| 661 /** | 663 /** |
| 662 * Record a message that was exchanged with the server, and print it out if | 664 * Record a message that was exchanged with the server, and print it out if |
| 663 * [debugStdio] has been called. | 665 * [debugStdio] has been called. |
| 664 */ | 666 */ |
| 665 void _recordStdio(String line) { | 667 void _recordStdio(String line) { |
| 666 double elapsedTime = currentElapseTime; | 668 double elapsedTime = currentElapseTime; |
| 667 line = "$elapsedTime: $line"; | 669 line = "$elapsedTime: $line"; |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 void populateMismatches(item, List<MismatchDescriber> mismatches); | 885 void populateMismatches(item, List<MismatchDescriber> mismatches); |
| 884 | 886 |
| 885 /** | 887 /** |
| 886 * Create a [MismatchDescriber] describing a mismatch with a simple string. | 888 * Create a [MismatchDescriber] describing a mismatch with a simple string. |
| 887 */ | 889 */ |
| 888 MismatchDescriber simpleDescription(String description) => | 890 MismatchDescriber simpleDescription(String description) => |
| 889 (Description mismatchDescription) { | 891 (Description mismatchDescription) { |
| 890 mismatchDescription.add(description); | 892 mismatchDescription.add(description); |
| 891 }; | 893 }; |
| 892 } | 894 } |
| OLD | NEW |