| 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.channel; | 5 library test.channel.byte_stream; |
| 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 | 10 |
| 11 import 'package:analysis_server/src/channel.dart'; | 11 import 'package:analysis_server/src/channel/byte_stream_channel.dart'; |
| 12 import 'package:analysis_server/src/protocol.dart' hide Error; | 12 import 'package:analysis_server/src/protocol.dart'; |
| 13 import 'package:unittest/unittest.dart'; | 13 import 'package:unittest/unittest.dart'; |
| 14 | 14 |
| 15 import 'mocks.dart'; | 15 import '../mocks.dart'; |
| 16 | 16 |
| 17 main() { | 17 main() { |
| 18 group('WebSocketChannel', () { | |
| 19 setUp(WebSocketChannelTest.setUp); | |
| 20 test('close', WebSocketChannelTest.close); | |
| 21 test('invalidJsonToClient', WebSocketChannelTest.invalidJsonToClient); | |
| 22 test('invalidJsonToServer', WebSocketChannelTest.invalidJsonToServer); | |
| 23 test('notification', WebSocketChannelTest.notification); | |
| 24 test('notificationAndResponse', WebSocketChannelTest.notificationAndResponse
); | |
| 25 test('request', WebSocketChannelTest.request); | |
| 26 test('requestResponse', WebSocketChannelTest.requestResponse); | |
| 27 test('response', WebSocketChannelTest.response); | |
| 28 }); | |
| 29 group('ByteStreamClientChannel', () { | 18 group('ByteStreamClientChannel', () { |
| 30 setUp(ByteStreamClientChannelTest.setUp); | 19 setUp(ByteStreamClientChannelTest.setUp); |
| 31 test('close', ByteStreamClientChannelTest.close); | 20 test('close', ByteStreamClientChannelTest.close); |
| 32 test('listen_notification', ByteStreamClientChannelTest.listen_notification)
; | 21 test('listen_notification', ByteStreamClientChannelTest.listen_notification)
; |
| 33 test('listen_response', ByteStreamClientChannelTest.listen_response); | 22 test('listen_response', ByteStreamClientChannelTest.listen_response); |
| 34 test('sendRequest', ByteStreamClientChannelTest.sendRequest); | 23 test('sendRequest', ByteStreamClientChannelTest.sendRequest); |
| 35 }); | 24 }); |
| 36 group('ByteStreamServerChannel', () { | 25 group('ByteStreamServerChannel', () { |
| 37 setUp(ByteStreamServerChannelTest.setUp); | 26 setUp(ByteStreamServerChannelTest.setUp); |
| 38 test('closed', ByteStreamServerChannelTest.closed); | 27 test('closed', ByteStreamServerChannelTest.closed); |
| 39 test('listen_wellFormedRequest', | 28 test('listen_wellFormedRequest', |
| 40 ByteStreamServerChannelTest.listen_wellFormedRequest); | 29 ByteStreamServerChannelTest.listen_wellFormedRequest); |
| 41 test('listen_invalidRequest', | 30 test('listen_invalidRequest', |
| 42 ByteStreamServerChannelTest.listen_invalidRequest); | 31 ByteStreamServerChannelTest.listen_invalidRequest); |
| 43 test('listen_invalidJson', ByteStreamServerChannelTest.listen_invalidJson); | 32 test('listen_invalidJson', ByteStreamServerChannelTest.listen_invalidJson); |
| 44 test('listen_streamError', ByteStreamServerChannelTest.listen_streamError); | 33 test('listen_streamError', ByteStreamServerChannelTest.listen_streamError); |
| 45 test('listen_streamDone', ByteStreamServerChannelTest.listen_streamDone); | 34 test('listen_streamDone', ByteStreamServerChannelTest.listen_streamDone); |
| 46 test('sendNotification', ByteStreamServerChannelTest.sendNotification); | 35 test('sendNotification', ByteStreamServerChannelTest.sendNotification); |
| 47 test('sendResponse', ByteStreamServerChannelTest.sendResponse); | 36 test('sendResponse', ByteStreamServerChannelTest.sendResponse); |
| 48 }); | 37 }); |
| 49 } | 38 } |
| 50 | 39 |
| 51 class WebSocketChannelTest { | |
| 52 static MockSocket socket; | |
| 53 static WebSocketClientChannel client; | |
| 54 static WebSocketServerChannel server; | |
| 55 | |
| 56 static List requestsReceived; | |
| 57 static List responsesReceived; | |
| 58 static List notificationsReceived; | |
| 59 | |
| 60 static void setUp() { | |
| 61 socket = new MockSocket.pair(); | |
| 62 client = new WebSocketClientChannel(socket); | |
| 63 server = new WebSocketServerChannel(socket.twin); | |
| 64 | |
| 65 requestsReceived = []; | |
| 66 responsesReceived = []; | |
| 67 notificationsReceived = []; | |
| 68 | |
| 69 // Allow multiple listeners on server side for testing. | |
| 70 socket.twin.allowMultipleListeners(); | |
| 71 | |
| 72 server.listen(requestsReceived.add); | |
| 73 client.responseStream.listen(responsesReceived.add); | |
| 74 client.notificationStream.listen(notificationsReceived.add); | |
| 75 } | |
| 76 | |
| 77 static Future close() { | |
| 78 var timeout = new Duration(seconds: 1); | |
| 79 var future = client.responseStream.drain().timeout(timeout); | |
| 80 client.close(); | |
| 81 return future; | |
| 82 } | |
| 83 | |
| 84 static Future invalidJsonToClient() { | |
| 85 var result = client.responseStream | |
| 86 .first | |
| 87 .timeout(new Duration(seconds: 1)) | |
| 88 .then((Response response) { | |
| 89 expect(response.id, equals('myId')); | |
| 90 expectMsgCount(responseCount: 1); | |
| 91 }); | |
| 92 socket.twin.add('{"foo":"bar"}'); | |
| 93 server.sendResponse(new Response('myId')); | |
| 94 return result; | |
| 95 } | |
| 96 | |
| 97 static Future invalidJsonToServer() { | |
| 98 var result = client.responseStream | |
| 99 .first | |
| 100 .timeout(new Duration(seconds: 1)) | |
| 101 .then((Response response) { | |
| 102 expect(response.id, equals('')); | |
| 103 expect(response.error, isNotNull); | |
| 104 expectMsgCount(responseCount: 1); | |
| 105 }); | |
| 106 socket.add('"blat"'); | |
| 107 return result; | |
| 108 } | |
| 109 | |
| 110 static Future notification() { | |
| 111 var result = client.notificationStream | |
| 112 .first | |
| 113 .timeout(new Duration(seconds: 1)) | |
| 114 .then((Notification notification) { | |
| 115 expect(notification.event, equals('myEvent')); | |
| 116 expectMsgCount(notificationCount: 1); | |
| 117 expect(notificationsReceived.first, equals(notification)); | |
| 118 }); | |
| 119 server.sendNotification(new Notification('myEvent')); | |
| 120 return result; | |
| 121 } | |
| 122 | |
| 123 static Future notificationAndResponse() { | |
| 124 var result = Future | |
| 125 .wait([ | |
| 126 client.notificationStream.first, | |
| 127 client.responseStream.first]) | |
| 128 .timeout(new Duration(seconds: 1)) | |
| 129 .then((_) => expectMsgCount(responseCount: 1, notificationCount: 1)); | |
| 130 server | |
| 131 ..sendNotification(new Notification('myEvent')) | |
| 132 ..sendResponse(new Response('myId')); | |
| 133 return result; | |
| 134 } | |
| 135 | |
| 136 static void request() { | |
| 137 client.sendRequest(new Request('myId', 'myMth')); | |
| 138 server.listen((Request request) { | |
| 139 expect(request.id, equals('myId')); | |
| 140 expect(request.method, equals('myMth')); | |
| 141 expectMsgCount(requestCount: 1); | |
| 142 }); | |
| 143 } | |
| 144 | |
| 145 static Future requestResponse() { | |
| 146 // Simulate server sending a response by echoing the request. | |
| 147 server.listen((Request request) => | |
| 148 server.sendResponse(new Response(request.id))); | |
| 149 return client.sendRequest(new Request('myId', 'myMth')) | |
| 150 .timeout(new Duration(seconds: 1)) | |
| 151 .then((Response response) { | |
| 152 expect(response.id, equals('myId')); | |
| 153 expectMsgCount(requestCount: 1, responseCount: 1); | |
| 154 | |
| 155 expect(requestsReceived.first is Request, isTrue); | |
| 156 Request request = requestsReceived.first; | |
| 157 expect(request.id, equals('myId')); | |
| 158 expect(request.method, equals('myMth')); | |
| 159 expect(responsesReceived.first, equals(response)); | |
| 160 }); | |
| 161 } | |
| 162 | |
| 163 static Future response() { | |
| 164 server.sendResponse(new Response('myId')); | |
| 165 return client.responseStream | |
| 166 .first | |
| 167 .timeout(new Duration(seconds: 1)) | |
| 168 .then((Response response) { | |
| 169 expect(response.id, equals('myId')); | |
| 170 expectMsgCount(responseCount: 1); | |
| 171 }); | |
| 172 } | |
| 173 | |
| 174 static void expectMsgCount({requestCount: 0, | |
| 175 responseCount: 0, | |
| 176 notificationCount: 0}) { | |
| 177 expect(requestsReceived, hasLength(requestCount)); | |
| 178 expect(responsesReceived, hasLength(responseCount)); | |
| 179 expect(notificationsReceived, hasLength(notificationCount)); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 class ByteStreamClientChannelTest { | 40 class ByteStreamClientChannelTest { |
| 184 static ByteStreamClientChannel channel; | 41 static ByteStreamClientChannel channel; |
| 185 | 42 |
| 186 /** | 43 /** |
| 187 * Sink that may be used to deliver data to the channel, as though it's | 44 * Sink that may be used to deliver data to the channel, as though it's |
| 188 * coming from the server. | 45 * coming from the server. |
| 189 */ | 46 */ |
| 190 static IOSink inputSink; | 47 static IOSink inputSink; |
| 191 | 48 |
| 192 /** | 49 /** |
| 193 * Sink through which the channel delivers data to the server. | 50 * Sink through which the channel delivers data to the server. |
| 194 */ | 51 */ |
| 195 static IOSink outputSink; | 52 static IOSink outputSink; |
| 196 | 53 |
| 197 /** | 54 /** |
| 198 * Stream of lines sent back to the client by the channel. | 55 * Stream of lines sent back to the client by the channel. |
| 199 */ | 56 */ |
| 200 static Stream<String> outputLineStream; | 57 static Stream<String> outputLineStream; |
| 201 | 58 |
| 202 static void setUp() { | |
| 203 var inputStream = new StreamController<List<int>>(); | |
| 204 inputSink = new IOSink(inputStream); | |
| 205 var outputStream = new StreamController<List<int>>(); | |
| 206 outputLineStream = outputStream.stream.transform((new Utf8Codec()).decoder | |
| 207 ).transform(new LineSplitter()); | |
| 208 outputSink = new IOSink(outputStream); | |
| 209 channel = new ByteStreamClientChannel(inputStream.stream, outputSink); | |
| 210 } | |
| 211 | |
| 212 static Future close() { | 59 static Future close() { |
| 213 bool doneCalled = false; | 60 bool doneCalled = false; |
| 214 bool closeCalled = false; | 61 bool closeCalled = false; |
| 215 // add listener so that outputSink will trigger done/close futures | 62 // add listener so that outputSink will trigger done/close futures |
| 216 outputLineStream.listen((_) { /* no-op */ }); | 63 outputLineStream.listen((_) { /* no-op */ }); |
| 217 outputSink.done.then((_) { | 64 outputSink.done.then((_) { |
| 218 doneCalled = true; | 65 doneCalled = true; |
| 219 }); | 66 }); |
| 220 channel.close().then((_) { | 67 channel.close().then((_) { |
| 221 closeCalled = true; | 68 closeCalled = true; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 inputSink.writeln('{"id":"72"}'); | 105 inputSink.writeln('{"id":"72"}'); |
| 259 assertCount++; | 106 assertCount++; |
| 260 }); | 107 }); |
| 261 channel.sendRequest(request) | 108 channel.sendRequest(request) |
| 262 .then((Response response) { | 109 .then((Response response) { |
| 263 expect(response.id, equals('72')); | 110 expect(response.id, equals('72')); |
| 264 assertCount++; | 111 assertCount++; |
| 265 }); | 112 }); |
| 266 return pumpEventQueue().then((_) => expect(assertCount, equals(2))); | 113 return pumpEventQueue().then((_) => expect(assertCount, equals(2))); |
| 267 } | 114 } |
| 115 |
| 116 static void setUp() { |
| 117 var inputStream = new StreamController<List<int>>(); |
| 118 inputSink = new IOSink(inputStream); |
| 119 var outputStream = new StreamController<List<int>>(); |
| 120 outputLineStream = outputStream.stream.transform((new Utf8Codec()).decoder |
| 121 ).transform(new LineSplitter()); |
| 122 outputSink = new IOSink(outputStream); |
| 123 channel = new ByteStreamClientChannel(inputStream.stream, outputSink); |
| 124 } |
| 268 } | 125 } |
| 269 | 126 |
| 270 class ByteStreamServerChannelTest { | 127 class ByteStreamServerChannelTest { |
| 271 static ByteStreamServerChannel channel; | 128 static ByteStreamServerChannel channel; |
| 272 | 129 |
| 273 /** | 130 /** |
| 274 * Sink that may be used to deliver data to the channel, as though it's | 131 * Sink that may be used to deliver data to the channel, as though it's |
| 275 * coming from the client. | 132 * coming from the client. |
| 276 */ | 133 */ |
| 277 static IOSink inputSink; | 134 static IOSink inputSink; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 289 /** | 146 /** |
| 290 * Stream of errors received from the channel via [listen()]. | 147 * Stream of errors received from the channel via [listen()]. |
| 291 */ | 148 */ |
| 292 static Stream errorStream; | 149 static Stream errorStream; |
| 293 | 150 |
| 294 /** | 151 /** |
| 295 * Future which is completed when then [listen()] reports [onDone]. | 152 * Future which is completed when then [listen()] reports [onDone]. |
| 296 */ | 153 */ |
| 297 static Future doneFuture; | 154 static Future doneFuture; |
| 298 | 155 |
| 299 static void setUp() { | |
| 300 StreamController<List<int>> inputStream = new StreamController<List<int>>(); | |
| 301 inputSink = new IOSink(inputStream); | |
| 302 StreamController<List<int>> outputStream = new StreamController<List<int>>( | |
| 303 ); | |
| 304 outputLineStream = outputStream.stream.transform((new Utf8Codec()).decoder | |
| 305 ).transform(new LineSplitter()); | |
| 306 IOSink outputSink = new IOSink(outputStream); | |
| 307 channel = new ByteStreamServerChannel(inputStream.stream, outputSink); | |
| 308 StreamController<Request> requestStreamController = | |
| 309 new StreamController<Request>(); | |
| 310 requestStream = requestStreamController.stream; | |
| 311 StreamController errorStreamController = new StreamController(); | |
| 312 errorStream = errorStreamController.stream; | |
| 313 Completer doneCompleter = new Completer(); | |
| 314 doneFuture = doneCompleter.future; | |
| 315 channel.listen((Request request) { | |
| 316 requestStreamController.add(request); | |
| 317 }, onError: (error) { | |
| 318 errorStreamController.add(error); | |
| 319 }, onDone: () { | |
| 320 doneCompleter.complete(); | |
| 321 }); | |
| 322 } | |
| 323 | |
| 324 static Future closed() { | 156 static Future closed() { |
| 325 return inputSink.close().then((_) => channel.closed.timeout(new Duration( | 157 return inputSink.close().then((_) => channel.closed.timeout(new Duration( |
| 326 seconds: 1))); | 158 seconds: 1))); |
| 327 } | 159 } |
| 328 | 160 |
| 329 static Future listen_wellFormedRequest() { | 161 static Future listen_invalidJson() { |
| 330 inputSink.writeln('{"id":"0","method":"server.version"}'); | 162 inputSink.writeln('{"id":'); |
| 331 return inputSink.flush().then((_) => requestStream.first.timeout( | |
| 332 new Duration(seconds: 1))).then((Request request) { | |
| 333 expect(request.id, equals("0")); | |
| 334 expect(request.method, equals("server.version")); | |
| 335 }); | |
| 336 } | |
| 337 | |
| 338 static Future listen_invalidRequest() { | |
| 339 inputSink.writeln('{"id":"0"}'); | |
| 340 return inputSink.flush().then((_) => outputLineStream.first.timeout( | 163 return inputSink.flush().then((_) => outputLineStream.first.timeout( |
| 341 new Duration(seconds: 1))).then((String response) { | 164 new Duration(seconds: 1))).then((String response) { |
| 342 var jsonResponse = new JsonCodec().decode(response); | 165 var jsonResponse = new JsonCodec().decode(response); |
| 343 expect(jsonResponse, isMap); | 166 expect(jsonResponse, isMap); |
| 344 expect(jsonResponse, contains('error')); | 167 expect(jsonResponse, contains('error')); |
| 345 expect(jsonResponse['error'], isNotNull); | 168 expect(jsonResponse['error'], isNotNull); |
| 346 }); | 169 }); |
| 347 } | 170 } |
| 348 | 171 |
| 349 static Future listen_invalidJson() { | 172 static Future listen_invalidRequest() { |
| 350 inputSink.writeln('{"id":'); | 173 inputSink.writeln('{"id":"0"}'); |
| 351 return inputSink.flush().then((_) => outputLineStream.first.timeout( | 174 return inputSink.flush().then((_) => outputLineStream.first.timeout( |
| 352 new Duration(seconds: 1))).then((String response) { | 175 new Duration(seconds: 1))).then((String response) { |
| 353 var jsonResponse = new JsonCodec().decode(response); | 176 var jsonResponse = new JsonCodec().decode(response); |
| 354 expect(jsonResponse, isMap); | 177 expect(jsonResponse, isMap); |
| 355 expect(jsonResponse, contains('error')); | 178 expect(jsonResponse, contains('error')); |
| 356 expect(jsonResponse['error'], isNotNull); | 179 expect(jsonResponse['error'], isNotNull); |
| 357 }); | 180 }); |
| 358 } | 181 } |
| 359 | 182 |
| 183 static Future listen_streamDone() { |
| 184 return inputSink.close().then((_) => doneFuture.timeout(new Duration( |
| 185 seconds: 1))); |
| 186 } |
| 187 |
| 360 static Future listen_streamError() { | 188 static Future listen_streamError() { |
| 361 var error = new Error(); | 189 var error = new Error(); |
| 362 inputSink.addError(error); | 190 inputSink.addError(error); |
| 363 return inputSink.flush().then((_) => errorStream.first.timeout(new Duration( | 191 return inputSink.flush().then((_) => errorStream.first.timeout(new Duration( |
| 364 seconds: 1))).then((var receivedError) { | 192 seconds: 1))).then((var receivedError) { |
| 365 expect(receivedError, same(error)); | 193 expect(receivedError, same(error)); |
| 366 }); | 194 }); |
| 367 } | 195 } |
| 368 | 196 |
| 369 static Future listen_streamDone() { | 197 static Future listen_wellFormedRequest() { |
| 370 return inputSink.close().then((_) => doneFuture.timeout(new Duration( | 198 inputSink.writeln('{"id":"0","method":"server.version"}'); |
| 371 seconds: 1))); | 199 return inputSink.flush().then((_) => requestStream.first.timeout( |
| 200 new Duration(seconds: 1))).then((Request request) { |
| 201 expect(request.id, equals("0")); |
| 202 expect(request.method, equals("server.version")); |
| 203 }); |
| 372 } | 204 } |
| 373 | 205 |
| 374 static Future sendNotification() { | 206 static Future sendNotification() { |
| 375 channel.sendNotification(new Notification('foo')); | 207 channel.sendNotification(new Notification('foo')); |
| 376 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String | 208 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String |
| 377 notification) { | 209 notification) { |
| 378 var jsonNotification = new JsonCodec().decode(notification); | 210 var jsonNotification = new JsonCodec().decode(notification); |
| 379 expect(jsonNotification, isMap); | 211 expect(jsonNotification, isMap); |
| 380 expect(jsonNotification, contains('event')); | 212 expect(jsonNotification, contains('event')); |
| 381 expect(jsonNotification['event'], equals('foo')); | 213 expect(jsonNotification['event'], equals('foo')); |
| 382 }); | 214 }); |
| 383 } | 215 } |
| 384 | 216 |
| 385 static Future sendResponse() { | 217 static Future sendResponse() { |
| 386 channel.sendResponse(new Response('foo')); | 218 channel.sendResponse(new Response('foo')); |
| 387 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String | 219 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String |
| 388 response) { | 220 response) { |
| 389 var jsonResponse = new JsonCodec().decode(response); | 221 var jsonResponse = new JsonCodec().decode(response); |
| 390 expect(jsonResponse, isMap); | 222 expect(jsonResponse, isMap); |
| 391 expect(jsonResponse, contains('id')); | 223 expect(jsonResponse, contains('id')); |
| 392 expect(jsonResponse['id'], equals('foo')); | 224 expect(jsonResponse['id'], equals('foo')); |
| 393 }); | 225 }); |
| 394 } | 226 } |
| 227 |
| 228 static void setUp() { |
| 229 StreamController<List<int>> inputStream = new StreamController<List<int>>(); |
| 230 inputSink = new IOSink(inputStream); |
| 231 StreamController<List<int>> outputStream = new StreamController<List<int>>( |
| 232 ); |
| 233 outputLineStream = outputStream.stream.transform((new Utf8Codec()).decoder |
| 234 ).transform(new LineSplitter()); |
| 235 IOSink outputSink = new IOSink(outputStream); |
| 236 channel = new ByteStreamServerChannel(inputStream.stream, outputSink); |
| 237 StreamController<Request> requestStreamController = |
| 238 new StreamController<Request>(); |
| 239 requestStream = requestStreamController.stream; |
| 240 StreamController errorStreamController = new StreamController(); |
| 241 errorStream = errorStreamController.stream; |
| 242 Completer doneCompleter = new Completer(); |
| 243 doneFuture = doneCompleter.future; |
| 244 channel.listen((Request request) { |
| 245 requestStreamController.add(request); |
| 246 }, onError: (error) { |
| 247 errorStreamController.add(error); |
| 248 }, onDone: () { |
| 249 doneCompleter.complete(); |
| 250 }); |
| 251 } |
| 395 } | 252 } |
| OLD | NEW |