dom/network/tests/unit/test_tcpsocket.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /**
michael@0 2 * Test TCPSocket.js by creating an XPCOM-style server socket, then sending
michael@0 3 * data in both directions and making sure each side receives their data
michael@0 4 * correctly and with the proper events.
michael@0 5 *
michael@0 6 * This test is derived from netwerk/test/unit/test_socks.js, except we don't
michael@0 7 * involve a subprocess.
michael@0 8 *
michael@0 9 * Future work:
michael@0 10 * - SSL. see https://bugzilla.mozilla.org/show_bug.cgi?id=466524
michael@0 11 * https://bugzilla.mozilla.org/show_bug.cgi?id=662180
michael@0 12 * Alternatively, mochitests could be used.
michael@0 13 * - Testing overflow logic.
michael@0 14 *
michael@0 15 **/
michael@0 16
michael@0 17 const Cc = Components.classes;
michael@0 18 const Ci = Components.interfaces;
michael@0 19 const Cr = Components.results;
michael@0 20 const Cu = Components.utils;
michael@0 21 const CC = Components.Constructor;
michael@0 22
michael@0 23 /**
michael@0 24 *
michael@0 25 * Constants
michael@0 26 *
michael@0 27 */
michael@0 28
michael@0 29 // Some binary data to send.
michael@0 30 const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0],
michael@0 31 DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length),
michael@0 32 TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER),
michael@0 33 HELLO_WORLD = "hlo wrld. ",
michael@0 34 BIG_ARRAY = new Array(65539),
michael@0 35 BIG_ARRAY_2 = new Array(65539);
michael@0 36
michael@0 37 TYPED_DATA_ARRAY.set(DATA_ARRAY, 0);
michael@0 38
michael@0 39 for (var i_big = 0; i_big < BIG_ARRAY.length; i_big++) {
michael@0 40 BIG_ARRAY[i_big] = Math.floor(Math.random() * 256);
michael@0 41 BIG_ARRAY_2[i_big] = Math.floor(Math.random() * 256);
michael@0 42 }
michael@0 43
michael@0 44 const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length),
michael@0 45 BIG_ARRAY_BUFFER_2 = new ArrayBuffer(BIG_ARRAY_2.length);
michael@0 46 const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER),
michael@0 47 BIG_TYPED_ARRAY_2 = new Uint8Array(BIG_ARRAY_BUFFER_2);
michael@0 48 BIG_TYPED_ARRAY.set(BIG_ARRAY);
michael@0 49 BIG_TYPED_ARRAY_2.set(BIG_ARRAY_2);
michael@0 50
michael@0 51 const ServerSocket = CC("@mozilla.org/network/server-socket;1",
michael@0 52 "nsIServerSocket",
michael@0 53 "init"),
michael@0 54 InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
michael@0 55 "nsIInputStreamPump",
michael@0 56 "init"),
michael@0 57 BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
michael@0 58 "nsIBinaryInputStream",
michael@0 59 "setInputStream"),
michael@0 60 BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
michael@0 61 "nsIBinaryOutputStream",
michael@0 62 "setOutputStream"),
michael@0 63 TCPSocket = new (CC("@mozilla.org/tcp-socket;1",
michael@0 64 "nsIDOMTCPSocket"))();
michael@0 65
michael@0 66 const gInChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
michael@0 67 .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
michael@0 68
michael@0 69 Cu.import("resource://gre/modules/Services.jsm");
michael@0 70
michael@0 71 /**
michael@0 72 *
michael@0 73 * Helper functions
michael@0 74 *
michael@0 75 */
michael@0 76
michael@0 77 function get_platform() {
michael@0 78 var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
michael@0 79 .getService(Components.interfaces.nsIXULRuntime);
michael@0 80 return xulRuntime.OS;
michael@0 81 }
michael@0 82
michael@0 83 function is_content() {
michael@0 84 return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
michael@0 85 .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
michael@0 86 }
michael@0 87
michael@0 88 /**
michael@0 89 * Spin up a listening socket and associate at most one live, accepted socket
michael@0 90 * with ourselves.
michael@0 91 */
michael@0 92 function TestServer() {
michael@0 93 this.listener = ServerSocket(-1, true, -1);
michael@0 94 do_print('server: listening on', this.listener.port);
michael@0 95 this.listener.asyncListen(this);
michael@0 96
michael@0 97 this.binaryInput = null;
michael@0 98 this.input = null;
michael@0 99 this.binaryOutput = null;
michael@0 100 this.output = null;
michael@0 101
michael@0 102 this.onconnect = null;
michael@0 103 this.ondata = null;
michael@0 104 this.onclose = null;
michael@0 105 }
michael@0 106
michael@0 107 TestServer.prototype = {
michael@0 108 onSocketAccepted: function(socket, trans) {
michael@0 109 if (this.input)
michael@0 110 do_throw("More than one live connection!?");
michael@0 111
michael@0 112 do_print('server: got client connection');
michael@0 113 this.input = trans.openInputStream(0, 0, 0);
michael@0 114 this.binaryInput = new BinaryInputStream(this.input);
michael@0 115 this.output = trans.openOutputStream(0, 0, 0);
michael@0 116 this.binaryOutput = new BinaryOutputStream(this.output);
michael@0 117
michael@0 118 new InputStreamPump(this.input, -1, -1, 0, 0, false).asyncRead(this, null);
michael@0 119
michael@0 120 if (this.onconnect)
michael@0 121 this.onconnect();
michael@0 122 else
michael@0 123 do_throw("Received unexpected connection!");
michael@0 124 },
michael@0 125
michael@0 126 onStopListening: function(socket) {
michael@0 127 },
michael@0 128
michael@0 129 onDataAvailable: function(request, context, inputStream, offset, count) {
michael@0 130 var readData = this.binaryInput.readByteArray(count);
michael@0 131 if (this.ondata) {
michael@0 132 try {
michael@0 133 this.ondata(readData);
michael@0 134 } catch(ex) {
michael@0 135 // re-throw if this is from do_throw
michael@0 136 if (ex === Cr.NS_ERROR_ABORT)
michael@0 137 throw ex;
michael@0 138 // log if there was a test problem
michael@0 139 do_print('Caught exception: ' + ex + '\n' + ex.stack);
michael@0 140 do_throw('test is broken; bad ondata handler; see above');
michael@0 141 }
michael@0 142 } else {
michael@0 143 do_throw('Received ' + count + ' bytes of unexpected data!');
michael@0 144 }
michael@0 145 },
michael@0 146
michael@0 147 onStartRequest: function(request, context) {
michael@0 148 },
michael@0 149
michael@0 150 onStopRequest: function(request, context, status) {
michael@0 151 if (this.onclose)
michael@0 152 this.onclose();
michael@0 153 else
michael@0 154 do_throw("Received unexpected close!");
michael@0 155 },
michael@0 156
michael@0 157 close: function() {
michael@0 158 this.binaryInput.close();
michael@0 159 this.binaryOutput.close();
michael@0 160 },
michael@0 161
michael@0 162 /**
michael@0 163 * Forget about the socket we knew about before.
michael@0 164 */
michael@0 165 reset: function() {
michael@0 166 this.binaryInput = null;
michael@0 167 this.input = null;
michael@0 168 this.binaryOutput = null;
michael@0 169 this.output = null;
michael@0 170 },
michael@0 171 };
michael@0 172
michael@0 173 function makeSuccessCase(name) {
michael@0 174 return function() {
michael@0 175 do_print('got expected: ' + name);
michael@0 176 run_next_test();
michael@0 177 };
michael@0 178 }
michael@0 179
michael@0 180 function makeJointSuccess(names) {
michael@0 181 let funcs = {}, successCount = 0;
michael@0 182 names.forEach(function(name) {
michael@0 183 funcs[name] = function() {
michael@0 184 do_print('got expected: ' + name);
michael@0 185 if (++successCount === names.length)
michael@0 186 run_next_test();
michael@0 187 };
michael@0 188 });
michael@0 189 return funcs;
michael@0 190 }
michael@0 191
michael@0 192 function makeFailureCase(name) {
michael@0 193 return function() {
michael@0 194 let argstr;
michael@0 195 if (arguments.length) {
michael@0 196 argstr = '(args: ' +
michael@0 197 Array.map(arguments, function(x) { return x.data + ""; }).join(" ") + ')';
michael@0 198 }
michael@0 199 else {
michael@0 200 argstr = '(no arguments)';
michael@0 201 }
michael@0 202 do_throw('got unexpected: ' + name + ' ' + argstr);
michael@0 203 };
michael@0 204 }
michael@0 205
michael@0 206 function makeExpectData(name, expectedData, fromEvent, callback) {
michael@0 207 let dataBuffer = fromEvent ? null : [], done = false;
michael@0 208 let dataBufferView = null;
michael@0 209 return function(receivedData) {
michael@0 210 if (receivedData.data) {
michael@0 211 receivedData = receivedData.data;
michael@0 212 }
michael@0 213 let recvLength = receivedData.byteLength !== undefined ?
michael@0 214 receivedData.byteLength : receivedData.length;
michael@0 215
michael@0 216 if (fromEvent) {
michael@0 217 if (dataBuffer) {
michael@0 218 let newBuffer = new ArrayBuffer(dataBuffer.byteLength + recvLength);
michael@0 219 let newBufferView = new Uint8Array(newBuffer);
michael@0 220 newBufferView.set(dataBufferView, 0);
michael@0 221 newBufferView.set(receivedData, dataBuffer.byteLength);
michael@0 222 dataBuffer = newBuffer;
michael@0 223 dataBufferView = newBufferView;
michael@0 224 }
michael@0 225 else {
michael@0 226 dataBuffer = receivedData;
michael@0 227 dataBufferView = new Uint8Array(dataBuffer);
michael@0 228 }
michael@0 229 }
michael@0 230 else {
michael@0 231 dataBuffer = dataBuffer.concat(receivedData);
michael@0 232 }
michael@0 233 do_print(name + ' received ' + recvLength + ' bytes');
michael@0 234
michael@0 235 if (done)
michael@0 236 do_throw(name + ' Received data event when already done!');
michael@0 237
michael@0 238 let dataView = dataBuffer.byteLength !== undefined ? new Uint8Array(dataBuffer) : dataBuffer;
michael@0 239 if (dataView.length >= expectedData.length) {
michael@0 240 // check the bytes are equivalent
michael@0 241 for (let i = 0; i < expectedData.length; i++) {
michael@0 242 if (dataView[i] !== expectedData[i]) {
michael@0 243 do_throw(name + ' Received mismatched character at position ' + i);
michael@0 244 }
michael@0 245 }
michael@0 246 if (dataView.length > expectedData.length)
michael@0 247 do_throw(name + ' Received ' + dataView.length + ' bytes but only expected ' +
michael@0 248 expectedData.length + ' bytes.');
michael@0 249
michael@0 250 done = true;
michael@0 251 if (callback) {
michael@0 252 callback();
michael@0 253 } else {
michael@0 254 run_next_test();
michael@0 255 }
michael@0 256 }
michael@0 257 };
michael@0 258 }
michael@0 259
michael@0 260 var server = null, sock = null, failure_drain = null;
michael@0 261
michael@0 262 /**
michael@0 263 *
michael@0 264 * Test functions
michael@0 265 *
michael@0 266 */
michael@0 267
michael@0 268 /**
michael@0 269 * Connect the socket to the server. This test is added as the first
michael@0 270 * test, and is also added after every test which results in the socket
michael@0 271 * being closed.
michael@0 272 */
michael@0 273
michael@0 274 function connectSock() {
michael@0 275 server.reset();
michael@0 276 var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
michael@0 277
michael@0 278 sock = TCPSocket.open(
michael@0 279 '127.0.0.1', server.listener.port,
michael@0 280 { binaryType: 'arraybuffer' });
michael@0 281
michael@0 282 sock.onopen = yayFuncs.clientopen;
michael@0 283 sock.ondrain = null;
michael@0 284 sock.ondata = makeFailureCase('data');
michael@0 285 sock.onerror = makeFailureCase('error');
michael@0 286 sock.onclose = makeFailureCase('close');
michael@0 287
michael@0 288 server.onconnect = yayFuncs.serveropen;
michael@0 289 server.ondata = makeFailureCase('serverdata');
michael@0 290 server.onclose = makeFailureCase('serverclose');
michael@0 291 }
michael@0 292
michael@0 293 /**
michael@0 294 * Test that sending a small amount of data works, and that buffering
michael@0 295 * does not take place for this small amount of data.
michael@0 296 */
michael@0 297
michael@0 298 function sendData() {
michael@0 299 server.ondata = makeExpectData('serverdata', DATA_ARRAY);
michael@0 300 if (!sock.send(DATA_ARRAY_BUFFER)) {
michael@0 301 do_throw("send should not have buffered such a small amount of data");
michael@0 302 }
michael@0 303 }
michael@0 304
michael@0 305 /**
michael@0 306 * Test that sending a large amount of data works, that buffering
michael@0 307 * takes place (send returns true), and that ondrain is called once
michael@0 308 * the data has been sent.
michael@0 309 */
michael@0 310
michael@0 311 function sendBig() {
michael@0 312 var yays = makeJointSuccess(['serverdata', 'clientdrain']),
michael@0 313 amount = 0;
michael@0 314
michael@0 315 server.ondata = function (data) {
michael@0 316 amount += data.length;
michael@0 317 if (amount === BIG_TYPED_ARRAY.length) {
michael@0 318 yays.serverdata();
michael@0 319 }
michael@0 320 };
michael@0 321 sock.ondrain = function(evt) {
michael@0 322 if (sock.bufferedAmount) {
michael@0 323 do_throw("sock.bufferedAmount was > 0 in ondrain");
michael@0 324 }
michael@0 325 yays.clientdrain(evt);
michael@0 326 }
michael@0 327 if (sock.send(BIG_ARRAY_BUFFER)) {
michael@0 328 do_throw("expected sock.send to return false on large buffer send");
michael@0 329 }
michael@0 330 }
michael@0 331
michael@0 332 /**
michael@0 333 * Test that data sent from the server correctly fires the ondata
michael@0 334 * callback on the client side.
michael@0 335 */
michael@0 336
michael@0 337 function receiveData() {
michael@0 338 server.ondata = makeFailureCase('serverdata');
michael@0 339 sock.ondata = makeExpectData('data', DATA_ARRAY, true);
michael@0 340
michael@0 341 server.binaryOutput.writeByteArray(DATA_ARRAY, DATA_ARRAY.length);
michael@0 342 }
michael@0 343
michael@0 344 /**
michael@0 345 * Test that when the server closes the connection, the onclose callback
michael@0 346 * is fired on the client side.
michael@0 347 */
michael@0 348
michael@0 349 function serverCloses() {
michael@0 350 // we don't really care about the server's close event, but we do want to
michael@0 351 // make sure it happened for sequencing purposes.
michael@0 352 var yayFuncs = makeJointSuccess(['clientclose', 'serverclose']);
michael@0 353 sock.ondata = makeFailureCase('data');
michael@0 354 sock.onclose = yayFuncs.clientclose;
michael@0 355 server.onclose = yayFuncs.serverclose;
michael@0 356
michael@0 357 server.close();
michael@0 358 }
michael@0 359
michael@0 360 /**
michael@0 361 * Test that when the client closes the connection, the onclose callback
michael@0 362 * is fired on the server side.
michael@0 363 */
michael@0 364
michael@0 365 function clientCloses() {
michael@0 366 // we want to make sure the server heard the close and also that the client's
michael@0 367 // onclose event fired for consistency.
michael@0 368 var yayFuncs = makeJointSuccess(['clientclose', 'serverclose']);
michael@0 369 server.onclose = yayFuncs.serverclose;
michael@0 370 sock.onclose = yayFuncs.clientclose;
michael@0 371
michael@0 372 sock.close();
michael@0 373 }
michael@0 374
michael@0 375 /**
michael@0 376 * Send a large amount of data and immediately call close
michael@0 377 */
michael@0 378
michael@0 379 function bufferedClose() {
michael@0 380 var yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
michael@0 381 server.ondata = makeExpectData(
michael@0 382 "ondata", BIG_TYPED_ARRAY, false, yays.serverdata);
michael@0 383 server.onclose = yays.serverclose;
michael@0 384 sock.onclose = yays.clientclose;
michael@0 385 sock.send(BIG_ARRAY_BUFFER);
michael@0 386 sock.close();
michael@0 387 }
michael@0 388
michael@0 389 /**
michael@0 390 * Connect to a port we know is not listening so an error is assured,
michael@0 391 * and make sure that onerror and onclose are fired on the client side.
michael@0 392 */
michael@0 393
michael@0 394 function badConnect() {
michael@0 395 // There's probably nothing listening on tcp port 2.
michael@0 396 sock = TCPSocket.open('127.0.0.1', 2);
michael@0 397
michael@0 398 sock.onopen = makeFailureCase('open');
michael@0 399 sock.ondata = makeFailureCase('data');
michael@0 400
michael@0 401 let success = makeSuccessCase('error');
michael@0 402 let gotError = false;
michael@0 403 sock.onerror = function(event) {
michael@0 404 do_check_eq(event.data.name, 'ConnectionRefusedError');
michael@0 405 gotError = true;
michael@0 406 };
michael@0 407 sock.onclose = function() {
michael@0 408 if (!gotError)
michael@0 409 do_throw('got close without error!');
michael@0 410 else
michael@0 411 success();
michael@0 412 };
michael@0 413 }
michael@0 414
michael@0 415 /**
michael@0 416 * Test that calling send with enough data to buffer causes ondrain to
michael@0 417 * be invoked once the data has been sent, and then test that calling send
michael@0 418 * and buffering again causes ondrain to be fired again.
michael@0 419 */
michael@0 420
michael@0 421 function drainTwice() {
michael@0 422 let yays = makeJointSuccess(
michael@0 423 ['ondrain', 'ondrain2',
michael@0 424 'ondata', 'ondata2',
michael@0 425 'serverclose', 'clientclose']);
michael@0 426 let ondrainCalled = false,
michael@0 427 ondataCalled = false;
michael@0 428
michael@0 429 function maybeSendNextData() {
michael@0 430 if (!ondrainCalled || !ondataCalled) {
michael@0 431 // make sure server got data and client got ondrain.
michael@0 432 return;
michael@0 433 }
michael@0 434
michael@0 435 server.ondata = makeExpectData(
michael@0 436 "ondata2", BIG_TYPED_ARRAY_2, false, yays.ondata2);
michael@0 437
michael@0 438 sock.ondrain = yays.ondrain2;
michael@0 439
michael@0 440 if (sock.send(BIG_ARRAY_BUFFER_2)) {
michael@0 441 do_throw("sock.send(BIG_TYPED_ARRAY_2) did not return false to indicate buffering");
michael@0 442 }
michael@0 443
michael@0 444 sock.close();
michael@0 445 }
michael@0 446
michael@0 447 function clientOndrain() {
michael@0 448 yays.ondrain();
michael@0 449 ondrainCalled = true;
michael@0 450 maybeSendNextData();
michael@0 451 }
michael@0 452
michael@0 453 function serverSideCallback() {
michael@0 454 yays.ondata();
michael@0 455 ondataCalled = true;
michael@0 456 maybeSendNextData();
michael@0 457 }
michael@0 458
michael@0 459 server.onclose = yays.serverclose;
michael@0 460 server.ondata = makeExpectData(
michael@0 461 "ondata", BIG_TYPED_ARRAY, false, serverSideCallback);
michael@0 462
michael@0 463 sock.onclose = yays.clientclose;
michael@0 464 sock.ondrain = clientOndrain;
michael@0 465
michael@0 466 if (sock.send(BIG_ARRAY_BUFFER)) {
michael@0 467 throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
michael@0 468 }
michael@0 469 }
michael@0 470
michael@0 471 function cleanup() {
michael@0 472 do_print("Cleaning up");
michael@0 473 sock.close();
michael@0 474 if (!gInChild)
michael@0 475 Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
michael@0 476 run_next_test();
michael@0 477 }
michael@0 478
michael@0 479 /**
michael@0 480 * Test that calling send with enough data to buffer twice in a row without
michael@0 481 * waiting for ondrain still results in ondrain being invoked at least once.
michael@0 482 */
michael@0 483
michael@0 484 function bufferTwice() {
michael@0 485 let yays = makeJointSuccess(
michael@0 486 ['ondata', 'ondrain', 'serverclose', 'clientclose']);
michael@0 487
michael@0 488 let double_array = new Uint8Array(BIG_ARRAY.concat(BIG_ARRAY_2));
michael@0 489 server.ondata = makeExpectData(
michael@0 490 "ondata", double_array, false, yays.ondata);
michael@0 491
michael@0 492 server.onclose = yays.serverclose;
michael@0 493 sock.onclose = yays.clientclose;
michael@0 494
michael@0 495 sock.ondrain = function () {
michael@0 496 sock.close();
michael@0 497 yays.ondrain();
michael@0 498 }
michael@0 499
michael@0 500 if (sock.send(BIG_ARRAY_BUFFER)) {
michael@0 501 throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
michael@0 502 }
michael@0 503 if (sock.send(BIG_ARRAY_BUFFER_2)) {
michael@0 504 throw new Error("sock.send(BIG_TYPED_ARRAY_2) did not return false to indicate buffering on second synchronous call to send");
michael@0 505 }
michael@0 506 }
michael@0 507
michael@0 508 // Test child behavior when child thinks it's buffering but parent doesn't
michael@0 509 // buffer.
michael@0 510 // 1. set bufferedAmount of content socket to a value that will make next
michael@0 511 // send() call return false.
michael@0 512 // 2. send a small data to make send() return false, but it won't make
michael@0 513 // parent buffer.
michael@0 514 // 3. we should get a ondrain.
michael@0 515 function childbuffered() {
michael@0 516 let yays = makeJointSuccess(['ondrain', 'serverdata',
michael@0 517 'clientclose', 'serverclose']);
michael@0 518 sock.ondrain = function() {
michael@0 519 yays.ondrain();
michael@0 520 sock.close();
michael@0 521 };
michael@0 522
michael@0 523 server.ondata = makeExpectData(
michael@0 524 'ondata', DATA_ARRAY, false, yays.serverdata);
michael@0 525
michael@0 526 let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
michael@0 527 internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
michael@0 528 0);
michael@0 529 if (sock.send(DATA_ARRAY_BUFFER)) {
michael@0 530 do_throw("expected sock.send to return false.");
michael@0 531 }
michael@0 532
michael@0 533 sock.onclose = yays.clientclose;
michael@0 534 server.onclose = yays.serverclose;
michael@0 535 }
michael@0 536
michael@0 537 // Test child's behavior when send() of child return true but parent buffers
michael@0 538 // data.
michael@0 539 // 1. send BIG_ARRAY to make parent buffer. This would make child wait for
michael@0 540 // drain as well.
michael@0 541 // 2. set child's bufferedAmount to zero, so child will no longer wait for
michael@0 542 // drain but parent will dispatch a drain event.
michael@0 543 // 3. wait for 1 second, to make sure there's no ondrain event dispatched in
michael@0 544 // child.
michael@0 545 function childnotbuffered() {
michael@0 546 let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
michael@0 547 server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
michael@0 548 if (sock.send(BIG_ARRAY_BUFFER)) {
michael@0 549 do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
michael@0 550 }
michael@0 551 let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
michael@0 552 internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
michael@0 553 1);
michael@0 554
michael@0 555 // shouldn't get ondrain, even after parent have cleared its buffer.
michael@0 556 sock.ondrain = makeFailureCase('drain');
michael@0 557 sock.onclose = yays.clientclose;
michael@0 558 server.onclose = yays.serverclose;
michael@0 559 do_timeout(1000, function() {
michael@0 560 sock.close();
michael@0 561 });
michael@0 562 };
michael@0 563
michael@0 564 // - connect, data and events work both ways
michael@0 565 add_test(connectSock);
michael@0 566 add_test(sendData);
michael@0 567 add_test(sendBig);
michael@0 568 add_test(receiveData);
michael@0 569 // - server closes on us
michael@0 570 add_test(serverCloses);
michael@0 571
michael@0 572 // - connect, we close on the server
michael@0 573 add_test(connectSock);
michael@0 574 add_test(clientCloses);
michael@0 575
michael@0 576 // - connect, buffer, close
michael@0 577 add_test(connectSock);
michael@0 578 add_test(bufferedClose);
michael@0 579
michael@0 580 if (get_platform() !== "Darwin") {
michael@0 581 // This test intermittently fails way too often on OS X, for unknown reasons.
michael@0 582 // Please, diagnose and fix it if you can.
michael@0 583 // - get an error on an attempt to connect to a non-listening port
michael@0 584 add_test(badConnect);
michael@0 585 }
michael@0 586
michael@0 587 // send a buffer, get a drain, send a buffer, get a drain
michael@0 588 add_test(connectSock);
michael@0 589 add_test(drainTwice);
michael@0 590
michael@0 591 // send a buffer, get a drain, send a buffer, get a drain
michael@0 592 add_test(connectSock);
michael@0 593 add_test(bufferTwice);
michael@0 594
michael@0 595 if (is_content()) {
michael@0 596 add_test(connectSock);
michael@0 597 add_test(childnotbuffered);
michael@0 598
michael@0 599 add_test(connectSock);
michael@0 600 add_test(childbuffered);
michael@0 601 }
michael@0 602
michael@0 603 // clean up
michael@0 604 add_test(cleanup);
michael@0 605
michael@0 606 function run_test() {
michael@0 607 if (!gInChild)
michael@0 608 Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
michael@0 609
michael@0 610 server = new TestServer();
michael@0 611
michael@0 612 run_next_test();
michael@0 613 }

mercurial