Bug 1264110 - Fix timing issue in test cases. r=kershaw, a=ritu
authorShih-Chiang Chien <schien@mozilla.com>
Mon, 05 Sep 2016 18:18:11 +0800
changeset 348136 207dc5d0e976f71dd24729dead303399984a8887
parent 348135 5755a15244c83e1bb3bff68835e941e73fed0110
child 348137 630e64bbd358a3035ce788368a618871e6469990
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskershaw, ritu
bugs1264110
milestone50.0a2
Bug 1264110 - Fix timing issue in test cases. r=kershaw, a=ritu MozReview-Commit-ID: 2Ia4L7EizrA
dom/presentation/PresentationSessionInfo.cpp
dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -393,16 +393,21 @@ PresentationSessionInfo::ContinueTermina
 }
 
 // nsIPresentationSessionTransportCallback
 NS_IMETHODIMP
 PresentationSessionInfo::NotifyTransportReady()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mState != nsIPresentationSessionListener::STATE_CONNECTING &&
+      mState != nsIPresentationSessionListener::STATE_CONNECTED) {
+    return NS_OK;
+  }
+
   mIsTransportReady = true;
 
   // Established RTCDataChannel implies responder is ready.
   if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
     mIsResponderReady = true;
   }
 
   // At sender side, session might not be ready at this point (waiting for
@@ -465,16 +470,20 @@ PresentationSessionInfo::NotifyData(cons
 }
 
 // nsIPresentationSessionTransportBuilderListener
 NS_IMETHODIMP
 PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
 {
   SetBuilder(nullptr);
 
+  if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
+    return NS_ERROR_FAILURE;
+  }
+
   // The session transport is managed by content process
   if (!transport) {
     return NS_OK;
   }
 
   mTransport = transport;
 
   nsresult rv = mTransport->SetCallback(this);
@@ -1019,16 +1028,17 @@ PresentationPresentingInfo::FlushPending
   mPendingCandidates.Clear();
   return NS_OK;
 }
 
 nsresult
 PresentationPresentingInfo::InitTransportAndSendAnswer()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CONNECTING);
 
   uint8_t type = 0;
   nsresult rv = mRequesterDescription->GetType(&type);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (type == nsIPresentationChannelDescription::TYPE_TCP) {
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -223,46 +223,45 @@ const mockedSessionTransport = {
   },
   get callback() {
     return this._callback;
   },
   get selfAddress() {
     return this._selfAddress;
   },
   buildTCPSenderTransport: function(transport, listener) {
-    sendAsyncMessage('data-transport-initialized');
     this._listener = listener;
     this._role = Ci.nsIPresentationService.ROLE_CONTROLLER;
+    this._listener.onSessionTransport(this);
+    this._listener = null;
+    sendAsyncMessage('data-transport-initialized');
 
     setTimeout(()=>{
-      this._listener.onSessionTransport(this);
-      this._listener = null;
       this.simulateTransportReady();
     }, 0);
   },
   buildTCPReceiverTransport: function(description, listener) {
     this._listener = listener;
-    this._role = Ci.nsIPresentationService.ROLE_CONTROLLER;
+    this._role = Ci.nsIPresentationService.ROLE_RECEIVER;
 
     var addresses = description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpAddress;
     this._selfAddress = {
       QueryInterface: XPCOMUtils.generateQI([Ci.nsINetAddr]),
       address: (addresses.length > 0) ?
                 addresses.queryElementAt(0, Ci.nsISupportsCString).data : "",
       port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
     };
 
     setTimeout(()=>{
       this._listener.onSessionTransport(this);
       this._listener = null;
     }, 0);
   },
   // in-process case
   buildDataChannelTransport: function(role, window, listener) {
-    dump("PresentationSessionChromeScript: build data channel transport\n");
     this._listener = listener;
     this._role = role;
 
     var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
     sendAsyncMessage('check-navigator', hasNavigator);
 
     setTimeout(()=>{
       this._listener.onSessionTransport(this);
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
@@ -47,307 +47,425 @@ function testCreateRequestWithEmptyURL()
     } catch (aError) {
       is(aError.name, "SyntaxError", "SyntaxError is expected when using an empty URL.");
       aResolve();
     }
   });
 }
 
 function testStartConnectionCancelPrompt() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-cancel');
-    });
-
+  info('--- testStartConnectionCancelPrompt ---');
+  return Promise.all([
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-cancel', SpecialPowers.Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR);
+        resolve();
+      });
+    }),
     request.start().then(
       function(aConnection) {
         ok(false, "|start| shouldn't succeed in this case.");
-        aReject();
       },
       function(aError) {
         is(aError.name, "AbortError", "AbortError is expected when the prompt is canceled.");
-        aResolve();
       }
-    );
-  });
+    ),
+  ]);
 }
 
 function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-select');
