Home | History | Annotate | Download | only in message_loop
      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/message_loop/message_pump_libevent.h"
      6 
      7 #include <unistd.h>
      8 
      9 #include "base/bind.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/posix/eintr_wrapper.h"
     12 #include "base/run_loop.h"
     13 #include "base/threading/thread.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/libevent/event.h"
     16 
     17 namespace base {
     18 
     19 class MessagePumpLibeventTest : public testing::Test {
     20  protected:
     21   MessagePumpLibeventTest()
     22       : ui_loop_(MessageLoop::TYPE_UI),
     23         io_thread_("MessagePumpLibeventTestIOThread") {}
     24   virtual ~MessagePumpLibeventTest() {}
     25 
     26   virtual void SetUp() OVERRIDE {
     27     Thread::Options options(MessageLoop::TYPE_IO, 0);
     28     ASSERT_TRUE(io_thread_.StartWithOptions(options));
     29     ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
     30     int ret = pipe(pipefds_);
     31     ASSERT_EQ(0, ret);
     32   }
     33 
     34   virtual void TearDown() OVERRIDE {
     35     if (IGNORE_EINTR(close(pipefds_[0])) < 0)
     36       PLOG(ERROR) << "close";
     37     if (IGNORE_EINTR(close(pipefds_[1])) < 0)
     38       PLOG(ERROR) << "close";
     39   }
     40 
     41   MessageLoop* ui_loop() { return &ui_loop_; }
     42   MessageLoopForIO* io_loop() const {
     43     return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
     44   }
     45 
     46   void OnLibeventNotification(
     47       MessagePumpLibevent* pump,
     48       MessagePumpLibevent::FileDescriptorWatcher* controller) {
     49     pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
     50   }
     51 
     52   int pipefds_[2];
     53 
     54  private:
     55   MessageLoop ui_loop_;
     56   Thread io_thread_;
     57 };
     58 
     59 namespace {
     60 
     61 // Concrete implementation of MessagePumpLibevent::Watcher that does
     62 // nothing useful.
     63 class StupidWatcher : public MessagePumpLibevent::Watcher {
     64  public:
     65   virtual ~StupidWatcher() {}
     66 
     67   // base:MessagePumpLibevent::Watcher interface
     68   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
     69   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
     70 };
     71 
     72 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     73 
     74 // Test to make sure that we catch calling WatchFileDescriptor off of the
     75 // wrong thread.
     76 TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
     77   MessagePumpLibevent::FileDescriptorWatcher watcher;
     78   StupidWatcher delegate;
     79 
     80   ASSERT_DEATH(io_loop()->WatchFileDescriptor(
     81       STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
     82       "Check failed: "
     83       "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)");
     84 }
     85 
     86 TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) {
     87   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
     88   ASSERT_DEATH(pump->Quit(), "Check failed: in_run_. "
     89                              "Quit was called outside of Run!");
     90 }
     91 
     92 #endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     93 
     94 class BaseWatcher : public MessagePumpLibevent::Watcher {
     95  public:
     96   explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
     97       : controller_(controller) {
     98     DCHECK(controller_);
     99   }
    100   virtual ~BaseWatcher() {}
    101 
    102   // base:MessagePumpLibevent::Watcher interface
    103   virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
    104     NOTREACHED();
    105   }
    106 
    107   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    108     NOTREACHED();
    109   }
    110 
    111  protected:
    112   MessagePumpLibevent::FileDescriptorWatcher* controller_;
    113 };
    114 
    115 class DeleteWatcher : public BaseWatcher {
    116  public:
    117   explicit DeleteWatcher(
    118       MessagePumpLibevent::FileDescriptorWatcher* controller)
    119       : BaseWatcher(controller) {}
    120 
    121   virtual ~DeleteWatcher() {
    122     DCHECK(!controller_);
    123   }
    124 
    125   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    126     DCHECK(controller_);
    127     delete controller_;
    128     controller_ = NULL;
    129   }
    130 };
    131 
    132 TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
    133   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
    134   MessagePumpLibevent::FileDescriptorWatcher* watcher =
    135       new MessagePumpLibevent::FileDescriptorWatcher;
    136   DeleteWatcher delegate(watcher);
    137   pump->WatchFileDescriptor(pipefds_[1],
    138       false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
    139 
    140   // Spoof a libevent notification.
    141   OnLibeventNotification(pump.get(), watcher);
    142 }
    143 
    144 class StopWatcher : public BaseWatcher {
    145  public:
    146   explicit StopWatcher(
    147       MessagePumpLibevent::FileDescriptorWatcher* controller)
    148       : BaseWatcher(controller) {}
    149 
    150   virtual ~StopWatcher() {}
    151 
    152   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    153     controller_->StopWatchingFileDescriptor();
    154   }
    155 };
    156 
    157 TEST_F(MessagePumpLibeventTest, StopWatcher) {
    158   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
    159   MessagePumpLibevent::FileDescriptorWatcher watcher;
    160   StopWatcher delegate(&watcher);
    161   pump->WatchFileDescriptor(pipefds_[1],
    162       false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
    163 
    164   // Spoof a libevent notification.
    165   OnLibeventNotification(pump.get(), &watcher);
    166 }
    167 
    168 void QuitMessageLoopAndStart(const Closure& quit_closure) {
    169   quit_closure.Run();
    170 
    171   MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
    172   RunLoop runloop;
    173   MessageLoop::current()->PostTask(FROM_HERE, runloop.QuitClosure());
    174   runloop.Run();
    175 }
    176 
    177 class NestedPumpWatcher : public MessagePumpLibevent::Watcher {
    178  public:
    179   NestedPumpWatcher() {}
    180   virtual ~NestedPumpWatcher() {}
    181 
    182   virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
    183     RunLoop runloop;
    184     MessageLoop::current()->PostTask(FROM_HERE, Bind(&QuitMessageLoopAndStart,
    185                                                      runloop.QuitClosure()));
    186     runloop.Run();
    187   }
    188 
    189   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {}
    190 };
    191 
    192 TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) {
    193   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
    194   MessagePumpLibevent::FileDescriptorWatcher watcher;
    195   NestedPumpWatcher delegate;
    196   pump->WatchFileDescriptor(pipefds_[1],
    197       false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate);
    198 
    199   // Spoof a libevent notification.
    200   OnLibeventNotification(pump.get(), &watcher);
    201 }
    202 
    203 }  // namespace
    204 
    205 }  // namespace base
    206