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 14namespace base { 15 16class 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 61namespace { 62 63// Concrete implementation of MessagePumpIOSForIO::Watcher that does 64// nothing useful. 65class 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. 78TEST_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 90class 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 111class 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 128TEST_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 140class 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 164TEST_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 175TEST_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