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