ipc_channel_proxy_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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_test_base.h"
12#include "ipc/message_filter.h"
13
14// Get basic type definitions.
15#define IPC_MESSAGE_IMPL
16#include "ipc/ipc_channel_proxy_unittest_messages.h"
17
18// Generate constructors.
19#include "ipc/struct_constructor_macros.h"
20#include "ipc/ipc_channel_proxy_unittest_messages.h"
21
22// Generate destructors.
23#include "ipc/struct_destructor_macros.h"
24#include "ipc/ipc_channel_proxy_unittest_messages.h"
25
26// Generate param traits write methods.
27#include "ipc/param_traits_write_macros.h"
28namespace IPC {
29#include "ipc/ipc_channel_proxy_unittest_messages.h"
30}  // namespace IPC
31
32// Generate param traits read methods.
33#include "ipc/param_traits_read_macros.h"
34namespace IPC {
35#include "ipc/ipc_channel_proxy_unittest_messages.h"
36}  // namespace IPC
37
38// Generate param traits log methods.
39#include "ipc/param_traits_log_macros.h"
40namespace IPC {
41#include "ipc/ipc_channel_proxy_unittest_messages.h"
42}  // namespace IPC
43
44
45namespace {
46
47class QuitListener : public IPC::Listener {
48 public:
49  QuitListener() : bad_message_received_(false) {}
50  virtual ~QuitListener() {}
51
52  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
53    IPC_BEGIN_MESSAGE_MAP(QuitListener, message)
54      IPC_MESSAGE_HANDLER(WorkerMsg_Quit, OnQuit)
55      IPC_MESSAGE_HANDLER(TestMsg_BadMessage, OnBadMessage)
56    IPC_END_MESSAGE_MAP()
57    return true;
58  }
59
60  virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE {
61    bad_message_received_ = true;
62  }
63
64  void OnQuit() {
65    base::MessageLoop::current()->QuitWhenIdle();
66  }
67
68  void OnBadMessage(const BadType& bad_type) {
69    // Should never be called since IPC wouldn't be deserialized correctly.
70    CHECK(false);
71  }
72
73  bool bad_message_received_;
74};
75
76class ChannelReflectorListener : public IPC::Listener {
77 public:
78  ChannelReflectorListener() : channel_(NULL) {}
79  virtual ~ChannelReflectorListener() {}
80
81  void Init(IPC::Channel* channel) {
82    DCHECK(!channel_);
83    channel_ = channel;
84  }
85
86  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
87    IPC_BEGIN_MESSAGE_MAP(ChannelReflectorListener, message)
88      IPC_MESSAGE_HANDLER(TestMsg_Bounce, OnTestBounce)
89      IPC_MESSAGE_HANDLER(TestMsg_SendBadMessage, OnSendBadMessage)
90      IPC_MESSAGE_HANDLER(UtilityMsg_Bounce, OnUtilityBounce)
91      IPC_MESSAGE_HANDLER(WorkerMsg_Bounce, OnBounce)
92      IPC_MESSAGE_HANDLER(WorkerMsg_Quit, OnQuit)
93    IPC_END_MESSAGE_MAP()
94    return true;
95  }
96
97  void OnTestBounce() {
98    channel_->Send(new TestMsg_Bounce());
99  }
100
101  void OnSendBadMessage() {
102    channel_->Send(new TestMsg_BadMessage(BadType()));
103  }
104
105  void OnUtilityBounce() {
106    channel_->Send(new UtilityMsg_Bounce());
107  }
108
109  void OnBounce() {
110    channel_->Send(new WorkerMsg_Bounce());
111  }
112
113  void OnQuit() {
114    channel_->Send(new WorkerMsg_Quit());
115    base::MessageLoop::current()->QuitWhenIdle();
116  }
117
118 private:
119  IPC::Channel* channel_;
120};
121
122class MessageCountFilter : public IPC::MessageFilter {
123 public:
124  enum FilterEvent {
125    NONE,
126    FILTER_ADDED,
127    CHANNEL_CONNECTED,
128    CHANNEL_ERROR,
129    CHANNEL_CLOSING,
130    FILTER_REMOVED
131  };
132  MessageCountFilter()
133      : messages_received_(0),
134        supported_message_class_(0),
135        is_global_filter_(true),
136        last_filter_event_(NONE),
137        message_filtering_enabled_(false) {}
138
139  MessageCountFilter(uint32 supported_message_class)
140      : messages_received_(0),
141        supported_message_class_(supported_message_class),
142        is_global_filter_(false),
143        last_filter_event_(NONE),
144        message_filtering_enabled_(false) {}
145
146  virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
147    EXPECT_TRUE(sender);
148    EXPECT_EQ(NONE, last_filter_event_);
149    last_filter_event_ = FILTER_ADDED;
150  }
151
152  virtual void OnChannelConnected(int32_t peer_pid) OVERRIDE {
153    EXPECT_EQ(FILTER_ADDED, last_filter_event_);
154    EXPECT_NE(static_cast<int32_t>(base::kNullProcessId), peer_pid);
155    last_filter_event_ = CHANNEL_CONNECTED;
156  }
157
158  virtual void OnChannelError() OVERRIDE {
159    EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
160    last_filter_event_ = CHANNEL_ERROR;
161  }
162
163  virtual void OnChannelClosing() OVERRIDE {
164    // We may or may not have gotten OnChannelError; if not, the last event has
165    // to be OnChannelConnected.
166    if (last_filter_event_ != CHANNEL_ERROR)
167      EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
168    last_filter_event_ = CHANNEL_CLOSING;
169  }
170
171  virtual void OnFilterRemoved() OVERRIDE {
172    // If the channel didn't get a chance to connect, we might see the
173    // OnFilterRemoved event with no other events preceding it. We still want
174    // OnFilterRemoved to be called to allow for deleting the Filter.
175    if (last_filter_event_ != NONE)
176      EXPECT_EQ(CHANNEL_CLOSING, last_filter_event_);
177    last_filter_event_ = FILTER_REMOVED;
178  }
179
180  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
181    // We should always get the OnFilterAdded and OnChannelConnected events
182    // prior to any messages.
183    EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
184
185    if (!is_global_filter_) {
186      EXPECT_EQ(supported_message_class_, IPC_MESSAGE_CLASS(message));
187    }
188    ++messages_received_;
189
190    if (!message_filtering_enabled_)
191      return false;
192
193    bool handled = true;
194    IPC_BEGIN_MESSAGE_MAP(MessageCountFilter, message)
195      IPC_MESSAGE_HANDLER(TestMsg_BadMessage, OnBadMessage)
196      IPC_MESSAGE_UNHANDLED(handled = false)
197    IPC_END_MESSAGE_MAP()
198    return handled;
199  }
200
201  void OnBadMessage(const BadType& bad_type) {
202    // Should never be called since IPC wouldn't be deserialized correctly.
203    CHECK(false);
204  }
205
206  virtual bool GetSupportedMessageClasses(
207      std::vector<uint32>* supported_message_classes) const OVERRIDE {
208    if (is_global_filter_)
209      return false;
210    supported_message_classes->push_back(supported_message_class_);
211    return true;
212  }
213
214  void set_message_filtering_enabled(bool enabled) {
215    message_filtering_enabled_ = enabled;
216  }
217
218  size_t messages_received() const { return messages_received_; }
219  FilterEvent last_filter_event() const { return last_filter_event_; }
220
221 private:
222  virtual ~MessageCountFilter() {}
223
224  size_t messages_received_;
225  uint32 supported_message_class_;
226  bool is_global_filter_;
227
228  FilterEvent last_filter_event_;
229  bool message_filtering_enabled_;
230};
231
232class IPCChannelProxyTest : public IPCTestBase {
233 public:
234  IPCChannelProxyTest() {}
235  virtual ~IPCChannelProxyTest() {}
236
237  virtual void SetUp() OVERRIDE {
238    IPCTestBase::SetUp();
239
240    Init("ChannelProxyClient");
241
242    thread_.reset(new base::Thread("ChannelProxyTestServerThread"));
243    base::Thread::Options options;
244    options.message_loop_type = base::MessageLoop::TYPE_IO;
245    thread_->StartWithOptions(options);
246
247    listener_.reset(new QuitListener());
248    CreateChannelProxy(listener_.get(), thread_->message_loop_proxy().get());
249
250    ASSERT_TRUE(StartClient());
251  }
252
253  virtual void TearDown() {
254    DestroyChannelProxy();
255    thread_.reset();
256    listener_.reset();
257    IPCTestBase::TearDown();
258  }
259
260  void SendQuitMessageAndWaitForIdle() {
261    sender()->Send(new WorkerMsg_Quit);
262    base::MessageLoop::current()->Run();
263    EXPECT_TRUE(WaitForClientShutdown());
264  }
265
266  bool DidListenerGetBadMessage() {
267    return listener_->bad_message_received_;
268  }
269
270 private:
271  scoped_ptr<base::Thread> thread_;
272  scoped_ptr<QuitListener> listener_;
273};
274
275TEST_F(IPCChannelProxyTest, MessageClassFilters) {
276  // Construct a filter per message class.
277  std::vector<scoped_refptr<MessageCountFilter> > class_filters;
278  class_filters.push_back(make_scoped_refptr(
279      new MessageCountFilter(TestMsgStart)));
280  class_filters.push_back(make_scoped_refptr(
281      new MessageCountFilter(UtilityMsgStart)));
282  for (size_t i = 0; i < class_filters.size(); ++i)
283    channel_proxy()->AddFilter(class_filters[i].get());
284
285  // Send a message for each class; each filter should receive just one message.
286  sender()->Send(new TestMsg_Bounce());
287  sender()->Send(new UtilityMsg_Bounce());
288
289  // Send some messages not assigned to a specific or valid message class.
290  sender()->Send(new WorkerMsg_Bounce);
291
292  // Each filter should have received just the one sent message of the
293  // corresponding class.
294  SendQuitMessageAndWaitForIdle();
295  for (size_t i = 0; i < class_filters.size(); ++i)
296    EXPECT_EQ(1U, class_filters[i]->messages_received());
297}
298
299TEST_F(IPCChannelProxyTest, GlobalAndMessageClassFilters) {
300  // Add a class and global filter.
301  scoped_refptr<MessageCountFilter> class_filter(
302      new MessageCountFilter(TestMsgStart));
303  class_filter->set_message_filtering_enabled(false);
304  channel_proxy()->AddFilter(class_filter.get());
305
306  scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter());
307  global_filter->set_message_filtering_enabled(false);
308  channel_proxy()->AddFilter(global_filter.get());
309
310  // A message  of class Test should be seen by both the global filter and
311  // Test-specific filter.
312  sender()->Send(new TestMsg_Bounce);
313
314  // A message of a different class should be seen only by the global filter.
315  sender()->Send(new UtilityMsg_Bounce);
316
317  // Flush all messages.
318  SendQuitMessageAndWaitForIdle();
319
320  // The class filter should have received only the class-specific message.
321  EXPECT_EQ(1U, class_filter->messages_received());
322
323  // The global filter should have received both messages, as well as the final
324  // QUIT message.
325  EXPECT_EQ(3U, global_filter->messages_received());
326}
327
328TEST_F(IPCChannelProxyTest, FilterRemoval) {
329  // Add a class and global filter.
330  scoped_refptr<MessageCountFilter> class_filter(
331      new MessageCountFilter(TestMsgStart));
332  scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter());
333
334  // Add and remove both types of filters.
335  channel_proxy()->AddFilter(class_filter.get());
336  channel_proxy()->AddFilter(global_filter.get());
337  channel_proxy()->RemoveFilter(global_filter.get());
338  channel_proxy()->RemoveFilter(class_filter.get());
339
340  // Send some messages; they should not be seen by either filter.
341  sender()->Send(new TestMsg_Bounce);
342  sender()->Send(new UtilityMsg_Bounce);
343
344  // Ensure that the filters were removed and did not receive any messages.
345  SendQuitMessageAndWaitForIdle();
346  EXPECT_EQ(MessageCountFilter::FILTER_REMOVED,
347            global_filter->last_filter_event());
348  EXPECT_EQ(MessageCountFilter::FILTER_REMOVED,
349            class_filter->last_filter_event());
350  EXPECT_EQ(0U, class_filter->messages_received());
351  EXPECT_EQ(0U, global_filter->messages_received());
352}
353
354// The test that follow trigger DCHECKS in debug build.
355#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
356
357TEST_F(IPCChannelProxyTest, BadMessageOnListenerThread) {
358  scoped_refptr<MessageCountFilter> class_filter(
359      new MessageCountFilter(TestMsgStart));
360  class_filter->set_message_filtering_enabled(false);
361  channel_proxy()->AddFilter(class_filter.get());
362
363  sender()->Send(new TestMsg_SendBadMessage());
364
365  SendQuitMessageAndWaitForIdle();
366  EXPECT_TRUE(DidListenerGetBadMessage());
367}
368
369TEST_F(IPCChannelProxyTest, BadMessageOnIPCThread) {
370  scoped_refptr<MessageCountFilter> class_filter(
371      new MessageCountFilter(TestMsgStart));
372  class_filter->set_message_filtering_enabled(true);
373  channel_proxy()->AddFilter(class_filter.get());
374
375  sender()->Send(new TestMsg_SendBadMessage());
376
377  SendQuitMessageAndWaitForIdle();
378  EXPECT_TRUE(DidListenerGetBadMessage());
379}
380
381class IPCChannelBadMessageTest : public IPCTestBase {
382 public:
383  IPCChannelBadMessageTest() {}
384  virtual ~IPCChannelBadMessageTest() {}
385
386  virtual void SetUp() OVERRIDE {
387    IPCTestBase::SetUp();
388
389    Init("ChannelProxyClient");
390
391    listener_.reset(new QuitListener());
392    CreateChannel(listener_.get());
393    ASSERT_TRUE(ConnectChannel());
394
395    ASSERT_TRUE(StartClient());
396  }
397
398  virtual void TearDown() {
399    listener_.reset();
400    IPCTestBase::TearDown();
401  }
402
403  void SendQuitMessageAndWaitForIdle() {
404    sender()->Send(new WorkerMsg_Quit);
405    base::MessageLoop::current()->Run();
406    EXPECT_TRUE(WaitForClientShutdown());
407  }
408
409  bool DidListenerGetBadMessage() {
410    return listener_->bad_message_received_;
411  }
412
413 private:
414  scoped_ptr<QuitListener> listener_;
415};
416
417#if !defined(OS_WIN)
418  // TODO(jam): for some reason this is flaky on win buildbots.
419TEST_F(IPCChannelBadMessageTest, BadMessage) {
420  sender()->Send(new TestMsg_SendBadMessage());
421  SendQuitMessageAndWaitForIdle();
422  EXPECT_TRUE(DidListenerGetBadMessage());
423}
424#endif
425
426#endif
427
428MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ChannelProxyClient) {
429  base::MessageLoopForIO main_message_loop;
430  ChannelReflectorListener listener;
431  scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
432      IPCTestBase::GetChannelName("ChannelProxyClient"),
433      &listener));
434  CHECK(channel->Connect());
435  listener.Init(channel.get());
436
437  base::MessageLoop::current()->Run();
438  return 0;
439}
440
441}  // namespace
442