-    });
+  info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit ---');
+  return Promise.all([
 
-    gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
-      gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
-      info("A control channel is established.");
-      gScript.sendAsyncMessage('trigger-control-channel-open');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-select');
+        resolve();
+      });
+    }),
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+        gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
+        info("A control channel is established.");
+        gScript.sendAsyncMessage('trigger-control-channel-open');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
-      info("The control channel is opened.");
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
+        gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
+        info("The control channel is opened.");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
-      info("The control channel is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
+        gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
+        info("The control channel is closed. " + aReason);
+        is(aReason, SpecialPowers.Cr.NS_ERROR_FAILURE, "The control channel is closed with NS_ERROR_FAILURE");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
-      gScript.removeMessageListener('offer-sent', offerSentHandler);
-      ok(aIsValid, "A valid offer is sent out.");
-      gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
+        gScript.removeMessageListener('offer-sent', offerSentHandler);
+        ok(aIsValid, "A valid offer is sent out.");
+        gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
+        resolve();
+      });
+    }),
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onterminate = function() {
-          aConnection.onterminate = null;
-          is(aConnection.state, "terminated", "Connection should be terminated.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onterminate = function() {
+            aConnection.onterminate = null;
+            is(aConnection.state, "terminated", "Connection should be terminated.");
+            resolve();
+          };
+        });
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
-        aReject();
       }
-    );
-  });
+    ),
+
+  ]);
 }
 
 function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-select');
-    });
+  info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit ---');
+  return Promise.all([
 
-    gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
-      gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
-      info("A control channel is established.");
-      gScript.sendAsyncMessage('trigger-control-channel-open');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-select');
+        resolve();
+      });
+    }),
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+        gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
+        info("A control channel is established.");
+        gScript.sendAsyncMessage('trigger-control-channel-open');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
-      info("The control channel is opened.");
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
+        gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
+        info("The control channel is opened.");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
-      info("The control channel is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
+        gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
+        info("The control channel is closed. " + aReason);
+        is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
-      gScript.removeMessageListener('offer-sent', offerSentHandler);
-      ok(aIsValid, "A valid offer is sent out.");
-      gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
+        gScript.removeMessageListener('offer-sent', offerSentHandler);
+        ok(aIsValid, "A valid offer is sent out.");
+        gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
+        resolve();
+      });
+    }),
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onterminate = function() {
-          aConnection.onterminate = null;
-          is(aConnection.state, "terminated", "Connection should be terminated.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onterminate = function() {
+            aConnection.onterminate = null;
+            is(aConnection.state, "terminated", "Connection should be terminated.");
+            resolve();
+          };
+        });
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
-        aReject();
       }
-    );
-  });
+    ),
+
+  ]);
 }
 
 function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-select');
-    });
+  info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady ---');
+  return Promise.all([
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-select');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
-      gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
-      info("A control channel is established.");
-      gScript.sendAsyncMessage('trigger-control-channel-open');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+        gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
+        info("A control channel is established.");
+        gScript.sendAsyncMessage('trigger-control-channel-open');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
-      info("The control channel is opened.");
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
+        gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
+        info("The control channel is opened.");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
-      info("The control channel is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
+        gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
+        is(aReason, SpecialPowers.Cr.NS_ERROR_ABORT, "The control channel is closed with NS_ERROR_ABORT");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
-      gScript.removeMessageListener('offer-sent', offerSentHandler);
-      ok(aIsValid, "A valid offer is sent out.");
-      gScript.sendAsyncMessage('trigger-incoming-transport');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
+        gScript.removeMessageListener('offer-sent', offerSentHandler);
+        ok(aIsValid, "A valid offer is sent out.");
+        gScript.sendAsyncMessage('trigger-incoming-transport');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
-      gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
-      info("Data transport channel is initialized.");
-      gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_ABORT);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
+        gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
+        info("Data transport channel is initialized.");
+        gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_ABORT);
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
-      gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
-      info("The data transport is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
+        gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
+        info("The data transport is closed. " + aReason);
+        resolve();
+      });
+    }),
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onterminate = function() {
-          aConnection.onterminate = null;
-          is(aConnection.state, "terminated", "Connection should be terminated.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onterminate = function() {
+            aConnection.onterminate = null;
+            is(aConnection.state, "terminated", "Connection should be terminated.");
+            resolve();
+          };
+        });
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
-        aReject();
       }
