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.
5 #include "build/build_config.h"
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"
16 #if defined(IPC_MESSAGE_START)
17 #undef IPC_MESSAGE_START
25 static void Send(IPC::Sender
* sender
,
28 const int IPC_MESSAGE_START
= message_class
;
29 IPC::Message
* message
= new IPC::Message(0,
31 IPC::Message::PRIORITY_NORMAL
);
32 message
->WriteInt(command
);
33 sender
->Send(message
);
36 class QuitListener
: public IPC::Listener
{
39 virtual ~QuitListener() {}
41 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
42 PickleIterator
iter(message
);
45 EXPECT_TRUE(iter
.ReadInt(&command
));
47 base::MessageLoop::current()->QuitWhenIdle();
53 class ChannelReflectorListener
: public IPC::Listener
{
55 ChannelReflectorListener() : channel_(NULL
) {}
56 virtual ~ChannelReflectorListener() {}
58 void Init(IPC::Channel
* channel
) {
63 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
66 PickleIterator
iter(message
);
69 EXPECT_TRUE(iter
.ReadInt(&command
));
70 if (command
== QUIT
) {
71 channel_
->Send(new IPC::Message(message
));
72 base::MessageLoop::current()->QuitWhenIdle();
76 channel_
->Send(new IPC::Message(message
));
81 IPC::Channel
* channel_
;
84 class MessageCountFilter
: public IPC::ChannelProxy::MessageFilter
{
87 : messages_received_(0),
88 supported_message_class_(0),
89 is_global_filter_(true),
90 filter_removed_(false),
91 message_filtering_enabled_(false) {}
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) {}
100 virtual void OnFilterRemoved() OVERRIDE
{
101 EXPECT_FALSE(filter_removed_
);
102 filter_removed_
= true;
105 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
106 if (!is_global_filter_
) {
107 EXPECT_EQ(supported_message_class_
, IPC_MESSAGE_CLASS(message
));
109 ++messages_received_
;
110 return message_filtering_enabled_
;
113 virtual bool GetSupportedMessageClasses(
114 std::vector
<uint32
>* supported_message_classes
) const OVERRIDE
{
115 if (is_global_filter_
)
117 supported_message_classes
->push_back(supported_message_class_
);
121 void set_message_filtering_enabled(bool enabled
) {
122 message_filtering_enabled_
= enabled
;
125 size_t messages_received() const { return messages_received_
; }
126 bool filter_removed() const { return filter_removed_
; }
129 virtual ~MessageCountFilter() {}
131 size_t messages_received_
;
132 uint32 supported_message_class_
;
133 bool is_global_filter_
;
134 bool filter_removed_
;
135 bool message_filtering_enabled_
;
138 class IPCChannelProxyTest
: public IPCTestBase
{
140 IPCChannelProxyTest() {}
141 virtual ~IPCChannelProxyTest() {}
143 virtual void SetUp() OVERRIDE
{
144 IPCTestBase::SetUp();
146 Init("ChannelProxyClient");
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
);
153 listener_
.reset(new QuitListener());
154 CreateChannelProxy(listener_
.get(), thread_
->message_loop_proxy().get());
156 ASSERT_TRUE(StartClient());
159 virtual void TearDown() {
160 DestroyChannelProxy();
163 IPCTestBase::TearDown();
166 void SendQuitMessageAndWaitForIdle() {
167 Send(sender(), -1, QUIT
);
168 base::MessageLoop::current()->Run();
169 EXPECT_TRUE(WaitForClientShutdown());
173 scoped_ptr
<base::Thread
> thread_
;
174 scoped_ptr
<QuitListener
> listener_
;
177 TEST_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());
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
);
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
);
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());
202 TEST_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());
210 scoped_refptr
<MessageCountFilter
> global_filter(new MessageCountFilter());
211 global_filter
->set_message_filtering_enabled(false);
212 channel_proxy()->AddFilter(global_filter
.get());
214 // A message of class |kMessageClass| should be seen by both the global
215 // filter and |kMessageClass|-specific filter.
216 Send(sender(), kMessageClass
, SEND
);
218 // A message of a different class should be seen only by the global filter.
219 Send(sender(), kMessageClass
+ 1, SEND
);
221 // Flush all messages.
222 SendQuitMessageAndWaitForIdle();
224 // The class filter should have received only the class-specific message.
225 EXPECT_EQ(1U, class_filter
->messages_received());
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());
232 TEST_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());
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());
245 // Send some messages; they should not be seen by either filter.
246 Send(sender(), 0, SEND
);
247 Send(sender(), kMessageClass
, SEND
);
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());
257 MULTIPROCESS_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
,
263 CHECK(channel
.Connect());
264 listener
.Init(&channel
);
266 base::MessageLoop::current()->Run();