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/message_loop/message_loop.h"
     10 #include "base/posix/eintr_wrapper.h"
     11 #include "base/threading/thread.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 #include "third_party/libevent/event.h"
     14 
     15 namespace base {
     16 
     17 class MessagePumpLibeventTest : public testing::Test {
     18  protected:
     19   MessagePumpLibeventTest()
     20       : ui_loop_(MessageLoop::TYPE_UI),
     21         io_thread_("MessagePumpLibeventTestIOThread") {}
     22   virtual ~MessagePumpLibeventTest() {}
     23 
     24   virtual void SetUp() OVERRIDE {
     25     Thread::Options options(MessageLoop::TYPE_IO, 0);
     26     ASSERT_TRUE(io_thread_.StartWithOptions(options));
     27     ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
     28     int ret = pipe(pipefds_);
     29     ASSERT_EQ(0, ret);
     30   }
     31 
     32   virtual void TearDown() OVERRIDE {
     33     if (HANDLE_EINTR(close(pipefds_[0])) < 0)
     34       PLOG(ERROR) << "close";
     35     if (HANDLE_EINTR(close(pipefds_[1])) < 0)
     36       PLOG(ERROR) << "close";
     37   }
     38 
     39   MessageLoop* ui_loop() { return &ui_loop_; }
     40   MessageLoopForIO* io_loop() const {
     41     return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
     42   }
     43 
     44   void OnLibeventNotification(
     45       MessagePumpLibevent* pump,
     46       MessagePumpLibevent::FileDescriptorWatcher* controller) {
     47     pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
     48   }
     49 
     50   int pipefds_[2];
     51 
     52  private:
     53   MessageLoop ui_loop_;
     54   Thread io_thread_;
     55 };
     56 
     57 namespace {
     58 
     59 // Concrete implementation of MessagePumpLibevent::Watcher that does
     60 // nothing useful.
     61 class StupidWatcher : public MessagePumpLibevent::Watcher {
     62  public:
     63   virtual ~StupidWatcher() {}
     64 
     65   // base:MessagePumpLibevent::Watcher interface
     66   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {}
     67   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
     68 };
     69 
     70 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     71 
     72 // Test to make sure that we catch calling WatchFileDescriptor off of the
     73 // wrong thread.
     74 TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
     75   MessagePumpLibevent::FileDescriptorWatcher watcher;
     76   StupidWatcher delegate;
     77 
     78   ASSERT_DEATH(io_loop()->WatchFileDescriptor(
     79       STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
     80       "Check failed: "
     81       "watch_file_descriptor_caller_checker_.CalledOnValidThread()");
     82 }
     83 
     84 #endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
     85 
     86 class BaseWatcher : public MessagePumpLibevent::Watcher {
     87  public:
     88   explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
     89       : controller_(controller) {
     90     DCHECK(controller_);
     91   }
     92   virtual ~BaseWatcher() {}
     93 
     94   // base:MessagePumpLibevent::Watcher interface
     95   virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE {
     96     NOTREACHED();
     97   }
     98 
     99   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    100     NOTREACHED();
    101   }
    102 
    103  protected:
    104   MessagePumpLibevent::FileDescriptorWatcher* controller_;
    105 };
    106 
    107 class DeleteWatcher : public BaseWatcher {
    108  public:
    109   explicit DeleteWatcher(
    110       MessagePumpLibevent::FileDescriptorWatcher* controller)
    111       : BaseWatcher(controller) {}
    112 
    113   virtual ~DeleteWatcher() {
    114     DCHECK(!controller_);
    115   }
    116 
    117   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    118     DCHECK(controller_);
    119     delete controller_;
    120     controller_ = NULL;
    121   }
    122 };
    123 
    124 TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
    125   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
    126   MessagePumpLibevent::FileDescriptorWatcher* watcher =
    127       new MessagePumpLibevent::FileDescriptorWatcher;
    128   DeleteWatcher delegate(watcher);
    129   pump->WatchFileDescriptor(pipefds_[1],
    130       false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
    131 
    132   // Spoof a libevent notification.
    133   OnLibeventNotification(pump.get(), watcher);
    134 }
    135 
    136 class StopWatcher : public BaseWatcher {
    137  public:
    138   explicit StopWatcher(
    139       MessagePumpLibevent::FileDescriptorWatcher* controller)
    140       : BaseWatcher(controller) {}
    141 
    142   virtual ~StopWatcher() {}
    143 
    144   virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {
    145     controller_->StopWatchingFileDescriptor();
    146   }
    147 };
    148 
    149 TEST_F(MessagePumpLibeventTest, StopWatcher) {
    150   scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
    151   MessagePumpLibevent::FileDescriptorWatcher watcher;
    152   StopWatcher delegate(&watcher);
    153   pump->WatchFileDescriptor(pipefds_[1],
    154       false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
    155 
    156   // Spoof a libevent notification.
    157   OnLibeventNotification(pump.get(), &watcher);
    158 }
    159 
    160 }  // namespace
    161 
    162 }  // namespace base
    163