-    );
-  });
+    ),
+
+  ]);
 }
 
 function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-select');
-    });
+  info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady -- ');
+  return Promise.all([
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-select');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
-      gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
-      info("A control channel is established.");
-      gScript.sendAsyncMessage('trigger-control-channel-open');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+        gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
+        info("A control channel is established.");
+        gScript.sendAsyncMessage('trigger-control-channel-open');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
-      info("The control channel is opened.");
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
+        gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
+        info("The control channel is opened.");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
-      info("The control channel is closed. " + aReason);
-    });
-
-    gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
-      gScript.removeMessageListener('offer-sent', offerSentHandler);
-      ok(aIsValid, "A valid offer is sent out.");
-      gScript.sendAsyncMessage('trigger-incoming-transport');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
+        gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
+        info("The control channel is closed. " + aReason);
+        is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
-      gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
-      info("Data transport channel is initialized.");
-      gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
+        gScript.removeMessageListener('offer-sent', offerSentHandler);
+        ok(aIsValid, "A valid offer is sent out.");
+        gScript.sendAsyncMessage('trigger-incoming-transport');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
-      gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
-      info("The data transport is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
+        gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
+        info("Data transport channel is initialized.");
+        gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
+        resolve();
+      });
+    }),
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
+        gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
+        info("The data transport is closed. " + aReason);
+        resolve();
+      });
+    }),
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onterminate = function() {
-          aConnection.onterminate = null;
-          is(aConnection.state, "terminated", "Connection should be terminated.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onterminate = function() {
+            aConnection.onterminate = null;
+            is(aConnection.state, "terminated", "Connection should be terminated.");
+            resolve();
+          };
+        });
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
-        aReject();
       }
-    );
-  });
+    ),
+
+  ]);
 }
 
 function testStartConnectionUnexpectedDataTransportClose() {
-  return new Promise(function(aResolve, aReject) {
-    gScript.addMessageListener('device-prompt', function devicePromptHandler() {
-      gScript.removeMessageListener('device-prompt', devicePromptHandler);
-      info("Device prompt is triggered.");
-      gScript.sendAsyncMessage('trigger-device-prompt-select');
-    });
+  info('--- testStartConnectionUnexpectedDataTransportClose ---');
+  return Promise.all([
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('device-prompt', function devicePromptHandler() {
+        gScript.removeMessageListener('device-prompt', devicePromptHandler);
+        info("Device prompt is triggered.");
+        gScript.sendAsyncMessage('trigger-device-prompt-select');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
-      gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
-      info("A control channel is established.");
-      gScript.sendAsyncMessage('trigger-control-channel-open');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
+        gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
+        info("A control channel is established.");
+        gScript.sendAsyncMessage('trigger-control-channel-open');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
-      info("The control channel is opened.");
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
+        gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
+        info("The control channel is opened.");
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
-      gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
-      info("The control channel is closed. " + aReason);
-    });
-
-    gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
-      gScript.removeMessageListener('offer-sent', offerSentHandler);
-      ok(aIsValid, "A valid offer is sent out.");
-      gScript.sendAsyncMessage('trigger-incoming-transport');
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
+        gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
+        info("The control channel is closed. " + aReason);
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
-      gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
-      info("Data transport channel is initialized.");
-      gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_UNEXPECTED);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
+        gScript.removeMessageListener('offer-sent', offerSentHandler);
+        ok(aIsValid, "A valid offer is sent out.");
+        info("recv offer-sent.");
+        gScript.sendAsyncMessage('trigger-incoming-transport');
+        resolve();
+      });
+    }),
 
-    gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
-      gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
-      info("The data transport is closed. " + aReason);
-    });
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
+        gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
+        info("Data transport channel is initialized.");
+        gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_UNEXPECTED);
+        resolve();
+      });
+    }),
+
+    new Promise((resolve) => {
+      gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
+        gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
+        info("The data transport is closed. " + aReason);
+        resolve();
+      });
+    }),
 
     request.start().then(
       function(aConnection) {
         is(aConnection.state, "connecting", "The initial state should be connecting.");
-        aConnection.onterminate = function() {
-          aConnection.onterminate = null;
-          is(aConnection.state, "terminated", "Connection should be terminated.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onterminate = function() {
+            aConnection.onterminate = null;
+            is(aConnection.state, "terminated", "Connection should be terminated.");
+            resolve();
+          };
+        });
       },
       function(aError) {
         ok(false, "Error occurred when establishing a connection: " + aError);
         teardown();
-        aReject();
       }
-    );
-  });
+    ),
+
+  ]);
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
     SimpleTest.finish();
   });