Bug 995380 - Signaling unittests should use the real main thread. r=jesup
authorEthan Hugg <ethanhugg@gmail.com>
Mon, 21 Apr 2014 19:37:22 -0700
changeset 199047 e7160b5750b537ef7147d854e583d60c1992dc07
parent 199046 b9b4ff616b32af49791c397ed2585c18fba294be
child 199048 e351fbac578934abf83918d3d634b5cb082d5d40
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs995380
milestone31.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 995380 - Signaling unittests should use the real main thread. r=jesup
media/webrtc/signaling/test/signaling_unittests.cpp
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -43,17 +43,19 @@
 #include "logging.h"
 #include "stunserver.h"
 #include "stunserver.cpp"
 #include "PeerConnectionImplEnumsBinding.cpp"
 
 #include "mtransport_test_utils.h"
 #include "gtest_ringbuffer_dumper.h"
 MtransportTestUtils *test_utils;
-nsCOMPtr<nsIThread> gThread;
+nsCOMPtr<nsIThread> gMainThread;
+nsCOMPtr<nsIThread> gGtestThread;
+bool gTestsComplete = false;
 
 #ifndef USE_FAKE_MEDIA_STREAMS
 #error USE_FAKE_MEDIA_STREAMS undefined
 #endif
 #ifndef USE_FAKE_PCOBSERVER
 #error USE_FAKE_PCOBSERVER undefined
 #endif
 
@@ -208,29 +210,16 @@ enum mediaPipelineFlags
   PIPELINE_LOCAL = (1<<0),
   PIPELINE_RTCP_MUX = (1<<1),
   PIPELINE_SEND = (1<<2),
   PIPELINE_VIDEO = (1<<3),
   PIPELINE_RTCP_NACK = (1<<4)
 };
 
 
