1/*
2 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/messagequeue.h"
12
13#include "webrtc/base/bind.h"
14#include "webrtc/base/gunit.h"
15#include "webrtc/base/logging.h"
16#include "webrtc/base/thread.h"
17#include "webrtc/base/timeutils.h"
18#include "webrtc/base/nullsocketserver.h"
19#include "webrtc/test/testsupport/gtest_disable.h"
20
21using namespace rtc;
22
23class MessageQueueTest: public testing::Test, public MessageQueue {
24 public:
25  bool IsLocked_Worker() {
26    if (!crit_.TryEnter()) {
27      return true;
28    }
29    crit_.Leave();
30    return false;
31  }
32  bool IsLocked() {
33    // We have to do this on a worker thread, or else the TryEnter will
34    // succeed, since our critical sections are reentrant.
35    Thread worker;
36    worker.Start();
37    return worker.Invoke<bool>(
38        rtc::Bind(&MessageQueueTest::IsLocked_Worker, this));
39  }
40};
41
42struct DeletedLockChecker {
43  DeletedLockChecker(MessageQueueTest* test, bool* was_locked, bool* deleted)
44      : test(test), was_locked(was_locked), deleted(deleted) { }
45  ~DeletedLockChecker() {
46    *deleted = true;
47    *was_locked = test->IsLocked();
48  }
49  MessageQueueTest* test;
50  bool* was_locked;
51  bool* deleted;
52};
53
54static void DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(
55    MessageQueue* q) {
56  EXPECT_TRUE(q != NULL);
57  TimeStamp now = Time();
58  q->PostAt(now, NULL, 3);
59  q->PostAt(now - 2, NULL, 0);
60  q->PostAt(now - 1, NULL, 1);
61  q->PostAt(now, NULL, 4);
62  q->PostAt(now - 1, NULL, 2);
63
64  Message msg;
65  for (size_t i=0; i<5; ++i) {
66    memset(&msg, 0, sizeof(msg));
67    EXPECT_TRUE(q->Get(&msg, 0));
68    EXPECT_EQ(i, msg.message_id);
69  }
70
71  EXPECT_FALSE(q->Get(&msg, 0));  // No more messages
72}
73
74TEST_F(MessageQueueTest,
75       DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder) {
76  MessageQueue q;
77  DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q);
78  NullSocketServer nullss;
79  MessageQueue q_nullss(&nullss);
80  DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q_nullss);
81}
82
83TEST_F(MessageQueueTest, DISABLED_ON_MAC(DisposeNotLocked)) {
84  bool was_locked = true;
85  bool deleted = false;
86  DeletedLockChecker* d = new DeletedLockChecker(this, &was_locked, &deleted);
87  Dispose(d);
88  Message msg;
89  EXPECT_FALSE(Get(&msg, 0));
90  EXPECT_TRUE(deleted);
91  EXPECT_FALSE(was_locked);
92}
93
94class DeletedMessageHandler : public MessageHandler {
95 public:
96  explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) { }
97  ~DeletedMessageHandler() {
98    *deleted_ = true;
99  }
100  void OnMessage(Message* msg) { }
101 private:
102  bool* deleted_;
103};
104
105TEST_F(MessageQueueTest, DiposeHandlerWithPostedMessagePending) {
106  bool deleted = false;
107  DeletedMessageHandler *handler = new DeletedMessageHandler(&deleted);
108  // First, post a dispose.
109  Dispose(handler);
110  // Now, post a message, which should *not* be returned by Get().
111  Post(handler, 1);
112  Message msg;
113  EXPECT_FALSE(Get(&msg, 0));
114  EXPECT_TRUE(deleted);
115}
116
117struct UnwrapMainThreadScope {
118  UnwrapMainThreadScope() : rewrap_(Thread::Current() != NULL) {
119    if (rewrap_) ThreadManager::Instance()->UnwrapCurrentThread();
120  }
121  ~UnwrapMainThreadScope() {
122    if (rewrap_) ThreadManager::Instance()->WrapCurrentThread();
123  }
124 private:
125  bool rewrap_;
126};
127
128TEST(MessageQueueManager, Clear) {
129  UnwrapMainThreadScope s;
130  if (MessageQueueManager::IsInitialized()) {
131    LOG(LS_INFO) << "Unable to run MessageQueueManager::Clear test, since the "
132                 << "MessageQueueManager was already initialized by some "
133                 << "other test in this run.";
134    return;
135  }
136  bool deleted = false;
137  DeletedMessageHandler* handler = new DeletedMessageHandler(&deleted);
138  delete handler;
139  EXPECT_TRUE(deleted);
140  EXPECT_FALSE(MessageQueueManager::IsInitialized());
141}
142