ipc_channel_proxy_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 14namespace { 15 16#if defined(IPC_MESSAGE_START) 17#undef IPC_MESSAGE_START 18#endif 19 20enum Command { 21 SEND, 22 QUIT 23}; 24 25static void Send(IPC::Sender* sender, 26 int message_class, 27 Command command) { 28 const int IPC_MESSAGE_START = message_class; 29 IPC::Message* message = new IPC::Message(0, 30 IPC_MESSAGE_ID(), 31 IPC::Message::PRIORITY_NORMAL); 32 message->WriteInt(command); 33 sender->Send(message); 34} 35 36class QuitListener : public IPC::Listener { 37 public: 38 QuitListener() {} 39 virtual ~QuitListener() {} 40 41 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 42 PickleIterator iter(message); 43 44 int command = SEND; 45 EXPECT_TRUE(iter.ReadInt(&command)); 46 if (command == QUIT) 47 base::MessageLoop::current()->QuitWhenIdle(); 48 49 return true; 50 } 51}; 52 53class ChannelReflectorListener : public IPC::Listener { 54 public: 55 ChannelReflectorListener() : channel_(NULL) {} 56 virtual ~ChannelReflectorListener() {} 57 58 void Init(IPC::Channel* channel) { 59 DCHECK(!channel_); 60 channel_ = channel; 61 } 62 63 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 64 CHECK(channel_); 65 66 PickleIterator iter(message); 67 68 int command = SEND; 69 EXPECT_TRUE(iter.ReadInt(&command)); 70 if (command == QUIT) { 71 channel_->Send(new IPC::Message(message)); 72 base::MessageLoop::current()->QuitWhenIdle(); 73 return true; 74 } 75 76 channel_->Send(new IPC::Message(message)); 77 return true; 78 } 79 80 private: 81 IPC::Channel* channel_; 82}; 83 84class MessageCountFilter : public IPC::ChannelProxy::MessageFilter { 85 public: 86 MessageCountFilter() 87 : messages_received_(0), 88 supported_message_class_(0), 89 is_global_filter_(true), 90 filter_removed_(false), 91 message_filtering_enabled_(false) {} 92 93 MessageCountFilter(uint32 supported_message_class) 94 : messages_received_(0), 95 supported_message_class_(supported_message_class), 96 is_global_filter_(false), 97 filter_removed_(false), 98 message_filtering_enabled_(false) {} 99 100 virtual void OnFilterRemoved() OVERRIDE { 101 EXPECT_FALSE(filter_removed_); 102 filter_removed_ = true; 103 } 104 105 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 106 if (!is_global_filter_) { 107 EXPECT_EQ(supported_message_class_, IPC_MESSAGE_CLASS(message)); 108 } 109 ++messages_received_; 110 return message_filtering_enabled_; 111 } 112 113 virtual bool GetSupportedMessageClasses( 114 std::vector<uint32>* supported_message_classes) const OVERRIDE { 115 if (is_global_filter_) 116 return false; 117 supported_message_classes->push_back(supported_message_class_); 118 return true; 119 } 120 121 void set_message_filtering_enabled(bool enabled) { 122 message_filtering_enabled_ = enabled; 123 } 124 125 size_t messages_received() const { return messages_received_; } 126 bool filter_removed() const { return filter_removed_; } 127 128 private: 129 virtual ~MessageCountFilter() {} 130 131 size_t messages_received_; 132 uint32 supported_message_class_; 133 bool is_global_filter_; 134 bool filter_removed_; 135 bool message_filtering_enabled_; 136}; 137 138class IPCChannelProxyTest : public IPCTestBase { 139 public: 140 IPCChannelProxyTest() {} 141 virtual ~IPCChannelProxyTest() {} 142 143 virtual void SetUp() OVERRIDE { 144 IPCTestBase::SetUp(); 145 146 Init("ChannelProxyClient"); 147 148 thread_.reset(new base::Thread("ChannelProxyTestServerThread")); 149 base::Thread::Options options; 150 options.message_loop_type = base::MessageLoop::TYPE_IO; 151 thread_->StartWithOptions(options); 152 153 listener_.reset(new QuitListener()); 154 CreateChannelProxy(listener_.get(), thread_->message_loop_proxy().get()); 155 156 ASSERT_TRUE(StartClient()); 157 } 158 159 virtual void TearDown() { 160 DestroyChannelProxy(); 161 thread_.reset(); 162 listener_.reset(); 163 IPCTestBase::TearDown(); 164 } 165 166 void SendQuitMessageAndWaitForIdle() { 167 Send(sender(), -1, QUIT); 168 base::MessageLoop::current()->Run(); 169 EXPECT_TRUE(WaitForClientShutdown()); 170 } 171 172 private: 173 scoped_ptr<base::Thread> thread_; 174 scoped_ptr<QuitListener> listener_; 175}; 176 177TEST_F(IPCChannelProxyTest, MessageClassFilters) { 178 // Construct a filter per message class. 179 std::vector<scoped_refptr<MessageCountFilter> > class_filters; 180 for (uint32 i = 0; i < LastIPCMsgStart; ++i) { 181 class_filters.push_back(make_scoped_refptr( 182 new MessageCountFilter(i))); 183 channel_proxy()->AddFilter(class_filters.back().get()); 184 } 185 186 // Send a message for each class; each filter should receive just one message. 187 for (uint32 i = 0; i < LastIPCMsgStart; ++i) 188 Send(sender(), i, SEND); 189 190 // Send some messages not assigned to a specific or valid message class. 191 Send(sender(), -1, SEND); 192 Send(sender(), LastIPCMsgStart, SEND); 193 Send(sender(), LastIPCMsgStart + 1, SEND); 194 195 // Each filter should have received just the one sent message of the 196 // corresponding class. 197 SendQuitMessageAndWaitForIdle(); 198 for (size_t i = 0; i < class_filters.size(); ++i) 199 EXPECT_EQ(1U, class_filters[i]->messages_received()); 200} 201 202TEST_F(IPCChannelProxyTest, GlobalAndMessageClassFilters) { 203 // Add a class and global filter. 204 const int kMessageClass = 7; 205 scoped_refptr<MessageCountFilter> class_filter( 206 new MessageCountFilter(kMessageClass)); 207 class_filter->set_message_filtering_enabled(false); 208 channel_proxy()->AddFilter(class_filter.get()); 209 210 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); 211 global_filter->set_message_filtering_enabled(false); 212 channel_proxy()->AddFilter(global_filter.get()); 213 214 // A message of class |kMessageClass| should be seen by both the global 215 // filter and |kMessageClass|-specific filter. 216 Send(sender(), kMessageClass, SEND); 217 218 // A message of a different class should be seen only by the global filter. 219 Send(sender(), kMessageClass + 1, SEND); 220 221 // Flush all messages. 222 SendQuitMessageAndWaitForIdle(); 223 224 // The class filter should have received only the class-specific message. 225 EXPECT_EQ(1U, class_filter->messages_received()); 226 227 // The global filter should have received both SEND messages, as well as the 228 // final QUIT message. 229 EXPECT_EQ(3U, global_filter->messages_received()); 230} 231 232TEST_F(IPCChannelProxyTest, FilterRemoval) { 233 // Add a class and global filter. 234 const int kMessageClass = 7; 235 scoped_refptr<MessageCountFilter> class_filter( 236 new MessageCountFilter(kMessageClass)); 237 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); 238 239 // Add and remove both types of filters. 240 channel_proxy()->AddFilter(class_filter.get()); 241 channel_proxy()->AddFilter(global_filter.get()); 242 channel_proxy()->RemoveFilter(global_filter.get()); 243 channel_proxy()->RemoveFilter(class_filter.get()); 244 245 // Send some messages; they should not be seen by either filter. 246 Send(sender(), 0, SEND); 247 Send(sender(), kMessageClass, SEND); 248 249 // Ensure that the filters were removed and did not receive any messages. 250 SendQuitMessageAndWaitForIdle(); 251 EXPECT_TRUE(global_filter->filter_removed()); 252 EXPECT_TRUE(class_filter->filter_removed()); 253 EXPECT_EQ(0U, class_filter->messages_received()); 254 EXPECT_EQ(0U, global_filter->messages_received()); 255} 256 257MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ChannelProxyClient) { 258 base::MessageLoopForIO main_message_loop; 259 ChannelReflectorListener listener; 260 IPC::Channel channel(IPCTestBase::GetChannelName("ChannelProxyClient"), 261 IPC::Channel::MODE_CLIENT, 262 &listener); 263 CHECK(channel.Connect()); 264 listener.Init(&channel); 265 266 base::MessageLoop::current()->Run(); 267 return 0; 268} 269 270} // namespace 271