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