OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 virtual void QuitAndWaitForIdle() { | |
167 Send(sender(), -1, QUIT); | |
168 base::MessageLoop::current()->Run(); | |
169 thread_->message_loop()->RunUntilIdle(); | |
piman
2014/02/14 22:05:05
I don't think this does what you want it to do.
If
jdduke (slow)
2014/02/15 02:57:09
Done.
| |
170 EXPECT_TRUE(WaitForClientShutdown()); | |
171 } | |
172 | |
173 private: | |
174 scoped_ptr<base::Thread> thread_; | |
175 scoped_ptr<QuitListener> listener_; | |
176 }; | |
177 | |
178 TEST_F(IPCChannelProxyTest, MessageClassFilters) { | |
179 // Construct a filter per message class. | |
180 std::vector<scoped_refptr<MessageCountFilter> > class_filters; | |
181 for (size_t i = 0; i < LastIPCMsgStart; ++i) { | |
182 class_filters.push_back(make_scoped_refptr( | |
183 new MessageCountFilter(i))); | |
184 channel_proxy()->AddFilter(class_filters.back().get()); | |
185 } | |
186 | |
187 // Send a message for each class; each filter should receive just one message. | |
188 for (size_t i = 0; i < class_filters.size(); ++i) | |
189 Send(sender(), i, SEND); | |
190 | |
191 // Send a message with an invalid class; this should not reach any filter. | |
192 Send(sender(), -1, SEND); | |
piman
2014/02/14 22:05:05
nit: -1 is special (for replies, etc.). You may wa
jdduke (slow)
2014/02/15 02:57:09
Done.
| |
193 | |
194 // All messages should have been received by their respective filter. | |
195 QuitAndWaitForIdle(); | |
196 for (size_t i = 0; i < class_filters.size(); ++i) | |
197 EXPECT_EQ(1U, class_filters[i]->messages_received()); | |
198 } | |
199 | |
200 TEST_F(IPCChannelProxyTest, GlobalAndMessageClassFilters) { | |
201 // Add a class and global filter. | |
202 const int kMessageClass = 7; | |
203 scoped_refptr<MessageCountFilter> class_filter( | |
204 new MessageCountFilter(kMessageClass)); | |
205 class_filter->set_message_filtering_enabled(false); | |
206 channel_proxy()->AddFilter(class_filter.get()); | |
207 | |
208 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); | |
209 global_filter->set_message_filtering_enabled(false); | |
210 channel_proxy()->AddFilter(global_filter.get()); | |
211 | |
212 // A message of class |kMessageClass| should be seen by both the global | |
213 // filter and |kMessageClass|-specific filter. | |
214 Send(sender(), kMessageClass, SEND); | |
215 | |
216 // A message of a different class should be seen only by the global filter. | |
217 Send(sender(), kMessageClass + 1, SEND); | |
218 | |
219 // Flush all messages. | |
220 QuitAndWaitForIdle(); | |
221 | |
222 // The class filter should have received only the class-specific message. | |
223 EXPECT_EQ(1U, class_filter->messages_received()); | |
224 | |
225 // The global filter should have received both SEND messages, as well as the | |
226 // final QUIT message. | |
227 EXPECT_EQ(3U, global_filter->messages_received()); | |
228 } | |
229 | |
230 TEST_F(IPCChannelProxyTest, FilterRemoval) { | |
231 // Add a class and global filter. | |
232 const int kMessageClass = 7; | |
233 scoped_refptr<MessageCountFilter> class_filter( | |
234 new MessageCountFilter(kMessageClass)); | |
235 scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter()); | |
236 | |
237 // Add and remove both types of filters. | |
238 channel_proxy()->AddFilter(class_filter.get()); | |
239 channel_proxy()->AddFilter(global_filter.get()); | |
240 channel_proxy()->RemoveFilter(global_filter.get()); | |
241 channel_proxy()->RemoveFilter(class_filter.get()); | |
242 | |
243 // Send some messages; they should not be seen by either filter. | |
244 Send(sender(), kMessageClass, SEND); | |
245 Send(sender(), kMessageClass, SEND); | |
246 | |
247 // Ensure that the filters were removed and did not receive any messages. | |
248 QuitAndWaitForIdle(); | |
249 EXPECT_TRUE(global_filter->filter_removed()); | |
250 EXPECT_TRUE(class_filter->filter_removed()); | |
251 EXPECT_EQ(0U, class_filter->messages_received()); | |
252 EXPECT_EQ(0U, global_filter->messages_received()); | |
253 } | |
254 | |
255 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ChannelProxyClient) { | |
256 base::MessageLoopForIO main_message_loop; | |
257 ChannelReflectorListener listener; | |
258 IPC::Channel channel(IPCTestBase::GetChannelName("ChannelProxyClient"), | |
259 IPC::Channel::MODE_CLIENT, | |
260 &listener); | |
261 CHECK(channel.Connect()); | |
262 listener.Init(&channel); | |
263 | |
264 base::MessageLoop::current()->Run(); | |
265 return 0; | |
266 } | |
267 | |
268 } // namespace | |
OLD | NEW |