-static bool SetupGlobalThread() {
-  if (!gThread) {
-    nsIThread *thread;
-
-    nsresult rv = NS_NewNamedThread("pseudo-main",&thread);
-    if (NS_FAILED(rv))
-      return false;
-
-    gThread = thread;
-  }
-  return true;
-}
-
 class TestObserver : public AFakePCObserver
 {
 public:
   TestObserver(sipcc::PeerConnectionImpl *peerConnection,
                const std::string &aName) :
     AFakePCObserver(peerConnection, aName) {}
 
   size_t MatchingCandidates(const std::string& cand) {
@@ -698,17 +687,17 @@ class SignalingAgent {
     cfg_.addStunServer(stun_addr, stun_port);
 
     pc = sipcc::PeerConnectionImpl::CreatePeerConnection();
     EXPECT_TRUE(pc);
   }
 
 
   ~SignalingAgent() {
-    mozilla::SyncRunnable::DispatchToThread(gThread,
+    mozilla::SyncRunnable::DispatchToThread(gMainThread,
       WrapRunnable(this, &SignalingAgent::Close));
   }
 
   void Init_m(nsCOMPtr<nsIThread> thread)
   {
     pObserver = new TestObserver(pc, name);
     ASSERT_TRUE(pObserver);
 
@@ -1277,17 +1266,16 @@ class SignalingEnvironment : public ::te
   void TearDown() {
     // Signaling is shut down in XPCOM shutdown
   }
 };
 
 class SignalingAgentTest : public ::testing::Test {
  public:
   static void SetUpTestCase() {
-    ASSERT_TRUE(SetupGlobalThread());
   }
 
   void TearDown() {
     // Delete all the agents.
     for (size_t i=0; i < agents_.size(); i++) {
       delete agents_[i];
     }
   }
@@ -1296,17 +1284,17 @@ class SignalingAgentTest : public ::test
     return CreateAgent(g_stun_server_address, g_stun_server_port);
   }
 
   bool CreateAgent(const std::string stun_addr, uint16_t stun_port,
                    bool wait_for_gather = true) {
     ScopedDeletePtr<SignalingAgent> agent(
         new SignalingAgent("agent", stun_addr, stun_port));
 
-    agent->Init(gThread);
+    agent->Init(gMainThread);
 
     if (wait_for_gather) {
       if (!agent->WaitForGatherAllowFail())
         return false;
     }
 
     agents_.push_back(agent.forget());
 
@@ -1340,42 +1328,40 @@ public:
   SignalingTest(const std::string& stun_addr, uint16_t stun_port)
       : a1_(nullptr),
         a2_(nullptr),
         wait_for_gather_(true),
         stun_addr_(stun_addr),
         stun_port_(stun_port) {}
 
   static void SetUpTestCase() {
-    ASSERT_TRUE(SetupGlobalThread());
   }
 
   void EnsureInit() {
 
     if (init_)
       return;
 
     a1_ = new SignalingAgent(callerName, stun_addr_, stun_port_);
     a2_ = new SignalingAgent(calleeName, stun_addr_, stun_port_);
 
-    a1_->Init(gThread);
-    a2_->Init(gThread);
+    a1_->Init(gMainThread);
+    a2_->Init(gMainThread);
 
     if (wait_for_gather_) {
       WaitForGather();
     }
   }
 
   void WaitForGather() {
     a1_->WaitForGather();
     a2_->WaitForGather();
   }
 
   static void TearDownTestCase() {
-    gThread = nullptr;
   }
 
   void CreateOffer(sipcc::MediaConstraints& constraints,
                    uint32_t offerFlags, uint32_t sdpCheck) {
     EnsureInit();
     a1_->CreateOffer(constraints, offerFlags, sdpCheck);
   }
 
@@ -1631,22 +1617,61 @@ public:
   bool init_;
   ScopedDeletePtr<SignalingAgent> a1_;  // Canonically "caller"
   ScopedDeletePtr<SignalingAgent> a2_;  // Canonically "callee"
   bool wait_for_gather_;
   std::string stun_addr_;
   uint16_t stun_port_;
 };
 
+static void SetIntPrefOnMainThread(nsCOMPtr<nsIPrefBranch> prefs,
+  const char *pref_name,
+  int new_value) {
+  MOZ_ASSERT(NS_IsMainThread());
+  prefs->SetIntPref(pref_name, new_value);
+}
+
+static void SetMaxFsFr(nsCOMPtr<nsIPrefBranch> prefs,
+  int max_fs,
+  int max_fr) {
+  gMainThread->Dispatch(
+    WrapRunnableNM(SetIntPrefOnMainThread,
+      prefs,
+      "media.navigator.video.max_fs",
+      max_fs),
+    NS_DISPATCH_SYNC);
+
+  gMainThread->Dispatch(
+    WrapRunnableNM(SetIntPrefOnMainThread,
+      prefs,
+      "media.navigator.video.max_fr",
+      max_fr),
+    NS_DISPATCH_SYNC);
+}
+
 class FsFrPrefClearer {
   public:
     FsFrPrefClearer(nsCOMPtr<nsIPrefBranch> prefs): mPrefs(prefs) {}
     ~FsFrPrefClearer() {
-      mPrefs->ClearUserPref("media.navigator.video.max_fs");
-      mPrefs->ClearUserPref("media.navigator.video.max_fr");
+      gMainThread->Dispatch(
+        WrapRunnableNM(FsFrPrefClearer::ClearUserPrefOnMainThread,
+          mPrefs,
+          "media.navigator.video.max_fs"),
+        NS_DISPATCH_SYNC);
+      gMainThread->Dispatch(
+        WrapRunnableNM(FsFrPrefClearer::ClearUserPrefOnMainThread,
+          mPrefs,
+          "media.navigator.video.max_fr"),
+        NS_DISPATCH_SYNC);
+    }
+
+    static void ClearUserPrefOnMainThread(nsCOMPtr<nsIPrefBranch> prefs,
+      const char *pref_name) {
+      MOZ_ASSERT(NS_IsMainThread());
+      prefs->ClearUserPref(pref_name);
     }
   private:
     nsCOMPtr<nsIPrefBranch> mPrefs;
 };
 
 TEST_F(SignalingTest, JustInit)
 {
 }
@@ -3453,18 +3478,17 @@ TEST_F(SignalingTest, MaxFsFrInOffer)
   EnsureInit();
 
   sipcc::MediaConstraints constraints;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   ASSERT_TRUE(prefs);
   FsFrPrefClearer prefClearer(prefs);
 
-  prefs->SetIntPref("media.navigator.video.max_fs", 300);
-  prefs->SetIntPref("media.navigator.video.max_fr", 30);
+  SetMaxFsFr(prefs, 300, 30);
 
   a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
 
   // Verify that SDP contains correct max-fs and max-fr
   CheckMaxFsFrSdp(a1_->offer(), 120, 300, 30);
 }
 
 // Test max_fs and max_fr prefs have proper impact on SDP answer
@@ -3474,28 +3498,26 @@ TEST_F(SignalingTest, MaxFsFrInAnswer)
 
   sipcc::MediaConstraints constraints;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   ASSERT_TRUE(prefs);
   FsFrPrefClearer prefClearer(prefs);
 
   // We don't want max_fs and max_fr prefs impact SDP at this moment
-  prefs->SetIntPref("media.navigator.video.max_fs", 0);
-  prefs->SetIntPref("media.navigator.video.max_fr", 0);
+  SetMaxFsFr(prefs, 0, 0);
 
   a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
 
   // SDP should not contain max-fs and max-fr here
   CheckMaxFsFrSdp(a1_->offer(), 120, 0, 0);
 
   a2_->SetRemote(TestObserver::OFFER, a1_->offer());
 
-  prefs->SetIntPref("media.navigator.video.max_fs", 600);
-  prefs->SetIntPref("media.navigator.video.max_fr", 60);
+  SetMaxFsFr(prefs, 600, 60);
 
   a2_->CreateAnswer(constraints, a1_->offer(), OFFER_AV | ANSWER_AV);
 
   // Verify that SDP contains correct max-fs and max-fr
   CheckMaxFsFrSdp(a2_->answer(), 120, 600, 60);
 }
 
 // Test SDP offer has proper impact on callee's codec configuration
@@ -3505,18 +3527,17 @@ TEST_F(SignalingTest, MaxFsFrCalleeCodec
 
   sipcc::MediaConstraints constraints;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   ASSERT_TRUE(prefs);
   FsFrPrefClearer prefClearer(prefs);
 
   // We don't want max_fs and max_fr prefs impact SDP at this moment
-  prefs->SetIntPref("media.navigator.video.max_fs", 0);
-  prefs->SetIntPref("media.navigator.video.max_fr", 0);
+  SetMaxFsFr(prefs, 0, 0);
 
   a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
 
   ParsedSDP sdpWrapper(a1_->offer());
 
   sdpWrapper.ReplaceLine("a=rtpmap:120",
     "a=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=300;max-fr=30\r\n");
 
@@ -3562,18 +3583,17 @@ TEST_F(SignalingTest, MaxFsFrCallerCodec
 
   sipcc::MediaConstraints constraints;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   ASSERT_TRUE(prefs);
   FsFrPrefClearer prefClearer(prefs);
 
   // We don't want max_fs and max_fr prefs impact SDP at this moment
-  prefs->SetIntPref("media.navigator.video.max_fs", 0);
-  prefs->SetIntPref("media.navigator.video.max_fr", 0);
+  SetMaxFsFr(prefs, 0, 0);
 
   a1_->CreateOffer(constraints, OFFER_AV, SHOULD_CHECK_AV);
   a1_->SetLocal(TestObserver::OFFER, a1_->offer());
   a2_->SetRemote(TestObserver::OFFER, a1_->offer());
 
   a2_->CreateAnswer(constraints, a1_->offer(), OFFER_AV | ANSWER_AV);
 
   ParsedSDP sdpWrapper(a2_->answer());
@@ -3637,16 +3657,49 @@ static std::string get_environment(const
   char *value = getenv(name);
 
   if (!value)
     return "";
 
   return value;
 }
 
+// This exists to send as an event to trigger shutdown.
+static void tests_complete() {
+  gTestsComplete = true;
+}
+
+// The GTest thread runs this instead of the main thread so it can
+// do things like ASSERT_TRUE_WAIT which you could not do on the main thread.
+static int gtest_main(int argc, char **argv) {
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  ::testing::InitGoogleTest(&argc, argv);
+
+  for(int i=0; i<argc; i++) {
+    if (!strcmp(argv[i],"-t")) {
+      kDefaultTimeout = 20000;
+    }
+   }
+
+  ::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
+  int result = RUN_ALL_TESTS();
+
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
+
+  // Set the global shutdown flag and tickle the main thread
+  // The main thread did not go through Init() so calling Shutdown()
+  // on it will not work.
+  gMainThread->Dispatch(WrapRunnableNM(tests_complete), NS_DISPATCH_SYNC);
+
+  return result;
+}
+
+
 int main(int argc, char **argv) {
 
   // This test can cause intermittent oranges on the builders
   CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS")
 
   if (isatty(STDOUT_FILENO) && is_color_terminal(getenv("TERM"))) {
     std::string ansiMagenta = "\x1b[35m";
     std::string ansiCyan = "\x1b[36m";
@@ -3662,37 +3715,42 @@ int main(int argc, char **argv) {
   tmp = get_environment("STUN_SERVER_PORT");
   if (tmp != "")
       g_stun_server_port = atoi(tmp.c_str());
 
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
-  ::testing::InitGoogleTest(&argc, argv);
-
-  for(int i=0; i<argc; i++) {
-    if (!strcmp(argv[i],"-t")) {
-      kDefaultTimeout = 20000;
-    }
-  }
-
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
 
-  ::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
-  int result = RUN_ALL_TESTS();
-
-  test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
-
-  // Because we don't initialize on the main thread, we can't register for
-  // XPCOM shutdown callbacks (where the context is usually shut down) --
-  // so we need to explictly destroy the context.
+  // Set the main thread global which is this thread.
+  nsIThread *thread;
+  NS_GetMainThread(&thread);
+  gMainThread = thread;
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Now create the GTest thread and run all of the tests on it
+  // When it is complete it will set gTestsComplete
+  NS_NewNamedThread("gtest_thread", &thread);
+  gGtestThread = thread;
+
+  int result;
+  gGtestThread->Dispatch(
+    WrapRunnableNMRet(gtest_main, argc, argv, &result), NS_DISPATCH_NORMAL);
+
+  // Here we handle the event queue for dispatches to the main thread
+  // When the GTest thread is complete it will send one more dispatch
+  // with gTestsComplete == true.
+  while (!gTestsComplete && NS_ProcessNextEvent());
+
+  gGtestThread->Shutdown();
+
   sipcc::PeerConnectionCtx::Destroy();
   delete test_utils;
 
   return result;
 }