Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 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/observer_list.h"
      6 #include "base/observer_list_threadsafe.h"
      7 
      8 #include <vector>
      9 
     10 #include "base/compiler_specific.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/run_loop.h"
     14 #include "base/threading/platform_thread.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace base {
     18 namespace {
     19 
     20 class Foo {
     21  public:
     22   virtual void Observe(int x) = 0;
     23   virtual ~Foo() {}
     24 };
     25 
     26 class Adder : public Foo {
     27  public:
     28   explicit Adder(int scaler) : total(0), scaler_(scaler) {}
     29   virtual void Observe(int x) OVERRIDE {
     30     total += x * scaler_;
     31   }
     32   virtual ~Adder() {}
     33   int total;
     34 
     35  private:
     36   int scaler_;
     37 };
     38 
     39 class Disrupter : public Foo {
     40  public:
     41   Disrupter(ObserverList<Foo>* list, Foo* doomed)
     42       : list_(list),
     43         doomed_(doomed) {
     44   }
     45   virtual ~Disrupter() {}
     46   virtual void Observe(int x) OVERRIDE {
     47     list_->RemoveObserver(doomed_);
     48   }
     49 
     50  private:
     51   ObserverList<Foo>* list_;
     52   Foo* doomed_;
     53 };
     54 
     55 class ThreadSafeDisrupter : public Foo {
     56  public:
     57   ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
     58       : list_(list),
     59         doomed_(doomed) {
     60   }
     61   virtual ~ThreadSafeDisrupter() {}
     62   virtual void Observe(int x) OVERRIDE {
     63     list_->RemoveObserver(doomed_);
     64   }
     65 
     66  private:
     67   ObserverListThreadSafe<Foo>* list_;
     68   Foo* doomed_;
     69 };
     70 
     71 template <typename ObserverListType>
     72 class AddInObserve : public Foo {
     73  public:
     74   explicit AddInObserve(ObserverListType* observer_list)
     75       : added(false),
     76         observer_list(observer_list),
     77         adder(1) {
     78   }
     79 
     80   virtual void Observe(int x) OVERRIDE {
     81     if (!added) {
     82       added = true;
     83       observer_list->AddObserver(&adder);
     84     }
     85   }
     86 
     87   bool added;
     88   ObserverListType* observer_list;
     89   Adder adder;
     90 };
     91 
     92 
     93 static const int kThreadRunTime = 2000;  // ms to run the multi-threaded test.
     94 
     95 // A thread for use in the ThreadSafeObserver test
     96 // which will add and remove itself from the notification
     97 // list repeatedly.
     98 class AddRemoveThread : public PlatformThread::Delegate,
     99                         public Foo {
    100  public:
    101   AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
    102       : list_(list),
    103         loop_(NULL),
    104         in_list_(false),
    105         start_(Time::Now()),
    106         count_observes_(0),
    107         count_addtask_(0),
    108         do_notifies_(notify),
    109         weak_factory_(this) {
    110   }
    111 
    112   virtual ~AddRemoveThread() {
    113   }
    114 
    115   virtual void ThreadMain() OVERRIDE {
    116     loop_ = new MessageLoop();  // Fire up a message loop.
    117     loop_->PostTask(
    118         FROM_HERE,
    119         base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
    120     loop_->Run();
    121     //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
    122     //    count_observes_ << ", " << count_addtask_;
    123     delete loop_;
    124     loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
    125     delete this;
    126   }
    127 
    128   // This task just keeps posting to itself in an attempt
    129   // to race with the notifier.
    130   void AddTask() {
    131     count_addtask_++;
    132 
    133     if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
    134       VLOG(1) << "DONE!";
    135       return;
    136     }
    137 
    138     if (!in_list_) {
    139       list_->AddObserver(this);
    140       in_list_ = true;
    141     }
    142 
    143     if (do_notifies_) {
    144       list_->Notify(&Foo::Observe, 10);
    145     }
    146 
    147     loop_->PostTask(
    148         FROM_HERE,
    149         base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
    150   }
    151 
    152   void Quit() {
    153     loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
    154   }
    155 
    156   virtual void Observe(int x) OVERRIDE {
    157     count_observes_++;
    158 
    159     // If we're getting called after we removed ourselves from
    160     // the list, that is very bad!
    161     DCHECK(in_list_);
    162 
    163     // This callback should fire on the appropriate thread
    164     EXPECT_EQ(loop_, MessageLoop::current());
    165 
    166     list_->RemoveObserver(this);
    167     in_list_ = false;
    168   }
    169 
    170  private:
    171   ObserverListThreadSafe<Foo>* list_;
    172   MessageLoop* loop_;
    173   bool in_list_;        // Are we currently registered for notifications.
    174                         // in_list_ is only used on |this| thread.
    175   Time start_;          // The time we started the test.
    176 
    177   int count_observes_;  // Number of times we observed.
    178   int count_addtask_;   // Number of times thread AddTask was called
    179   bool do_notifies_;    // Whether these threads should do notifications.
    180 
    181   base::WeakPtrFactory<AddRemoveThread> weak_factory_;
    182 };
    183 
    184 TEST(ObserverListTest, BasicTest) {
    185   ObserverList<Foo> observer_list;
    186   Adder a(1), b(-1), c(1), d(-1), e(-1);
    187   Disrupter evil(&observer_list, &c);
    188 
    189   observer_list.AddObserver(&a);
    190   observer_list.AddObserver(&b);
    191 
    192   FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
    193 
    194   observer_list.AddObserver(&evil);
    195   observer_list.AddObserver(&c);
    196   observer_list.AddObserver(&d);
    197 
    198   // Removing an observer not in the list should do nothing.
    199   observer_list.RemoveObserver(&e);
    200 
    201   FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
    202 
    203   EXPECT_EQ(20, a.total);
    204   EXPECT_EQ(-20, b.total);
    205   EXPECT_EQ(0, c.total);
    206   EXPECT_EQ(-10, d.total);
    207   EXPECT_EQ(0, e.total);
    208 }
    209 
    210 TEST(ObserverListThreadSafeTest, BasicTest) {
    211   MessageLoop loop;
    212 
    213   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    214       new ObserverListThreadSafe<Foo>);
    215   Adder a(1);
    216   Adder b(-1);
    217   Adder c(1);
    218   Adder d(-1);
    219   ThreadSafeDisrupter evil(observer_list.get(), &c);
    220 
    221   observer_list->AddObserver(&a);
    222   observer_list->AddObserver(&b);
    223 
    224   observer_list->Notify(&Foo::Observe, 10);
    225   RunLoop().RunUntilIdle();
    226 
    227   observer_list->AddObserver(&evil);
    228   observer_list->AddObserver(&c);
    229   observer_list->AddObserver(&d);
    230 
    231   observer_list->Notify(&Foo::Observe, 10);
    232   RunLoop().RunUntilIdle();
    233 
    234   EXPECT_EQ(20, a.total);
    235   EXPECT_EQ(-20, b.total);
    236   EXPECT_EQ(0, c.total);
    237   EXPECT_EQ(-10, d.total);
    238 }
    239 
    240 TEST(ObserverListThreadSafeTest, RemoveObserver) {
    241   MessageLoop loop;
    242 
    243   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    244       new ObserverListThreadSafe<Foo>);
    245   Adder a(1), b(1);
    246 
    247   // A workaround for the compiler bug. See http://crbug.com/121960.
    248   EXPECT_NE(&a, &b);
    249 
    250   // Should do nothing.
    251   observer_list->RemoveObserver(&a);
    252   observer_list->RemoveObserver(&b);
    253 
    254   observer_list->Notify(&Foo::Observe, 10);
    255   RunLoop().RunUntilIdle();
    256 
    257   EXPECT_EQ(0, a.total);
    258   EXPECT_EQ(0, b.total);
    259 
    260   observer_list->AddObserver(&a);
    261 
    262   // Should also do nothing.
    263   observer_list->RemoveObserver(&b);
    264 
    265   observer_list->Notify(&Foo::Observe, 10);
    266   RunLoop().RunUntilIdle();
    267 
    268   EXPECT_EQ(10, a.total);
    269   EXPECT_EQ(0, b.total);
    270 }
    271 
    272 TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
    273   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    274       new ObserverListThreadSafe<Foo>);
    275 
    276   Adder a(1), b(1), c(1);
    277 
    278   // No MessageLoop, so these should not be added.
    279   observer_list->AddObserver(&a);
    280   observer_list->AddObserver(&b);
    281 
    282   {
    283     // Add c when there's a loop.
    284     MessageLoop loop;
    285     observer_list->AddObserver(&c);
    286 
    287     observer_list->Notify(&Foo::Observe, 10);
    288     RunLoop().RunUntilIdle();
    289 
    290     EXPECT_EQ(0, a.total);
    291     EXPECT_EQ(0, b.total);
    292     EXPECT_EQ(10, c.total);
    293 
    294     // Now add a when there's a loop.
    295     observer_list->AddObserver(&a);
    296 
    297     // Remove c when there's a loop.
    298     observer_list->RemoveObserver(&c);
    299 
    300     // Notify again.
    301     observer_list->Notify(&Foo::Observe, 20);
    302     RunLoop().RunUntilIdle();
    303 
    304     EXPECT_EQ(20, a.total);
    305     EXPECT_EQ(0, b.total);
    306     EXPECT_EQ(10, c.total);
    307   }
    308 
    309   // Removing should always succeed with or without a loop.
    310   observer_list->RemoveObserver(&a);
    311 
    312   // Notifying should not fail but should also be a no-op.
    313   MessageLoop loop;
    314   observer_list->AddObserver(&b);
    315   observer_list->Notify(&Foo::Observe, 30);
    316   RunLoop().RunUntilIdle();
    317 
    318   EXPECT_EQ(20, a.total);
    319   EXPECT_EQ(30, b.total);
    320   EXPECT_EQ(10, c.total);
    321 }
    322 
    323 class FooRemover : public Foo {
    324  public:
    325   explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
    326   virtual ~FooRemover() {}
    327 
    328   void AddFooToRemove(Foo* foo) {
    329     foos_.push_back(foo);
    330   }
    331 
    332   virtual void Observe(int x) OVERRIDE {
    333     std::vector<Foo*> tmp;
    334     tmp.swap(foos_);
    335     for (std::vector<Foo*>::iterator it = tmp.begin();
    336          it != tmp.end(); ++it) {
    337       list_->RemoveObserver(*it);
    338     }
    339   }
    340 
    341  private:
    342   const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
    343   std::vector<Foo*> foos_;
    344 };
    345 
    346 TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
    347   MessageLoop loop;
    348   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    349       new ObserverListThreadSafe<Foo>);
    350 
    351   FooRemover a(observer_list.get());
    352   Adder b(1);
    353 
    354   observer_list->AddObserver(&a);
    355   observer_list->AddObserver(&b);
    356 
    357   a.AddFooToRemove(&a);
    358   a.AddFooToRemove(&b);
    359 
    360   observer_list->Notify(&Foo::Observe, 1);
    361   RunLoop().RunUntilIdle();
    362 }
    363 
    364 // A test driver for a multi-threaded notification loop.  Runs a number
    365 // of observer threads, each of which constantly adds/removes itself
    366 // from the observer list.  Optionally, if cross_thread_notifies is set
    367 // to true, the observer threads will also trigger notifications to
    368 // all observers.
    369 static void ThreadSafeObserverHarness(int num_threads,
    370                                       bool cross_thread_notifies) {
    371   MessageLoop loop;
    372 
    373   const int kMaxThreads = 15;
    374   num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads;
    375 
    376   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    377       new ObserverListThreadSafe<Foo>);
    378   Adder a(1);
    379   Adder b(-1);
    380   Adder c(1);
    381   Adder d(-1);
    382 
    383   observer_list->AddObserver(&a);
    384   observer_list->AddObserver(&b);
    385 
    386   AddRemoveThread* threaded_observer[kMaxThreads];
    387   base::PlatformThreadHandle threads[kMaxThreads];
    388   for (int index = 0; index < num_threads; index++) {
    389     threaded_observer[index] = new AddRemoveThread(observer_list.get(), false);
    390     EXPECT_TRUE(PlatformThread::Create(0,
    391                 threaded_observer[index], &threads[index]));
    392   }
    393 
    394   Time start = Time::Now();
    395   while (true) {
    396     if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
    397       break;
    398 
    399     observer_list->Notify(&Foo::Observe, 10);
    400 
    401     RunLoop().RunUntilIdle();
    402   }
    403 
    404   for (int index = 0; index < num_threads; index++) {
    405     threaded_observer[index]->Quit();
    406     PlatformThread::Join(threads[index]);
    407   }
    408 }
    409 
    410 TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
    411   // Use 7 observer threads.  Notifications only come from
    412   // the main thread.
    413   ThreadSafeObserverHarness(7, false);
    414 }
    415 
    416 TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
    417   // Use 3 observer threads.  Notifications will fire from
    418   // the main thread and all 3 observer threads.
    419   ThreadSafeObserverHarness(3, true);
    420 }
    421 
    422 TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
    423   MessageLoop* loop = new MessageLoop;
    424   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    425       new ObserverListThreadSafe<Foo>);
    426 
    427   Adder a(1);
    428   observer_list->AddObserver(&a);
    429   delete loop;
    430   // Test passes if we don't crash here.
    431   observer_list->Notify(&Foo::Observe, 1);
    432 }
    433 
    434 TEST(ObserverListTest, Existing) {
    435   ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
    436   Adder a(1);
    437   AddInObserve<ObserverList<Foo> > b(&observer_list);
    438 
    439   observer_list.AddObserver(&a);
    440   observer_list.AddObserver(&b);
    441 
    442   FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
    443 
    444   EXPECT_TRUE(b.added);
    445   // B's adder should not have been notified because it was added during
    446   // notificaiton.
    447   EXPECT_EQ(0, b.adder.total);
    448 
    449   // Notify again to make sure b's adder is notified.
    450   FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
    451   EXPECT_EQ(1, b.adder.total);
    452 }
    453 
    454 // Same as above, but for ObserverListThreadSafe
    455 TEST(ObserverListThreadSafeTest, Existing) {
    456   MessageLoop loop;
    457   scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
    458       new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY));
    459   Adder a(1);
    460   AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get());
    461 
    462   observer_list->AddObserver(&a);
    463   observer_list->AddObserver(&b);
    464 
    465   observer_list->Notify(&Foo::Observe, 1);
    466   RunLoop().RunUntilIdle();
    467 
    468   EXPECT_TRUE(b.added);
    469   // B's adder should not have been notified because it was added during
    470   // notificaiton.
    471   EXPECT_EQ(0, b.adder.total);
    472 
    473   // Notify again to make sure b's adder is notified.
    474   observer_list->Notify(&Foo::Observe, 1);
    475   RunLoop().RunUntilIdle();
    476   EXPECT_EQ(1, b.adder.total);
    477 }
    478 
    479 class AddInClearObserve : public Foo {
    480  public:
    481   explicit AddInClearObserve(ObserverList<Foo>* list)
    482       : list_(list), added_(false), adder_(1) {}
    483 
    484   virtual void Observe(int /* x */) OVERRIDE {
    485     list_->Clear();
    486     list_->AddObserver(&adder_);
    487     added_ = true;
    488   }
    489 
    490   bool added() const { return added_; }
    491   const Adder& adder() const { return adder_; }
    492 
    493  private:
    494   ObserverList<Foo>* const list_;
    495 
    496   bool added_;
    497   Adder adder_;
    498 };
    499 
    500 TEST(ObserverListTest, ClearNotifyAll) {
    501   ObserverList<Foo> observer_list;
    502   AddInClearObserve a(&observer_list);
    503 
    504   observer_list.AddObserver(&a);
    505 
    506   FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
    507   EXPECT_TRUE(a.added());
    508   EXPECT_EQ(1, a.adder().total)
    509       << "Adder should observe once and have sum of 1.";
    510 }
    511 
    512 TEST(ObserverListTest, ClearNotifyExistingOnly) {
    513   ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
    514   AddInClearObserve a(&observer_list);
    515 
    516   observer_list.AddObserver(&a);
    517 
    518   FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
    519   EXPECT_TRUE(a.added());
    520   EXPECT_EQ(0, a.adder().total)
    521       << "Adder should not observe, so sum should still be 0.";
    522 }
    523 
    524 class ListDestructor : public Foo {
    525  public:
    526   explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {}
    527   virtual ~ListDestructor() {}
    528 
    529   virtual void Observe(int x) OVERRIDE {
    530     delete list_;
    531   }
    532 
    533  private:
    534   ObserverList<Foo>* list_;
    535 };
    536 
    537 
    538 TEST(ObserverListTest, IteratorOutlivesList) {
    539   ObserverList<Foo>* observer_list = new ObserverList<Foo>;
    540   ListDestructor a(observer_list);
    541   observer_list->AddObserver(&a);
    542 
    543   FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0));
    544   // If this test fails, there'll be Valgrind errors when this function goes out
    545   // of scope.
    546 }
    547 
    548 }  // namespace
    549 }  // namespace base
    550