OLD | NEW |
| (Empty) |
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 | |
14 namespace { | |
15 | |
16 #if defined(IPC_MESSAGE_START) | |
17 #undef IPC_MESSAGE_START | |
18 #endif | |
19 | |
20 enum Command { | |
21 SEND, | |
22 QUIT | |
23 }; | |
24 | |
25 static 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 | |
36 class 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 | |
53 class 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 | |
84 class 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 | |
138 class 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 | |
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()); | |
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 | |
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()); | |
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 | |
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()); | |
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 | |
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, | |
262 &listener); | |
263 CHECK(channel.Connect()); | |
264 listener.Init(&channel); | |
265 | |
266 base::MessageLoop::current()->Run(); | |
267 return 0; | |
268 } | |
269 | |
270 } // namespace | |
OLD | NEW |