Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: pkg/analysis_server/test/integration/integration_tests.dart

Issue 668953002: Add an integration test to verify that server I/O is asynchronous. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 HashMap<String, List<AnalysisError>> currentAnalysisErrors = 45 HashMap<String, List<AnalysisError>> currentAnalysisErrors =
46 new HashMap<String, List<AnalysisError>>(); 46 new HashMap<String, List<AnalysisError>>();
47 47
48 /** 48 /**
49 * True if the teardown process should skip sending a "server.shutdown" 49 * True if the teardown process should skip sending a "server.shutdown"
50 * request (e.g. because the server is known to have already shutdown). 50 * request (e.g. because the server is known to have already shutdown).
51 */ 51 */
52 bool skipShutdown = false; 52 bool skipShutdown = false;
53 53
54 /** 54 /**
55 * Data associated with the "server.connected" notification that was received
56 * when the server started up.
57 */
58 var serverConnectedParams;
59
60 /**
61 * True if we are currently subscribed to [SERVER_STATUS] updates. 55 * True if we are currently subscribed to [SERVER_STATUS] updates.
62 */ 56 */
63 bool _subscribedToServerStatus = false; 57 bool _subscribedToServerStatus = false;
64 58
65 AbstractAnalysisServerIntegrationTest() { 59 AbstractAnalysisServerIntegrationTest() {
66 initializeInttestMixin(); 60 initializeInttestMixin();
67 } 61 }
68 62
69 /** 63 /**
70 * Write a source file with the given absolute [pathname] and [contents]. 64 * Write a source file with the given absolute [pathname] and [contents].
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer'); 143 sourceDirectory = Directory.systemTemp.createTempSync('analysisServer');
150 144
151 onAnalysisErrors.listen((AnalysisErrorsParams params) { 145 onAnalysisErrors.listen((AnalysisErrorsParams params) {
152 currentAnalysisErrors[params.file] = params.errors; 146 currentAnalysisErrors[params.file] = params.errors;
153 }); 147 });
154 Completer serverConnected = new Completer(); 148 Completer serverConnected = new Completer();
155 onServerConnected.listen((_) { 149 onServerConnected.listen((_) {
156 expect(serverConnected.isCompleted, isFalse); 150 expect(serverConnected.isCompleted, isFalse);
157 serverConnected.complete(); 151 serverConnected.complete();
158 }); 152 });
159 return server.start(dispatchNotification).then((params) { 153 return server.start().then((_) {
160 serverConnectedParams = params; 154 server.listenToOutput(dispatchNotification);
161 server.exitCode.then((_) { 155 server.exitCode.then((_) {
162 skipShutdown = true; 156 skipShutdown = true;
163 }); 157 });
164 return serverConnected.future; 158 return serverConnected.future;
165 }); 159 });
166 } 160 }
167 161
168 /** 162 /**
169 * After every test, the server is stopped and [sourceDirectory] is deleted. 163 * After every test, the server is stopped and [sourceDirectory] is deleted.
170 */ 164 */
(...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 } 675 }
682 pathname = parent; 676 pathname = parent;
683 } 677 }
684 return dirname(pathname); 678 return dirname(pathname);
685 } 679 }
686 680
687 /** 681 /**
688 * Start the server. If [debugServer] is true, the server will be started 682 * Start the server. If [debugServer] is true, the server will be started
689 * with "--debug", allowing a debugger to be attached. 683 * with "--debug", allowing a debugger to be attached.
690 */ 684 */
691 Future start(NotificationProcessor notificationProcessor, {bool debugServer: 685 Future start({bool debugServer: false}) {
692 false}) {
693 if (_process != null) { 686 if (_process != null) {
694 throw new Exception('Process already started'); 687 throw new Exception('Process already started');
695 } 688 }
696 _time.start(); 689 _time.start();
697 // TODO(paulberry): move the logic for finding the script, the dart
698 // executable, and the package root into a shell script.
699 String dartBinary = Platform.executable; 690 String dartBinary = Platform.executable;
700 String rootDir = 691 String rootDir =
701 findRoot(Platform.script.toFilePath(windows: Platform.isWindows)); 692 findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
702 String serverPath = normalize(join(rootDir, 'bin', 'server.dart')); 693 String serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
703 List<String> arguments = []; 694 List<String> arguments = [];
704 if (debugServer) { 695 if (debugServer) {
705 arguments.add('--debug'); 696 arguments.add('--debug');
706 } 697 }
707 if (Platform.packageRoot.isNotEmpty) { 698 if (Platform.packageRoot.isNotEmpty) {
708 arguments.add('--package-root=${Platform.packageRoot}'); 699 arguments.add('--package-root=${Platform.packageRoot}');
709 } 700 }
710 arguments.add('--checked'); 701 arguments.add('--checked');
711 arguments.add(serverPath); 702 arguments.add(serverPath);
712 return Process.start(dartBinary, arguments).then((Process process) { 703 return Process.start(dartBinary, arguments).then((Process process) {
713 _process = process; 704 _process = process;
714 process.stdout.transform(
715 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((Strin g line) {
716 String trimmedLine = line.trim();
717 _recordStdio('RECV: $trimmedLine');
718 var message;
719 try {
720 message = JSON.decoder.convert(trimmedLine);
721 } catch (exception) {
722 _badDataFromServer();
723 return;
724 }
725 expect(message, isMap);
726 Map messageAsMap = message;
727 if (messageAsMap.containsKey('id')) {
728 expect(messageAsMap['id'], isString);
729 String id = message['id'];
730 Completer completer = _pendingCommands[id];
731 if (completer == null) {
732 fail('Unexpected response from server: id=$id');
733 } else {
734 _pendingCommands.remove(id);
735 }
736 if (messageAsMap.containsKey('error')) {
737 // TODO(paulberry): propagate the error info to the completer.
738 completer.completeError(
739 new UnimplementedError(
740 'Server responded with an error: ${JSON.encode(message)}'));
741 } else {
742 completer.complete(messageAsMap['result']);
743 }
744 // Check that the message is well-formed. We do this after calling
745 // completer.complete() or completer.completeError() so that we don't
746 // stall the test in the event of an error.
747 expect(message, isResponse);
748 } else {
749 // Message is a notification. It should have an event and possibly
750 // params.
751 expect(messageAsMap, contains('event'));
752 expect(messageAsMap['event'], isString);
753 notificationProcessor(messageAsMap['event'], messageAsMap['params']);
754 // Check that the message is well-formed. We do this after calling
755 // notificationController.add() so that we don't stall the test in the
756 // event of an error.
757 expect(message, isNotification);
758 }
759 });
760 process.stderr.transform(
761 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((Strin g line) {
762 String trimmedLine = line.trim();
763 _recordStdio('ERR: $trimmedLine');
764 _badDataFromServer();
765 });
766 process.exitCode.then((int code) { 705 process.exitCode.then((int code) {
767 _recordStdio('TERMINATED WITH EXIT CODE $code'); 706 _recordStdio('TERMINATED WITH EXIT CODE $code');
768 if (code != 0) { 707 if (code != 0) {
769 _badDataFromServer(); 708 _badDataFromServer();
770 } 709 }
771 }); 710 });
772 }); 711 });
773 } 712 }
774 713
775 /** 714 /**
715 * Start listening to output from the server, and deliver notifications to
716 * [notificationProcessor].
717 */
718 void listenToOutput(NotificationProcessor notificationProcessor) {
719 _process.stdout.transform(
720 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((String line) {
721 String trimmedLine = line.trim();
722 _recordStdio('RECV: $trimmedLine');
723 var message;
724 try {
725 message = JSON.decoder.convert(trimmedLine);
726 } catch (exception) {
727 _badDataFromServer();
728 return;
729 }
730 expect(message, isMap);
731 Map messageAsMap = message;
732 if (messageAsMap.containsKey('id')) {
733 expect(messageAsMap['id'], isString);
734 String id = message['id'];
735 Completer completer = _pendingCommands[id];
736 if (completer == null) {
737 fail('Unexpected response from server: id=$id');
738 } else {
739 _pendingCommands.remove(id);
740 }
741 if (messageAsMap.containsKey('error')) {
742 // TODO(paulberry): propagate the error info to the completer.
743 completer.completeError(
744 new UnimplementedError(
745 'Server responded with an error: ${JSON.encode(message)}'));
746 } else {
747 completer.complete(messageAsMap['result']);
748 }
749 // Check that the message is well-formed. We do this after calling
750 // completer.complete() or completer.completeError() so that we don't
751 // stall the test in the event of an error.
752 expect(message, isResponse);
753 } else {
754 // Message is a notification. It should have an event and possibly
755 // params.
756 expect(messageAsMap, contains('event'));
757 expect(messageAsMap['event'], isString);
758 notificationProcessor(messageAsMap['event'], messageAsMap['params']);
759 // Check that the message is well-formed. We do this after calling
760 // notificationController.add() so that we don't stall the test in the
761 // event of an error.
762 expect(message, isNotification);
763 }
764 });
765 _process.stderr.transform(
766 (new Utf8Codec()).decoder).transform(new LineSplitter()).listen((String line) {
767 String trimmedLine = line.trim();
768 _recordStdio('ERR: $trimmedLine');
769 _badDataFromServer();
770 });
771 }
772
773 /**
776 * Future that completes when the server process exits. 774 * Future that completes when the server process exits.
777 */ 775 */
778 Future<int> get exitCode => _process.exitCode; 776 Future<int> get exitCode => _process.exitCode;
779 777
780 /** 778 /**
781 * Stop the server. 779 * Stop the server.
782 */ 780 */
783 Future kill() { 781 Future kill() {
784 debugStdio(); 782 debugStdio();
785 _recordStdio('PROCESS FORCIBLY TERMINATED'); 783 _recordStdio('PROCESS FORCIBLY TERMINATED');
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 if (_debuggingStdio) { 818 if (_debuggingStdio) {
821 return; 819 return;
822 } 820 }
823 _debuggingStdio = true; 821 _debuggingStdio = true;
824 for (String line in _recordedStdio) { 822 for (String line in _recordedStdio) {
825 print(line); 823 print(line);
826 } 824 }
827 } 825 }
828 826
829 /** 827 /**
828 * Return a future that will complete when all commands that have been sent
829 * to the server so far have been flushed to the OS buffer.
830 */
831 Future flushCommands() {
832 return _process.stdin.flush();
833 }
834
835 /**
830 * Deal with bad data received from the server. 836 * Deal with bad data received from the server.
831 */ 837 */
832 void _badDataFromServer() { 838 void _badDataFromServer() {
833 if (_receivedBadDataFromServer) { 839 if (_receivedBadDataFromServer) {
834 // We're already dealing with it. 840 // We're already dealing with it.
835 return; 841 return;
836 } 842 }
837 _receivedBadDataFromServer = true; 843 _receivedBadDataFromServer = true;
838 debugStdio(); 844 debugStdio();
839 // Give the server 1 second to continue outputting bad data before we kill 845 // Give the server 1 second to continue outputting bad data before we kill
(...skipping 12 matching lines...) Expand all
852 */ 858 */
853 void _recordStdio(String line) { 859 void _recordStdio(String line) {
854 double elapsedTime = _time.elapsedTicks / _time.frequency; 860 double elapsedTime = _time.elapsedTicks / _time.frequency;
855 line = "$elapsedTime: $line"; 861 line = "$elapsedTime: $line";
856 if (_debuggingStdio) { 862 if (_debuggingStdio) {
857 print(line); 863 print(line);
858 } 864 }
859 _recordedStdio.add(line); 865 _recordedStdio.add(line);
860 } 866 }
861 } 867 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698