Bug 1264110 - fix timing issue in test cases. r=kershaw.
authorShih-Chiang Chien <schien@mozilla.com>
Mon, 05 Sep 2016 18:18:11 +0800
changeset 354396 817e76d33b76a53521f0263819a45376092b4718
parent 354395 92f041a22d0a2f11d95453b0934fee8d3e9b6529
child 354397 8fcadb9544bb005b69a2c50d45fd85500d138332
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskershaw
bugs1264110
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1264110 - fix timing issue in test cases. r=kershaw. MozReview-Commit-ID: 2Ia4L7EizrA
dom/presentation/PresentationService.cpp
dom/presentation/PresentationSessionInfo.cpp
dom/presentation/PresentationSessionInfo.h
dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -458,17 +458,17 @@ PresentationService::HandleSessionReques
   // Call |NotifyResponderReady| to indicate the receiver page is already there.
   if (info) {
     PRES_DEBUG("handle reconnection:id[%s]\n",
                NS_ConvertUTF16toUTF8(sessionId).get());
 
     info->SetControlChannel(ctrlChannel);
     info->SetDevice(device);
     return static_cast<PresentationPresentingInfo*>(
-      info.get())->NotifyResponderReady();
+      info.get())->DoReconnect();
   }
 
   // This is the case for a new session.
   PRES_DEBUG("handle new session:url[%d], id[%s]\n",
              NS_ConvertUTF16toUTF8(url).get(),
              NS_ConvertUTF16toUTF8(sessionId).get());
 
   info = new PresentationPresentingInfo(url, sessionId, device);
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -400,21 +400,26 @@ PresentationSessionInfo::ContinueTermina
     Shutdown(NS_OK);
   }
 }
 
 // nsIPresentationSessionTransportCallback
 NS_IMETHODIMP
 PresentationSessionInfo::NotifyTransportReady()
 {
-  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
-             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
+  PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
+             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
 
   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
@@ -479,21 +484,25 @@ PresentationSessionInfo::NotifyData(cons
 
   return mListener->NotifyMessage(mSessionId, aData);
 }
 
 // nsIPresentationSessionTransportBuilderListener
 NS_IMETHODIMP
 PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
 {
-  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
-             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
+  PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
+             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
 
   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);
@@ -1190,16 +1199,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) {
@@ -1303,18 +1313,18 @@ PresentationPresentingInfo::IsAccessible
   return (mContentParent) ?
           aProcessId == static_cast<ContentParent*>(mContentParent.get())->OtherPid() :
           false;
 }
 
 nsresult
 PresentationPresentingInfo::NotifyResponderReady()
 {
-  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
-             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
+  PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
+             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
 
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
 
   mIsResponderReady = true;
 
@@ -1339,16 +1349,29 @@ PresentationPresentingInfo::NotifyRespon
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
 
   return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
 }
 
+nsresult
+PresentationPresentingInfo::DoReconnect()
+{
+  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
+             NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
+
+  MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
+
+  SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTING, NS_OK);
+
+  return NotifyResponderReady();
+}
+
 // nsIPresentationControlChannelListener
 NS_IMETHODIMP
 PresentationPresentingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
 {
   if (NS_WARN_IF(mHasFlushPendingEvents)) {
     return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
   }
 
--- a/dom/presentation/PresentationSessionInfo.h
+++ b/dom/presentation/PresentationSessionInfo.h
@@ -249,16 +249,18 @@ public:
   void SetPromise(Promise* aPromise)
   {
     mPromise = aPromise;
     mPromise->AppendNativeHandler(this);
   }
 
   bool IsAccessible(base::ProcessId aProcessId) override;
 
+  nsresult DoReconnect();
+
 private:
   ~PresentationPresentingInfo()
   {
     Shutdown(NS_OK);
   }
 
   void Shutdown(nsresult aReason) override;
 
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -235,46 +235,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
@@ -37,328 +37,447 @@ function setup() {
         teardown();
         aReject();
       }
     );
   });
 }
 
 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', SpecialPowers.Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR);
-    });
-
+  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, "NotAllowedError", "NotAllowedError is expected when the prompt is canceled.");
-        aResolve();
       }
-    );
-  });
+    ),
+  ]);
 }
 
 function testStartConnectionNoDevice() {
-  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', SpecialPowers.Cr.NS_ERROR_DOM_NOT_FOUND_ERR);
-    });
-
+  info('--- testStartConnectionNoDevice ---');
+  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_FOUND_ERR);
+        resolve();
+      });
+    }),
     request.start().then(
       function(aConnection) {
         ok(false, "|start| shouldn't succeed in this case.");
-        aReject();
       },
       function(aError) {
         is(aError.name, "NotFoundError", "NotFoundError is expected when no available device.");
-        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.onclose = function() {
-          aConnection.onclose = null;
-          is(aConnection.state, "closed", "Connection should be closed.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onclose = function() {
+            aConnection.onclose = null;
+            is(aConnection.state, "closed", "Connection should be closed.");
+            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.onclose = function() {
-          aConnection.onclose = null;
-          is(aConnection.state, "closed", "Connection should be closed.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onclose = function() {
+            aConnection.onclose = null;
+            is(aConnection.state, "closed", "Connection should be closed.");
+            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.onclose = function() {
-          aConnection.onclose = null;
-          is(aConnection.state, "closed", "Connection should be closed.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onclose = function() {
+            aConnection.onclose = null;
+            is(aConnection.state, "closed", "Connection should be closed.");
+            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.onclose = function() {
-          aConnection.onclose = null;
-          is(aConnection.state, "closed", "Connection should be closed.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onclose = function() {
+            aConnection.onclose = null;
+            is(aConnection.state, "closed", "Connection should be closed.");
+            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.onclose = function() {
-          aConnection.onclose = null;
-          is(aConnection.state, "closed", "Connection should be closed.");
-          aResolve();
-        };
+        return new Promise((resolve) => {
+          aConnection.onclose = function() {
+            aConnection.onclose = null;
+            is(aConnection.state, "closed", "Connection should be closed.");
+            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();
   });