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 (IGNORE_EINTR(close(pipefds_[0])) < 0) 34 PLOG(ERROR) << "close"; 35 if (IGNORE_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