| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library test.channel; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:convert'; | |
| 9 import 'dart:io'; | |
| 10 | |
| 11 import 'package:analysis_server/src/channel.dart'; | |
| 12 import 'package:analysis_server/src/protocol.dart' hide Error; | |
| 13 import 'package:unittest/unittest.dart'; | |
| 14 | |
| 15 import 'mocks.dart'; | |
| 16 | |
| 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', () { | |
| 30 setUp(ByteStreamClientChannelTest.setUp); | |
| 31 test('close', ByteStreamClientChannelTest.close); | |
| 32 test('listen_notification', ByteStreamClientChannelTest.listen_notification)
; | |
| 33 test('listen_response', ByteStreamClientChannelTest.listen_response); | |
| 34 test('sendRequest', ByteStreamClientChannelTest.sendRequest); | |
| 35 }); | |
| 36 group('ByteStreamServerChannel', () { | |
| 37 setUp(ByteStreamServerChannelTest.setUp); | |
| 38 test('closed', ByteStreamServerChannelTest.closed); | |
| 39 test('listen_wellFormedRequest', | |
| 40 ByteStreamServerChannelTest.listen_wellFormedRequest); | |
| 41 test('listen_invalidRequest', | |
| 42 ByteStreamServerChannelTest.listen_invalidRequest); | |
| 43 test('listen_invalidJson', ByteStreamServerChannelTest.listen_invalidJson); | |
| 44 test('listen_streamError', ByteStreamServerChannelTest.listen_streamError); | |
| 45 test('listen_streamDone', ByteStreamServerChannelTest.listen_streamDone); | |
| 46 test('sendNotification', ByteStreamServerChannelTest.sendNotification); | |
| 47 test('sendResponse', ByteStreamServerChannelTest.sendResponse); | |
| 48 }); | |
| 49 } | |
| 50 | |
| 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 { | |
| 184 static ByteStreamClientChannel channel; | |
| 185 | |
| 186 /** | |
| 187 * Sink that may be used to deliver data to the channel, as though it's | |
| 188 * coming from the server. | |
| 189 */ | |
| 190 static IOSink inputSink; | |
| 191 | |
| 192 /** | |
| 193 * Sink through which the channel delivers data to the server. | |
| 194 */ | |
| 195 static IOSink outputSink; | |
| 196 | |
| 197 /** | |
| 198 * Stream of lines sent back to the client by the channel. | |
| 199 */ | |
| 200 static Stream<String> outputLineStream; | |
| 201 | |
| 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() { | |
| 213 bool doneCalled = false; | |
| 214 bool closeCalled = false; | |
| 215 // add listener so that outputSink will trigger done/close futures | |
| 216 outputLineStream.listen((_) { /* no-op */ }); | |
| 217 outputSink.done.then((_) { | |
| 218 doneCalled = true; | |
| 219 }); | |
| 220 channel.close().then((_) { | |
| 221 closeCalled = true; | |
| 222 }); | |
| 223 return pumpEventQueue().then((_) { | |
| 224 expect(doneCalled, isTrue); | |
| 225 expect(closeCalled, isTrue); | |
| 226 }); | |
| 227 } | |
| 228 | |
| 229 static Future listen_notification() { | |
| 230 List<Notification> notifications = []; | |
| 231 channel.notificationStream.forEach((n) => notifications.add(n)); | |
| 232 inputSink.writeln('{"event":"server.connected"}'); | |
| 233 return pumpEventQueue().then((_) { | |
| 234 expect(notifications.length, equals(1)); | |
| 235 expect(notifications[0].event, equals('server.connected')); | |
| 236 }); | |
| 237 } | |
| 238 | |
| 239 static Future listen_response() { | |
| 240 List<Response> responses = []; | |
| 241 channel.responseStream.forEach((n) => responses.add(n)); | |
| 242 inputSink.writeln('{"id":"72"}'); | |
| 243 return pumpEventQueue().then((_) { | |
| 244 expect(responses.length, equals(1)); | |
| 245 expect(responses[0].id, equals('72')); | |
| 246 }); | |
| 247 } | |
| 248 | |
| 249 static Future sendRequest() { | |
| 250 int assertCount = 0; | |
| 251 Request request = new Request('72', 'foo.bar'); | |
| 252 outputLineStream.first | |
| 253 .then((line) => JSON.decode(line)) | |
| 254 .then((json) { | |
| 255 expect(json[Request.ID], equals('72')); | |
| 256 expect(json[Request.METHOD], equals('foo.bar')); | |
| 257 inputSink.writeln('{"id":"73"}'); | |
| 258 inputSink.writeln('{"id":"72"}'); | |
| 259 assertCount++; | |
| 260 }); | |
| 261 channel.sendRequest(request) | |
| 262 .then((Response response) { | |
| 263 expect(response.id, equals('72')); | |
| 264 assertCount++; | |
| 265 }); | |
| 266 return pumpEventQueue().then((_) => expect(assertCount, equals(2))); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 class ByteStreamServerChannelTest { | |
| 271 static ByteStreamServerChannel channel; | |
| 272 | |
| 273 /** | |
| 274 * Sink that may be used to deliver data to the channel, as though it's | |
| 275 * coming from the client. | |
| 276 */ | |
| 277 static IOSink inputSink; | |
| 278 | |
| 279 /** | |
| 280 * Stream of lines sent back to the client by the channel. | |
| 281 */ | |
| 282 static Stream<String> outputLineStream; | |
| 283 | |
| 284 /** | |
| 285 * Stream of requests received from the channel via [listen()]. | |
| 286 */ | |
| 287 static Stream<Request> requestStream; | |
| 288 | |
| 289 /** | |
| 290 * Stream of errors received from the channel via [listen()]. | |
| 291 */ | |
| 292 static Stream errorStream; | |
| 293 | |
| 294 /** | |
| 295 * Future which is completed when then [listen()] reports [onDone]. | |
| 296 */ | |
| 297 static Future doneFuture; | |
| 298 | |
| 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() { | |
| 325 return inputSink.close().then((_) => channel.closed.timeout(new Duration( | |
| 326 seconds: 1))); | |
| 327 } | |
| 328 | |
| 329 static Future listen_wellFormedRequest() { | |
| 330 inputSink.writeln('{"id":"0","method":"server.version"}'); | |
| 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( | |
| 341 new Duration(seconds: 1))).then((String response) { | |
| 342 var jsonResponse = new JsonCodec().decode(response); | |
| 343 expect(jsonResponse, isMap); | |
| 344 expect(jsonResponse, contains('error')); | |
| 345 expect(jsonResponse['error'], isNotNull); | |
| 346 }); | |
| 347 } | |
| 348 | |
| 349 static Future listen_invalidJson() { | |
| 350 inputSink.writeln('{"id":'); | |
| 351 return inputSink.flush().then((_) => outputLineStream.first.timeout( | |
| 352 new Duration(seconds: 1))).then((String response) { | |
| 353 var jsonResponse = new JsonCodec().decode(response); | |
| 354 expect(jsonResponse, isMap); | |
| 355 expect(jsonResponse, contains('error')); | |
| 356 expect(jsonResponse['error'], isNotNull); | |
| 357 }); | |
| 358 } | |
| 359 | |
| 360 static Future listen_streamError() { | |
| 361 var error = new Error(); | |
| 362 inputSink.addError(error); | |
| 363 return inputSink.flush().then((_) => errorStream.first.timeout(new Duration( | |
| 364 seconds: 1))).then((var receivedError) { | |
| 365 expect(receivedError, same(error)); | |
| 366 }); | |
| 367 } | |
| 368 | |
| 369 static Future listen_streamDone() { | |
| 370 return inputSink.close().then((_) => doneFuture.timeout(new Duration( | |
| 371 seconds: 1))); | |
| 372 } | |
| 373 | |
| 374 static Future sendNotification() { | |
| 375 channel.sendNotification(new Notification('foo')); | |
| 376 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String | |
| 377 notification) { | |
| 378 var jsonNotification = new JsonCodec().decode(notification); | |
| 379 expect(jsonNotification, isMap); | |
| 380 expect(jsonNotification, contains('event')); | |
| 381 expect(jsonNotification['event'], equals('foo')); | |
| 382 }); | |
| 383 } | |
| 384 | |
| 385 static Future sendResponse() { | |
| 386 channel.sendResponse(new Response('foo')); | |
| 387 return outputLineStream.first.timeout(new Duration(seconds: 1)).then((String | |
| 388 response) { | |
| 389 var jsonResponse = new JsonCodec().decode(response); | |
| 390 expect(jsonResponse, isMap); | |
| 391 expect(jsonResponse, contains('id')); | |
| 392 expect(jsonResponse['id'], equals('foo')); | |
| 393 }); | |
| 394 } | |
| 395 } | |
| OLD | NEW |