Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004--2011, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/base/messagequeue.h"
     29 
     30 #include "talk/base/bind.h"
     31 #include "talk/base/gunit.h"
     32 #include "talk/base/logging.h"
     33 #include "talk/base/thread.h"
     34 #include "talk/base/timeutils.h"
     35 #include "talk/base/nullsocketserver.h"
     36 
     37 using namespace talk_base;
     38 
     39 class MessageQueueTest: public testing::Test, public MessageQueue {
     40  public:
     41   bool IsLocked_Worker() {
     42     if (!crit_.TryEnter()) {
     43       return true;
     44     }
     45     crit_.Leave();
     46     return false;
     47   }
     48   bool IsLocked() {
     49     // We have to do this on a worker thread, or else the TryEnter will
     50     // succeed, since our critical sections are reentrant.
     51     Thread worker;
     52     worker.Start();
     53     return worker.Invoke<bool>(
     54         talk_base::Bind(&MessageQueueTest::IsLocked_Worker, this));
     55   }
     56 };
     57 
     58 struct DeletedLockChecker {
     59   DeletedLockChecker(MessageQueueTest* test, bool* was_locked, bool* deleted)
     60       : test(test), was_locked(was_locked), deleted(deleted) { }
     61   ~DeletedLockChecker() {
     62     *deleted = true;
     63     *was_locked = test->IsLocked();
     64   }
     65   MessageQueueTest* test;
     66   bool* was_locked;
     67   bool* deleted;
     68 };
     69 
     70 static void DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(
     71     MessageQueue* q) {
     72   EXPECT_TRUE(q != NULL);
     73   TimeStamp now = Time();
     74   q->PostAt(now, NULL, 3);
     75   q->PostAt(now - 2, NULL, 0);
     76   q->PostAt(now - 1, NULL, 1);
     77   q->PostAt(now, NULL, 4);
     78   q->PostAt(now - 1, NULL, 2);
     79 
     80   Message msg;
     81   for (size_t i=0; i<5; ++i) {
     82     memset(&msg, 0, sizeof(msg));
     83     EXPECT_TRUE(q->Get(&msg, 0));
     84     EXPECT_EQ(i, msg.message_id);
     85   }
     86 
     87   EXPECT_FALSE(q->Get(&msg, 0));  // No more messages
     88 }
     89 
     90 TEST_F(MessageQueueTest,
     91        DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder) {
     92   MessageQueue q;
     93   DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q);
     94   NullSocketServer nullss;
     95   MessageQueue q_nullss(&nullss);
     96   DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q_nullss);
     97 }
     98 
     99 TEST_F(MessageQueueTest, DisposeNotLocked) {
    100   bool was_locked = true;
    101   bool deleted = false;
    102   DeletedLockChecker* d = new DeletedLockChecker(this, &was_locked, &deleted);
    103   Dispose(d);
    104   Message msg;
    105   EXPECT_FALSE(Get(&msg, 0));
    106   EXPECT_TRUE(deleted);
    107   EXPECT_FALSE(was_locked);
    108 }
    109 
    110 class DeletedMessageHandler : public MessageHandler {
    111  public:
    112   explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) { }
    113   ~DeletedMessageHandler() {
    114     *deleted_ = true;
    115   }
    116   void OnMessage(Message* msg) { }
    117  private:
    118   bool* deleted_;
    119 };
    120 
    121 TEST_F(MessageQueueTest, DiposeHandlerWithPostedMessagePending) {
    122   bool deleted = false;
    123   DeletedMessageHandler *handler = new DeletedMessageHandler(&deleted);
    124   // First, post a dispose.
    125   Dispose(handler);
    126   // Now, post a message, which should *not* be returned by Get().
    127   Post(handler, 1);
    128   Message msg;
    129   EXPECT_FALSE(Get(&msg, 0));
    130   EXPECT_TRUE(deleted);
    131 }
    132 
    133 struct UnwrapMainThreadScope {
    134   UnwrapMainThreadScope() : rewrap_(Thread::Current() != NULL) {
    135     if (rewrap_) ThreadManager::Instance()->UnwrapCurrentThread();
    136   }
    137   ~UnwrapMainThreadScope() {
    138     if (rewrap_) ThreadManager::Instance()->WrapCurrentThread();
    139   }
    140  private:
    141   bool rewrap_;
    142 };
    143 
    144 TEST(MessageQueueManager, Clear) {
    145   UnwrapMainThreadScope s;
    146   if (MessageQueueManager::IsInitialized()) {
    147     LOG(LS_INFO) << "Unable to run MessageQueueManager::Clear test, since the "
    148                  << "MessageQueueManager was already initialized by some "
    149                  << "other test in this run.";
    150     return;
    151   }
    152   bool deleted = false;
    153   DeletedMessageHandler* handler = new DeletedMessageHandler(&deleted);
    154   delete handler;
    155   EXPECT_TRUE(deleted);
    156   EXPECT_FALSE(MessageQueueManager::IsInitialized());
    157 }
    158