1 // Copyright (c) 2011 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.
5 #include "base/observer_list.h"
6 #include "base/observer_list_threadsafe.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/threading/platform_thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using base::PlatformThread
;
23 virtual void Observe(int x
) = 0;
27 class Adder
: public Foo
{
29 explicit Adder(int scaler
) : total(0), scaler_(scaler
) {}
30 virtual void Observe(int x
) {
39 class Disrupter
: public Foo
{
41 Disrupter(ObserverList
<Foo
>* list
, Foo
* doomed
)
42 : list_(list
), doomed_(doomed
) { }
43 virtual ~Disrupter() { }
44 virtual void Observe(int x
) {
45 list_
->RemoveObserver(doomed_
);
48 ObserverList
<Foo
>* list_
;
52 class ThreadSafeDisrupter
: public Foo
{
54 ThreadSafeDisrupter(ObserverListThreadSafe
<Foo
>* list
, Foo
* doomed
)
55 : list_(list
), doomed_(doomed
) { }
56 virtual ~ThreadSafeDisrupter() { }
57 virtual void Observe(int x
) {
58 list_
->RemoveObserver(doomed_
);
61 ObserverListThreadSafe
<Foo
>* list_
;
65 template <typename ObserverListType
>
66 class AddInObserve
: public Foo
{
68 explicit AddInObserve(ObserverListType
* observer_list
)
70 observer_list(observer_list
),
73 virtual void Observe(int x
) {
76 observer_list
->AddObserver(&adder
);
81 ObserverListType
* observer_list
;
86 static const int kThreadRunTime
= 2000; // ms to run the multi-threaded test.
88 // A thread for use in the ThreadSafeObserver test
89 // which will add and remove itself from the notification
91 class AddRemoveThread
: public PlatformThread::Delegate
,
94 AddRemoveThread(ObserverListThreadSafe
<Foo
>* list
, bool notify
)
100 do_notifies_(notify
),
101 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
104 virtual ~AddRemoveThread() {
108 loop_
= new MessageLoop(); // Fire up a message loop.
111 base::Bind(&AddRemoveThread::AddTask
, weak_factory_
.GetWeakPtr()));
113 //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
114 // count_observes_ << ", " << count_addtask_;
116 loop_
= reinterpret_cast<MessageLoop
*>(0xdeadbeef);
120 // This task just keeps posting to itself in an attempt
121 // to race with the notifier.
125 if ((Time::Now() - start_
).InMilliseconds() > kThreadRunTime
) {
131 list_
->AddObserver(this);
136 list_
->Notify(&Foo::Observe
, 10);
141 base::Bind(&AddRemoveThread::AddTask
, weak_factory_
.GetWeakPtr()));
145 loop_
->PostTask(FROM_HERE
, new MessageLoop::QuitTask());
148 virtual void Observe(int x
) {
151 // If we're getting called after we removed ourselves from
152 // the list, that is very bad!
155 // This callback should fire on the appropriate thread
156 EXPECT_EQ(loop_
, MessageLoop::current());
158 list_
->RemoveObserver(this);
163 ObserverListThreadSafe
<Foo
>* list_
;
165 bool in_list_
; // Are we currently registered for notifications.
166 // in_list_ is only used on |this| thread.
167 Time start_
; // The time we started the test.
169 int count_observes_
; // Number of times we observed.
170 int count_addtask_
; // Number of times thread AddTask was called
171 bool do_notifies_
; // Whether these threads should do notifications.
173 base::WeakPtrFactory
<AddRemoveThread
> weak_factory_
;
176 TEST(ObserverListTest
, BasicTest
) {
177 ObserverList
<Foo
> observer_list
;
178 Adder
a(1), b(-1), c(1), d(-1), e(-1);
179 Disrupter
evil(&observer_list
, &c
);
181 observer_list
.AddObserver(&a
);
182 observer_list
.AddObserver(&b
);
184 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(10));
186 observer_list
.AddObserver(&evil
);
187 observer_list
.AddObserver(&c
);
188 observer_list
.AddObserver(&d
);
190 // Removing an observer not in the list should do nothing.
191 observer_list
.RemoveObserver(&e
);
193 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(10));
195 EXPECT_EQ(a
.total
, 20);
196 EXPECT_EQ(b
.total
, -20);
197 EXPECT_EQ(c
.total
, 0);
198 EXPECT_EQ(d
.total
, -10);
199 EXPECT_EQ(e
.total
, 0);
202 TEST(ObserverListThreadSafeTest
, BasicTest
) {
205 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
206 new ObserverListThreadSafe
<Foo
>);
211 ThreadSafeDisrupter
evil(observer_list
.get(), &c
);
213 observer_list
->AddObserver(&a
);
214 observer_list
->AddObserver(&b
);
216 observer_list
->Notify(&Foo::Observe
, 10);
217 loop
.RunAllPending();
219 observer_list
->AddObserver(&evil
);
220 observer_list
->AddObserver(&c
);
221 observer_list
->AddObserver(&d
);
223 observer_list
->Notify(&Foo::Observe
, 10);
224 loop
.RunAllPending();
226 EXPECT_EQ(a
.total
, 20);
227 EXPECT_EQ(b
.total
, -20);
228 EXPECT_EQ(c
.total
, 0);
229 EXPECT_EQ(d
.total
, -10);
232 TEST(ObserverListThreadSafeTest
, RemoveObserver
) {
235 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
236 new ObserverListThreadSafe
<Foo
>);
239 // Should do nothing.
240 observer_list
->RemoveObserver(&a
);
241 observer_list
->RemoveObserver(&b
);
243 observer_list
->Notify(&Foo::Observe
, 10);
244 loop
.RunAllPending();
246 EXPECT_EQ(a
.total
, 0);
247 EXPECT_EQ(b
.total
, 0);
249 observer_list
->AddObserver(&a
);
251 // Should also do nothing.
252 observer_list
->RemoveObserver(&b
);
254 observer_list
->Notify(&Foo::Observe
, 10);
255 loop
.RunAllPending();
257 EXPECT_EQ(a
.total
, 10);
258 EXPECT_EQ(b
.total
, 0);
261 class FooRemover
: public Foo
{
263 explicit FooRemover(ObserverListThreadSafe
<Foo
>* list
) : list_(list
) {}
264 virtual ~FooRemover() {}
266 void AddFooToRemove(Foo
* foo
) {
267 foos_
.push_back(foo
);
270 virtual void Observe(int x
) {
271 std::vector
<Foo
*> tmp
;
273 for (std::vector
<Foo
*>::iterator it
= tmp
.begin();
274 it
!= tmp
.end(); ++it
) {
275 list_
->RemoveObserver(*it
);
280 const scoped_refptr
<ObserverListThreadSafe
<Foo
> > list_
;
281 std::vector
<Foo
*> foos_
;
284 TEST(ObserverListThreadSafeTest
, RemoveMultipleObservers
) {
286 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
287 new ObserverListThreadSafe
<Foo
>);
289 FooRemover
a(observer_list
);
292 observer_list
->AddObserver(&a
);
293 observer_list
->AddObserver(&b
);
295 a
.AddFooToRemove(&a
);
296 a
.AddFooToRemove(&b
);
298 observer_list
->Notify(&Foo::Observe
, 1);
299 loop
.RunAllPending();
302 // A test driver for a multi-threaded notification loop. Runs a number
303 // of observer threads, each of which constantly adds/removes itself
304 // from the observer list. Optionally, if cross_thread_notifies is set
305 // to true, the observer threads will also trigger notifications to
307 static void ThreadSafeObserverHarness(int num_threads
,
308 bool cross_thread_notifies
) {
311 const int kMaxThreads
= 15;
312 num_threads
= num_threads
> kMaxThreads
? kMaxThreads
: num_threads
;
314 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
315 new ObserverListThreadSafe
<Foo
>);
321 observer_list
->AddObserver(&a
);
322 observer_list
->AddObserver(&b
);
324 AddRemoveThread
* threaded_observer
[kMaxThreads
];
325 base::PlatformThreadHandle threads
[kMaxThreads
];
326 for (int index
= 0; index
< num_threads
; index
++) {
327 threaded_observer
[index
] = new AddRemoveThread(observer_list
.get(), false);
328 EXPECT_TRUE(PlatformThread::Create(0,
329 threaded_observer
[index
], &threads
[index
]));
332 Time start
= Time::Now();
334 if ((Time::Now() - start
).InMilliseconds() > kThreadRunTime
)
337 observer_list
->Notify(&Foo::Observe
, 10);
339 loop
.RunAllPending();
342 for (int index
= 0; index
< num_threads
; index
++) {
343 threaded_observer
[index
]->Quit();
344 PlatformThread::Join(threads
[index
]);
348 TEST(ObserverListThreadSafeTest
, CrossThreadObserver
) {
349 // Use 7 observer threads. Notifications only come from
351 ThreadSafeObserverHarness(7, false);
354 TEST(ObserverListThreadSafeTest
, CrossThreadNotifications
) {
355 // Use 3 observer threads. Notifications will fire from
356 // the main thread and all 3 observer threads.
357 ThreadSafeObserverHarness(3, true);
360 TEST(ObserverListThreadSafeTest
, OutlivesMessageLoop
) {
361 MessageLoop
* loop
= new MessageLoop
;
362 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
363 new ObserverListThreadSafe
<Foo
>);
366 observer_list
->AddObserver(&a
);
368 // Test passes if we don't crash here.
369 observer_list
->Notify(&Foo::Observe
, 1);
372 TEST(ObserverListTest
, Existing
) {
373 ObserverList
<Foo
> observer_list(ObserverList
<Foo
>::NOTIFY_EXISTING_ONLY
);
375 AddInObserve
<ObserverList
<Foo
> > b(&observer_list
);
377 observer_list
.AddObserver(&a
);
378 observer_list
.AddObserver(&b
);
380 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(1));
382 EXPECT_TRUE(b
.added
);
383 // B's adder should not have been notified because it was added during
385 EXPECT_EQ(0, b
.adder
.total
);
387 // Notify again to make sure b's adder is notified.
388 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(1));
389 EXPECT_EQ(1, b
.adder
.total
);
392 // Same as above, but for ObserverListThreadSafe
393 TEST(ObserverListThreadSafeTest
, Existing
) {
395 scoped_refptr
<ObserverListThreadSafe
<Foo
> > observer_list(
396 new ObserverListThreadSafe
<Foo
>(ObserverList
<Foo
>::NOTIFY_EXISTING_ONLY
));
398 AddInObserve
<ObserverListThreadSafe
<Foo
> > b(observer_list
.get());
400 observer_list
->AddObserver(&a
);
401 observer_list
->AddObserver(&b
);
403 observer_list
->Notify(&Foo::Observe
, 1);
404 loop
.RunAllPending();
406 EXPECT_TRUE(b
.added
);
407 // B's adder should not have been notified because it was added during
409 EXPECT_EQ(0, b
.adder
.total
);
411 // Notify again to make sure b's adder is notified.
412 observer_list
->Notify(&Foo::Observe
, 1);
413 loop
.RunAllPending();
414 EXPECT_EQ(1, b
.adder
.total
);
417 class AddInClearObserve
: public Foo
{
419 explicit AddInClearObserve(ObserverList
<Foo
>* list
)
420 : list_(list
), added_(false), adder_(1) {}
422 virtual void Observe(int /* x */) {
424 list_
->AddObserver(&adder_
);
428 bool added() const { return added_
; }
429 const Adder
& adder() const { return adder_
; }
432 ObserverList
<Foo
>* const list_
;
438 TEST(ObserverListTest
, ClearNotifyAll
) {
439 ObserverList
<Foo
> observer_list
;
440 AddInClearObserve
a(&observer_list
);
442 observer_list
.AddObserver(&a
);
444 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(1));
445 EXPECT_TRUE(a
.added());
446 EXPECT_EQ(1, a
.adder().total
)
447 << "Adder should observe once and have sum of 1.";
450 TEST(ObserverListTest
, ClearNotifyExistingOnly
) {
451 ObserverList
<Foo
> observer_list(ObserverList
<Foo
>::NOTIFY_EXISTING_ONLY
);
452 AddInClearObserve
a(&observer_list
);
454 observer_list
.AddObserver(&a
);
456 FOR_EACH_OBSERVER(Foo
, observer_list
, Observe(1));
457 EXPECT_TRUE(a
.added());
458 EXPECT_EQ(0, a
.adder().total
)
459 << "Adder should not observe, so sum should still be 0.";
462 class ListDestructor
: public Foo
{
464 explicit ListDestructor(ObserverList
<Foo
>* list
) : list_(list
) {}
465 virtual void Observe(int x
) {
468 virtual ~ListDestructor() { }
471 ObserverList
<Foo
>* list_
;
475 TEST(ObserverListTest
, IteratorOutlivesList
) {
476 ObserverList
<Foo
>* observer_list
= new ObserverList
<Foo
>;
477 ListDestructor
a(observer_list
);
478 observer_list
->AddObserver(&a
);
480 FOR_EACH_OBSERVER(Foo
, *observer_list
, Observe(0));
481 // If this test fails, there'll be Valgrind errors when this function goes out