ipc_channel_proxy_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1// Copyright 2014 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 "build/build_config.h" 6 7#include "base/message_loop/message_loop.h" 8#include "base/pickle.h" 9#include "base/threading/thread.h" 10#include "ipc/ipc_message.h" 11#include "ipc/ipc_message_macros.h" 12#include "ipc/ipc_test_base.h" 13#include "ipc/message_filter.h" 14 15namespace { 16 17#if defined(IPC_MESSAGE_START) 18#undef IPC_MESSAGE_START 19#endif 20 21enum Command { 22 SEND, 23 QUIT 24}; 25 26static void Send(IPC::Sender* sender, 27 int message_class, 28 Command command) { 29 const int IPC_MESSAGE_START = message_class; 30 IPC::Message* message = new IPC::Message(0, 31 IPC_MESSAGE_ID(), 32 IPC::Message::PRIORITY_NORMAL); 33 message->WriteInt(command); 34 sender->Send(message); 35} 36 37class QuitListener : public IPC::Listener { 38 public: 39 QuitListener() {} 40 virtual ~QuitListener() {} 41 42 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 43 PickleIterator iter(message); 44 45 int command = SEND; 46 EXPECT_TRUE(iter.ReadInt(&command)); 47 if (command == QUIT) 48 base::MessageLoop::current()->QuitWhenIdle(); 49 50 return true; 51 } 52}; 53 54class ChannelReflectorListener : public IPC::Listener { 55 public: 56 ChannelReflectorListener() : channel_(NULL) {} 57 virtual ~ChannelReflectorListener() {} 58 59 void Init(IPC::Channel* channel) { 60 DCHECK(!channel_); 61 channel_ = channel; 62 } 63 64 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 65 CHECK(channel_); 66 67 PickleIterator iter(message); 68 69 int command = SEND; 70 EXPECT_TRUE(iter.ReadInt(&command)); 71 if (command == QUIT) { 72 channel_->Send(new IPC::Message(message)); 73 base::MessageLoop::current()->QuitWhenIdle(); 74 return true; 75 } 76 77 channel_->Send(new IPC::Message(message)); 78 return true; 79 } 80 81 private: 82 IPC::Channel* channel_; 83}; 84 85class MessageCountFilter : public IPC::MessageFilter { 86 public: 87 enum FilterEvent { 88 NONE, 89 FILTER_ADDED, 90 CHANNEL_CONNECTED, 91 CHANNEL_ERROR, 92 CHANNEL_CLOSING, 93 FILTER_REMOVED 94 }; 95 MessageCountFilter() 96 : messages_received_(0), 97 supported_message_class_(0), 98 is_global_filter_(true), 99 last_filter_event_(NONE), 100 message_filtering_enabled_(false) {} 101 102 MessageCountFilter(uint32 supported_message_class) 103 : messages_received_(0), 104 supported_message_class_(supported_message_class), 105 is_global_filter_(false), 106 last_filter_event_(NONE), 107 message_filtering_enabled_(false) {} 108 109 virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE { 110 EXPECT_TRUE(channel); 111 EXPECT_EQ(NONE, last_filter_event_); 112 last_filter_event_ = FILTER_ADDED; 113 } 114 115 virtual void OnChannelConnected(int32_t peer_pid) OVERRIDE { 116 EXPECT_EQ(FILTER_ADDED, last_filter_event_); 117 EXPECT_NE(static_cast<int32_t>(base::kNullProcessId), peer_pid); 118 last_filter_event_ = CHANNEL_CONNECTED; 119 } 120 121 virtual void OnChannelError() OVERRIDE { 122 EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_); 123 last_filter_event_ = CHANNEL_ERROR; 124 } 125 126 virtual void OnChannelClosing() OVERRIDE { 127 // We may or may not have gotten OnChannelError; if not, the last event has 128 // to be OnChannelConnected. 129 if (last_filter_event_ != CHANNEL_ERROR) 130 EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_); 131 last_filter_event_ = CHANNEL_CLOSING; 132 } 133 134 virtual void OnFilterRemoved() OVERRIDE { 135 // If the channel didn't get a chance to connect, we might see the 136 // OnFilterRemoved event with no other events preceding it. We still want 137 // OnFilterRemoved to be called to allow for deleting the Filter. 138 if (last_filter_event_ != NONE) 139 EXPECT_EQ(CHANNEL_CLOSING, last_filter_event_); 140 last_filter_event_ = FILTER_REMOVED; 141 } 142 143 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 144 // We should always get the OnFilterAdded and OnChannelConnected events 145 // prior to any messages. 146 EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_); 147 148 if (!is_global_filter_) { 149 EXPECT_EQ(supported_message_class_, IPC_MESSAGE_CLASS(message)); 150 } 151 ++messages_received_; 152 return message_filtering_enabled_; 153 } 154 155 virtual bool GetSupportedMessageClasses( 156 std::vector<uint32>* supported_message_classes) const OVERRIDE { 157 if (is_global_filter_) 158 return false; 159 supported_message_classes->push_back(supported_message_class_); 160 return true; 161 } 162 163 void set_message_filtering_enabled(bool enabled) { 164 message_filtering_enabled_ = enabled; 165 } 166 167 size_t messages_received() const { return messages_received_; } 168 FilterEvent last_filter_event() const { return last_filter_event_; } 169 170 private: 171 virtual ~MessageCountFilter() {} 172 173 size_t messages_received_; 174 uint32 supported_message_class_; 175 bool is_global_filter_; 176 177 FilterEvent last_filter_event_; 178 bool message_filtering_enabled_; 179}; 180 181class IPCChannelProxyTest : public IPCTestBase { 182 public: 183 IPCChannelProxyTest() {} 184 virtual ~IPCChannelProxyTest() {} 185 186 virtual void SetUp() OVERRIDE { 187 IPCTestBase::SetUp(); 188 189 Init("ChannelProxyClient"); 190 191 thread_.reset(new base::Thread("ChannelProxyTestServerThread")); 192 base::Thread::Options options; 193 options.message_loop_type = base::MessageLoop::TYPE_IO; 194 thread_->StartWithOptions(options); 195 196 listener_.reset(new QuitListener()); 197 CreateChannelProxy(listener_.get(), thread_->message_loop_proxy().get()); 198 199 ASSERT_TRUE(StartClient()); 200 } 201 202 virtual void TearDown() { 203 DestroyChannelProxy(); 204 thread_.reset(); 205 listener_.reset(); 206 IPCTestBase::TearDown(); 207 } 208 209 void SendQuitMessageAndWaitForIdle() { 210 Send(sender(), -1, QUIT); 211 base::MessageLoop::current()->Run(); 212 EXPECT_TRUE(WaitForClientShutdown()); 213 } 214 215 private: 216 scoped_ptr<base::Thread> thread_; 217 scoped_ptr<QuitListener> listener_; 218}; 219 220TEST_F(IPCChannelProxyTest, MessageClassFilters) { 221 // Construct a filter per message class. 222 std::vector<scoped_refptr<MessageCountFilter> > class_filters; 223 for (uint32 i = 0; i < LastIPCMsgStart; ++i) { 224 class_filters.push_back(make_scoped_refptr( 225 new MessageCountFilter(i))); 226 channel_proxy()->AddFilter(class_filters.back().get()); 227 } 228 229 // Send a message for each class; each filter should receive just one message. 230 for (uint32 i = 0; i < LastIPCMsgStart; ++i) 231 Send(sender(), i, SEND); 232 233 // Send some messages not assigned to a specific or valid message class. 234 Send(sender(), -1, SEND); 235 Send(sender(), LastIPCMsgStart, SEND); 236 Send(sender(), LastIPCMsgStart + 1, SEND); 237 238 // Each filter should have received just the one sent message of the 239 // corresponding class. 240 SendQuitMessageAndWaitForIdle(); 241 for (size_t i = 0; i < class_filters.size(); ++i) 242 EXPECT_EQ(1U, class_filters[i]->messages_received()); 243} 244 245TEST_F(IPCChannelProxyTest, GlobalAndMessageClassFilters) { 246 // Add a class and global filter. 247 const int kMessageClass = 7; 248 scoped_refptr<MessageCountFilter> class_filter( 249 new MessageCountFilter(kMessageClass)); 250 class_filter->set_message_filtering_enabled(false); 251 channel_proxy()->AddFilter(class_filter.get()); 252 253 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); 254 global_filter->set_message_filtering_enabled(false); 255 channel_proxy()->AddFilter(global_filter.get()); 256 257 // A message of class |kMessageClass| should be seen by both the global 258 // filter and |kMessageClass|-specific filter. 259 Send(sender(), kMessageClass, SEND); 260 261 // A message of a different class should be seen only by the global filter. 262 Send(sender(), kMessageClass + 1, SEND); 263 264 // Flush all messages. 265 SendQuitMessageAndWaitForIdle(); 266 267 // The class filter should have received only the class-specific message. 268 EXPECT_EQ(1U, class_filter->messages_received()); 269 270 // The global filter should have received both SEND messages, as well as the 271 // final QUIT message. 272 EXPECT_EQ(3U, global_filter->messages_received()); 273} 274 275TEST_F(IPCChannelProxyTest, FilterRemoval) { 276 // Add a class and global filter. 277 const int kMessageClass = 7; 278 scoped_refptr<MessageCountFilter> class_filter( 279 new MessageCountFilter(kMessageClass)); 280 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); 281 282 // Add and remove both types of filters. 283 channel_proxy()->AddFilter(class_filter.get()); 284 channel_proxy()->AddFilter(global_filter.get()); 285 channel_proxy()->RemoveFilter(global_filter.get()); 286 channel_proxy()->RemoveFilter(class_filter.get()); 287 288 // Send some messages; they should not be seen by either filter. 289 Send(sender(), 0, SEND); 290 Send(sender(), kMessageClass, SEND); 291 292 // Ensure that the filters were removed and did not receive any messages. 293 SendQuitMessageAndWaitForIdle(); 294 EXPECT_EQ(MessageCountFilter::FILTER_REMOVED, 295 global_filter->last_filter_event()); 296 EXPECT_EQ(MessageCountFilter::FILTER_REMOVED, 297 class_filter->last_filter_event()); 298 EXPECT_EQ(0U, class_filter->messages_received()); 299 EXPECT_EQ(0U, global_filter->messages_received()); 300} 301 302MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ChannelProxyClient) { 303 base::MessageLoopForIO main_message_loop; 304 ChannelReflectorListener listener; 305 IPC::Channel channel(IPCTestBase::GetChannelName("ChannelProxyClient"), 306 IPC::Channel::MODE_CLIENT, 307 &listener); 308 CHECK(channel.Connect()); 309 listener.Init(&channel); 310 311 base::MessageLoop::current()->Run(); 312 return 0; 313} 314 315} // namespace 316