Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / base / sequence_checker_unittest.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/bind_helpers.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/sequence_checker.h"
14 #include "base/test/sequenced_worker_pool_owner.h"
15 #include "base/threading/thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 // Duplicated from base/sequence_checker.h so that we can be good citizens
19 // there and undef the macro.
20 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
21 #define ENABLE_SEQUENCE_CHECKER 1
22 #else
23 #define ENABLE_SEQUENCE_CHECKER 0
24 #endif
25
26 namespace base {
27
28 namespace {
29
30 const size_t kNumWorkerThreads = 3;
31
32 // Simple class to exercise the basics of SequenceChecker.
33 // DoStuff should verify that it's called on a valid sequenced thread.
34 // SequenceCheckedObject can be destroyed on any thread (like WeakPtr).
35 class SequenceCheckedObject {
36  public:
37   SequenceCheckedObject() {}
38   ~SequenceCheckedObject() {}
39
40   // Verifies that it was called on the same thread as the constructor.
41   void DoStuff() {
42     DCHECK(sequence_checker_.CalledOnValidSequencedThread());
43   }
44
45   void DetachFromSequence() {
46     sequence_checker_.DetachFromSequence();
47   }
48
49  private:
50   SequenceChecker sequence_checker_;
51
52   DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject);
53 };
54
55 class SequenceCheckerTest : public testing::Test {
56  public:
57   SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {}
58
59   virtual ~SequenceCheckerTest() {}
60
61   virtual void SetUp() OVERRIDE {
62     other_thread_.Start();
63     ResetPool();
64   }
65
66   virtual void TearDown() OVERRIDE {
67     other_thread_.Stop();
68     pool()->Shutdown();
69   }
70
71  protected:
72   base::Thread* other_thread() { return &other_thread_; }
73
74   const scoped_refptr<SequencedWorkerPool>& pool() {
75     return pool_owner_->pool();
76   }
77
78   void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object,
79                                const std::string& token_name) {
80     pool()->PostNamedSequencedWorkerTask(
81         token_name,
82         FROM_HERE,
83         base::Bind(&SequenceCheckedObject::DoStuff,
84                    base::Unretained(sequence_checked_object)));
85   }
86
87   void PostDoStuffToOtherThread(
88       SequenceCheckedObject* sequence_checked_object) {
89     other_thread()->message_loop()->PostTask(
90         FROM_HERE,
91         base::Bind(&SequenceCheckedObject::DoStuff,
92                    base::Unretained(sequence_checked_object)));
93   }
94
95   void PostDeleteToOtherThread(
96       scoped_ptr<SequenceCheckedObject> sequence_checked_object) {
97     other_thread()->message_loop()->DeleteSoon(
98         FROM_HERE,
99         sequence_checked_object.release());
100   }
101
102   // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
103   // down, and creates a new instance.
104   void ResetPool() {
105     pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test"));
106   }
107
108   void MethodOnDifferentThreadDeathTest();
109   void DetachThenCallFromDifferentThreadDeathTest();
110   void DifferentSequenceTokensDeathTest();
111   void WorkerPoolAndSimpleThreadDeathTest();
112   void TwoDifferentWorkerPoolsDeathTest();
113
114  private:
115   MessageLoop message_loop_;  // Needed by SequencedWorkerPool to function.
116   base::Thread other_thread_;
117   scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
118 };
119
120 TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) {
121   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
122       new SequenceCheckedObject);
123
124   // Verify that DoStuff doesn't assert.
125   sequence_checked_object->DoStuff();
126
127   // Verify that the destructor doesn't assert.
128   sequence_checked_object.reset();
129 }
130
131 TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
132   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
133       new SequenceCheckedObject);
134
135   // Verify the destructor doesn't assert when called on a different thread.
136   PostDeleteToOtherThread(sequence_checked_object.Pass());
137   other_thread()->Stop();
138 }
139
140 TEST_F(SequenceCheckerTest, DetachFromSequence) {
141   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
142       new SequenceCheckedObject);
143
144   // Verify that DoStuff doesn't assert when called on a different thread after
145   // a call to DetachFromSequence.
146   sequence_checked_object->DetachFromSequence();
147
148   PostDoStuffToOtherThread(sequence_checked_object.get());
149   other_thread()->Stop();
150 }
151
152 TEST_F(SequenceCheckerTest, SameSequenceTokenValid) {
153   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
154       new SequenceCheckedObject);
155
156   sequence_checked_object->DetachFromSequence();
157   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
158   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
159   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
160   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
161   pool()->FlushForTesting();
162
163   PostDeleteToOtherThread(sequence_checked_object.Pass());
164   other_thread()->Stop();
165 }
166
167 TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
168   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
169       new SequenceCheckedObject);
170
171   sequence_checked_object->DetachFromSequence();
172   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
173   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
174   pool()->FlushForTesting();
175
176   sequence_checked_object->DetachFromSequence();
177   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
178   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
179   pool()->FlushForTesting();
180
181   PostDeleteToOtherThread(sequence_checked_object.Pass());
182   other_thread()->Stop();
183 }
184
185 #if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
186
187 void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() {
188   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
189       new SequenceCheckedObject);
190
191   // DoStuff should assert in debug builds only when called on a
192   // different thread.
193   PostDoStuffToOtherThread(sequence_checked_object.get());
194   other_thread()->Stop();
195 }
196
197 #if ENABLE_SEQUENCE_CHECKER
198 TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) {
199   // The default style "fast" does not support multi-threaded tests.
200   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
201   ASSERT_DEATH({
202     MethodOnDifferentThreadDeathTest();
203   }, "");
204 }
205 #else
206 TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) {
207   MethodOnDifferentThreadDeathTest();
208 }
209 #endif  // ENABLE_SEQUENCE_CHECKER
210
211 void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() {
212   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
213       new SequenceCheckedObject);
214
215   // DoStuff doesn't assert when called on a different thread
216   // after a call to DetachFromSequence.
217   sequence_checked_object->DetachFromSequence();
218   PostDoStuffToOtherThread(sequence_checked_object.get());
219   other_thread()->Stop();
220
221   // DoStuff should assert in debug builds only after moving to
222   // another thread.
223   sequence_checked_object->DoStuff();
224 }
225
226 #if ENABLE_SEQUENCE_CHECKER
227 TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) {
228   // The default style "fast" does not support multi-threaded tests.
229   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
230   ASSERT_DEATH({
231     DetachThenCallFromDifferentThreadDeathTest();
232   }, "");
233 }
234 #else
235 TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) {
236   DetachThenCallFromDifferentThreadDeathTest();
237 }
238 #endif  // ENABLE_SEQUENCE_CHECKER
239
240 void SequenceCheckerTest::DifferentSequenceTokensDeathTest() {
241   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
242       new SequenceCheckedObject);
243
244   sequence_checked_object->DetachFromSequence();
245   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
246   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
247   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
248   PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
249   pool()->FlushForTesting();
250
251   PostDeleteToOtherThread(sequence_checked_object.Pass());
252   other_thread()->Stop();
253 }
254
255 #if ENABLE_SEQUENCE_CHECKER
256 TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) {
257   // The default style "fast" does not support multi-threaded tests.
258   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
259   ASSERT_DEATH({
260     DifferentSequenceTokensDeathTest();
261   }, "");
262 }
263 #else
264 TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInRelease) {
265   DifferentSequenceTokensDeathTest();
266 }
267 #endif  // ENABLE_SEQUENCE_CHECKER
268
269 void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() {
270   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
271       new SequenceCheckedObject);
272
273   sequence_checked_object->DetachFromSequence();
274   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
275   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
276   pool()->FlushForTesting();
277
278   PostDoStuffToOtherThread(sequence_checked_object.get());
279   other_thread()->Stop();
280 }
281
282 #if ENABLE_SEQUENCE_CHECKER
283 TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) {
284   // The default style "fast" does not support multi-threaded tests.
285   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
286   ASSERT_DEATH({
287     WorkerPoolAndSimpleThreadDeathTest();
288   }, "");
289 }
290 #else
291 TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInRelease) {
292   WorkerPoolAndSimpleThreadDeathTest();
293 }
294 #endif  // ENABLE_SEQUENCE_CHECKER
295
296 void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() {
297   scoped_ptr<SequenceCheckedObject> sequence_checked_object(
298       new SequenceCheckedObject);
299
300   sequence_checked_object->DetachFromSequence();
301   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
302   PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
303   pool()->FlushForTesting();
304
305   SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2");
306   second_pool_owner.pool()->PostNamedSequencedWorkerTask(
307       "A",
308       FROM_HERE,
309       base::Bind(&SequenceCheckedObject::DoStuff,
310                  base::Unretained(sequence_checked_object.get())));
311   second_pool_owner.pool()->FlushForTesting();
312   second_pool_owner.pool()->Shutdown();
313 }
314
315 #if ENABLE_SEQUENCE_CHECKER
316 TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) {
317   // The default style "fast" does not support multi-threaded tests.
318   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
319   ASSERT_DEATH({
320     TwoDifferentWorkerPoolsDeathTest();
321   }, "");
322 }
323 #else
324 TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInRelease) {
325   TwoDifferentWorkerPoolsDeathTest();
326 }
327 #endif  // ENABLE_SEQUENCE_CHECKER
328
329 #endif  // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
330
331 }  // namespace
332
333 }  // namespace base
334
335 // Just in case we ever get lumped together with other compilation units.
336 #undef ENABLE_SEQUENCE_CHECKER