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 179890 e7160b5750b537ef7147d854e583d60c1992dc07
parent 179889 b9b4ff616b32af49791c397ed2585c18fba294be
child 179891 e351fbac578934abf83918d3d634b5cb082d5d40
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjesup
bugs995380
milestone31.0a1
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;
 }