OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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 <algorithm> | |
6 #include <memory> | |
7 #include <vector> | |
8 | |
9 #include "content/browser/websockets/websocket_manager.h" | |
10 #include "content/public/test/test_browser_thread_bundle.h" | |
11 #include "testing/gtest/include/gtest/gtest.h" | |
12 #include "url/gurl.h" | |
13 #include "url/origin.h" | |
14 | |
15 namespace content { | |
16 namespace { | |
17 | |
18 // This number is unlikely to occur by chance. | |
19 static const int kMagicRenderProcessId = 506116062; | |
20 | |
21 class TestWebSocketImpl : public WebSocketImpl { | |
22 public: | |
23 TestWebSocketImpl(Delegate* delegate, | |
24 mojom::WebSocketRequest request, | |
25 base::TimeDelta delay) | |
26 : WebSocketImpl(delegate, std::move(request), delay) {} | |
27 | |
28 base::TimeDelta delay() const { return delay_; } | |
29 | |
30 void SimulateConnectionError() { | |
31 OnConnectionError(); | |
32 } | |
33 }; | |
34 | |
35 class TestWebSocketManager : public WebSocketManager { | |
36 public: | |
37 TestWebSocketManager() | |
38 : WebSocketManager(kMagicRenderProcessId, nullptr) {} | |
39 | |
40 const std::vector<TestWebSocketImpl*>& sockets() const { | |
41 return sockets_; | |
42 } | |
43 | |
44 int num_pending_connections() const { | |
45 return num_pending_connections_; | |
46 } | |
47 int64_t num_failed_connections() const { | |
48 return num_current_failed_connections_ + num_previous_failed_connections_; | |
49 } | |
50 int64_t num_succeeded_connections() const { | |
51 return num_current_succeeded_connections_ + | |
52 num_previous_succeeded_connections_; | |
53 } | |
54 | |
55 void DoCreateWebSocket(mojom::WebSocketRequest request) { | |
56 WebSocketManager::DoCreateWebSocket(std::move(request)); | |
57 } | |
58 | |
59 private: | |
60 WebSocketImpl* CreateWebSocketImpl(WebSocketImpl::Delegate* delegate, | |
61 mojom::WebSocketRequest request, | |
62 base::TimeDelta delay) override { | |
63 TestWebSocketImpl* impl = | |
64 new TestWebSocketImpl(delegate, std::move(request), delay); | |
65 // We keep a vector of sockets here to track their creation order. | |
66 sockets_.push_back(impl); | |
67 return impl; | |
68 } | |
69 | |
70 void OnLostConnectionToClient(WebSocketImpl* impl) override { | |
71 auto it = std::find(sockets_.begin(), sockets_.end(), | |
72 static_cast<TestWebSocketImpl*>(impl)); | |
73 ASSERT_TRUE(it != sockets_.end()); | |
74 sockets_.erase(it); | |
75 | |
76 WebSocketManager::OnLostConnectionToClient(impl); | |
77 } | |
78 | |
79 std::vector<TestWebSocketImpl*> sockets_; | |
80 }; | |
81 | |
82 class WebSocketManagerTest : public ::testing::Test { | |
83 public: | |
84 WebSocketManagerTest() | |
85 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) { | |
86 websocket_manager_.reset(new TestWebSocketManager()); | |
87 } | |
88 | |
89 void AddMultipleChannels(int number_of_channels) { | |
90 for (int i = 0; i < number_of_channels; ++i) { | |
91 mojom::WebSocketPtr websocket; | |
92 websocket_manager_->DoCreateWebSocket(mojo::GetProxy(&websocket)); | |
93 } | |
94 } | |
95 | |
96 void AddAndCancelMultipleChannels(int number_of_channels) { | |
97 for (int i = 0; i < number_of_channels; ++i) { | |
98 mojom::WebSocketPtr websocket; | |
99 websocket_manager_->DoCreateWebSocket(mojo::GetProxy(&websocket)); | |
100 websocket_manager_->sockets().back()->SimulateConnectionError(); | |
101 } | |
102 } | |
103 | |
104 TestWebSocketManager* websocket_manager() { return websocket_manager_.get(); } | |
105 | |
106 private: | |
107 TestBrowserThreadBundle thread_bundle_; | |
108 std::unique_ptr<TestWebSocketManager> websocket_manager_; | |
109 }; | |
110 | |
111 TEST_F(WebSocketManagerTest, Construct) { | |
112 // Do nothing. | |
113 } | |
114 | |
115 #if 0 | |
Adam Rice
2016/07/27 02:38:54
Please delete all the #if 0s before checking in.
| |
116 TEST_F(WebSocketDispatcherHostTest, UnrelatedMessage) { | |
117 IPC::Message message; | |
118 EXPECT_FALSE(dispatcher_host_->OnMessageReceived(message)); | |
119 } | |
120 | |
121 TEST_F(WebSocketDispatcherHostTest, RenderProcessIdGetter) { | |
122 EXPECT_EQ(kMagicRenderProcessId, dispatcher_host_->render_process_id()); | |
123 } | |
124 #endif | |
125 | |
126 TEST_F(WebSocketManagerTest, CreateWebSocket) { | |
127 mojom::WebSocketPtr websocket; | |
128 | |
129 websocket_manager()->DoCreateWebSocket(mojo::GetProxy(&websocket)); | |
130 | |
131 EXPECT_EQ(1U, websocket_manager()->sockets().size()); | |
132 } | |
133 | |
134 #if 0 | |
135 TEST_F(WebSocketDispatcherHostTest, AddChannelRequest) { | |
136 int routing_id = 123; | |
137 GURL socket_url("ws://example.com/test"); | |
138 std::vector<std::string> requested_protocols; | |
139 requested_protocols.push_back("hello"); | |
140 url::Origin origin(GURL("http://example.com")); | |
141 WebSocketHostMsg_AddChannelRequest message( | |
142 routing_id, socket_url, requested_protocols, origin, ""); | |
143 | |
144 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message)); | |
145 | |
146 ASSERT_EQ(1U, mock_hosts_.size()); | |
147 MockWebSocketHost* host = mock_hosts_[0]; | |
148 | |
149 ASSERT_EQ(1U, host->received_messages_.size()); | |
150 const IPC::Message& forwarded_message = host->received_messages_[0]; | |
151 EXPECT_EQ(WebSocketHostMsg_AddChannelRequest::ID, forwarded_message.type()); | |
152 EXPECT_EQ(routing_id, forwarded_message.routing_id()); | |
153 } | |
154 #endif | |
155 | |
156 TEST_F(WebSocketManagerTest, SendFrameButNotConnectedYet) { | |
157 mojom::WebSocketPtr websocket; | |
158 | |
159 websocket_manager()->DoCreateWebSocket(mojo::GetProxy(&websocket)); | |
160 | |
161 // This should not crash. | |
162 mojo::Array<uint8_t> data; | |
163 websocket->SendFrame( | |
164 true, mojom::WebSocketMessageType::TEXT, std::move(data)); | |
165 } | |
166 | |
167 #if 0 | |
168 TEST_F(WebSocketDispatcherHostTest, SendFrameButNoHostYet) { | |
169 int routing_id = 123; | |
170 std::vector<char> data; | |
171 WebSocketMsg_SendFrame message( | |
172 routing_id, true, WEB_SOCKET_MESSAGE_TYPE_TEXT, data); | |
173 | |
174 // Expected to be ignored. | |
175 EXPECT_TRUE(dispatcher_host_->OnMessageReceived(message)); | |
176 | |
177 EXPECT_EQ(0U, mock_hosts_.size()); | |
178 } | |
179 #endif | |
180 | |
181 #if 0 | |
182 TEST_F(WebSocketDispatcherHostTest, SendFrame) { | |
183 int routing_id = 123; | |
184 | |
185 GURL socket_url("ws://example.com/test"); | |
186 std::vector<std::string> requested_protocols; | |
187 requested_protocols.push_back("hello"); | |
188 url::Origin origin(GURL("http://example.com")); | |
189 int render_frame_id = -2; | |
190 WebSocketHostMsg_AddChannelRequest add_channel_message( | |
191 routing_id, socket_url, requested_protocols, origin, "", render_frame_id); | |
192 | |
193 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(add_channel_message)); | |
194 | |
195 std::vector<char> data; | |
196 WebSocketMsg_SendFrame send_frame_message( | |
197 routing_id, true, WEB_SOCKET_MESSAGE_TYPE_TEXT, data); | |
198 | |
199 EXPECT_TRUE(dispatcher_host_->OnMessageReceived(send_frame_message)); | |
200 | |
201 ASSERT_EQ(1U, mock_hosts_.size()); | |
202 MockWebSocketHost* host = mock_hosts_[0]; | |
203 | |
204 ASSERT_EQ(2U, host->received_messages_.size()); | |
205 { | |
206 const IPC::Message& forwarded_message = host->received_messages_[0]; | |
207 EXPECT_EQ(WebSocketHostMsg_AddChannelRequest::ID, forwarded_message.type()); | |
208 EXPECT_EQ(routing_id, forwarded_message.routing_id()); | |
209 } | |
210 { | |
211 const IPC::Message& forwarded_message = host->received_messages_[1]; | |
212 EXPECT_EQ(WebSocketMsg_SendFrame::ID, forwarded_message.type()); | |
213 EXPECT_EQ(routing_id, forwarded_message.routing_id()); | |
214 } | |
215 } | |
216 | |
217 TEST_F(WebSocketDispatcherHostTest, Destruct) { | |
218 WebSocketHostMsg_AddChannelRequest message1( | |
219 123, GURL("ws://example.com/test"), std::vector<std::string>(), | |
220 url::Origin(GURL("http://example.com")), "", -1); | |
221 WebSocketHostMsg_AddChannelRequest message2( | |
222 456, GURL("ws://example.com/test2"), std::vector<std::string>(), | |
223 url::Origin(GURL("http://example.com")), "", -1); | |
224 | |
225 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message1)); | |
226 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message2)); | |
227 | |
228 ASSERT_EQ(2u, mock_hosts_.size()); | |
229 | |
230 mock_hosts_.clear(); | |
231 dispatcher_host_ = NULL; | |
232 | |
233 ASSERT_EQ(2u, gone_hosts_.size()); | |
234 // The gone_hosts_ ordering is not predictable because it depends on the | |
235 // hash_map ordering. | |
236 std::sort(gone_hosts_.begin(), gone_hosts_.end()); | |
237 EXPECT_EQ(123, gone_hosts_[0]); | |
238 EXPECT_EQ(456, gone_hosts_[1]); | |
239 } | |
240 #endif | |
241 | |
242 TEST_F(WebSocketManagerTest, DelayFor4thPendingConnectionIsZero) { | |
243 AddMultipleChannels(4); | |
244 | |
245 EXPECT_EQ(4, websocket_manager()->num_pending_connections()); | |
246 EXPECT_EQ(0, websocket_manager()->num_failed_connections()); | |
247 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
248 | |
249 ASSERT_EQ(4U, websocket_manager()->sockets().size()); | |
250 EXPECT_EQ(base::TimeDelta(), websocket_manager()->sockets()[3]->delay()); | |
251 } | |
252 | |
253 TEST_F(WebSocketManagerTest, DelayFor8thPendingConnectionIsNonZero) { | |
254 AddMultipleChannels(8); | |
255 | |
256 EXPECT_EQ(8, websocket_manager()->num_pending_connections()); | |
257 EXPECT_EQ(0, websocket_manager()->num_failed_connections()); | |
258 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
259 | |
260 ASSERT_EQ(8U, websocket_manager()->sockets().size()); | |
261 EXPECT_LT(base::TimeDelta(), websocket_manager()->sockets()[7]->delay()); | |
262 } | |
263 | |
264 TEST_F(WebSocketManagerTest, DelayFor17thPendingConnection) { | |
265 AddMultipleChannels(17); | |
266 | |
267 EXPECT_EQ(17, websocket_manager()->num_pending_connections()); | |
268 EXPECT_EQ(0, websocket_manager()->num_failed_connections()); | |
269 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
270 | |
271 ASSERT_EQ(17U, websocket_manager()->sockets().size()); | |
272 EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), | |
273 websocket_manager()->sockets()[16]->delay()); | |
274 EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), | |
275 websocket_manager()->sockets()[16]->delay()); | |
276 } | |
277 | |
278 // The 256th connection is rejected by per-renderer WebSocket throttling. | |
279 // This is not counted as a failure. | |
280 TEST_F(WebSocketManagerTest, Rejects256thPendingConnection) { | |
281 AddMultipleChannels(256); | |
282 | |
283 EXPECT_EQ(255, websocket_manager()->num_pending_connections()); | |
284 EXPECT_EQ(0, websocket_manager()->num_failed_connections()); | |
285 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
286 | |
287 ASSERT_EQ(255U, websocket_manager()->sockets().size()); | |
288 } | |
289 | |
290 TEST_F(WebSocketManagerTest, DelayIsZeroAfter3FailedConnections) { | |
291 AddAndCancelMultipleChannels(3); | |
292 | |
293 EXPECT_EQ(0, websocket_manager()->num_pending_connections()); | |
294 EXPECT_EQ(3, websocket_manager()->num_failed_connections()); | |
295 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
296 | |
297 AddMultipleChannels(1); | |
298 | |
299 ASSERT_EQ(1U, websocket_manager()->sockets().size()); | |
300 EXPECT_EQ(base::TimeDelta(), websocket_manager()->sockets()[0]->delay()); | |
301 } | |
302 | |
303 TEST_F(WebSocketManagerTest, DelayIsNonZeroAfter7FailedConnections) { | |
304 AddAndCancelMultipleChannels(7); | |
305 | |
306 EXPECT_EQ(0, websocket_manager()->num_pending_connections()); | |
307 EXPECT_EQ(7, websocket_manager()->num_failed_connections()); | |
308 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
309 | |
310 AddMultipleChannels(1); | |
311 | |
312 ASSERT_EQ(1U, websocket_manager()->sockets().size()); | |
313 EXPECT_LT(base::TimeDelta(), websocket_manager()->sockets()[0]->delay()); | |
314 } | |
315 | |
316 TEST_F(WebSocketManagerTest, DelayAfter16FailedConnections) { | |
317 AddAndCancelMultipleChannels(16); | |
318 | |
319 EXPECT_EQ(0, websocket_manager()->num_pending_connections()); | |
320 EXPECT_EQ(16, websocket_manager()->num_failed_connections()); | |
321 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
322 | |
323 AddMultipleChannels(1); | |
324 | |
325 ASSERT_EQ(1U, websocket_manager()->sockets().size()); | |
326 EXPECT_LE(base::TimeDelta::FromMilliseconds(1000), | |
327 websocket_manager()->sockets()[0]->delay()); | |
328 EXPECT_GE(base::TimeDelta::FromMilliseconds(5000), | |
329 websocket_manager()->sockets()[0]->delay()); | |
330 } | |
331 | |
332 TEST_F(WebSocketManagerTest, NotRejectedAfter255FailedConnections) { | |
333 AddAndCancelMultipleChannels(255); | |
334 | |
335 EXPECT_EQ(0, websocket_manager()->num_pending_connections()); | |
336 EXPECT_EQ(255, websocket_manager()->num_failed_connections()); | |
337 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
338 | |
339 AddMultipleChannels(1); | |
340 | |
341 EXPECT_EQ(1, websocket_manager()->num_pending_connections()); | |
342 EXPECT_EQ(255, websocket_manager()->num_failed_connections()); | |
343 EXPECT_EQ(0, websocket_manager()->num_succeeded_connections()); | |
344 } | |
345 | |
346 #if 0 | |
347 // This is a regression test for https://crrev.com/998173003/. | |
348 TEST_F(WebSocketDispatcherHostTest, InvalidScheme) { | |
349 int routing_id = 123; | |
350 GURL socket_url("http://example.com/test"); | |
351 std::vector<std::string> requested_protocols; | |
352 requested_protocols.push_back("hello"); | |
353 url::Origin origin(GURL("http://example.com")); | |
354 int render_frame_id = -2; | |
355 WebSocketHostMsg_AddChannelRequest message( | |
356 routing_id, socket_url, requested_protocols, origin, "", render_frame_id); | |
357 | |
358 ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message)); | |
359 | |
360 ASSERT_EQ(1U, mock_hosts_.size()); | |
361 MockWebSocketHost* host = mock_hosts_[0]; | |
362 | |
363 // Tests that WebSocketHost::OnMessageReceived() doesn't cause a crash and | |
364 // the connection with an invalid scheme fails here. | |
365 // We call WebSocketHost::OnMessageReceived() here explicitly because | |
366 // MockWebSocketHost does not call WebSocketHost::OnMessageReceived() for | |
367 // WebSocketHostMsg_AddChannelRequest. | |
368 host->WebSocketHost::OnMessageReceived(message); | |
369 | |
370 EXPECT_EQ(0, dispatcher_host_->num_pending_connections()); | |
371 EXPECT_EQ(1, dispatcher_host_->num_failed_connections()); | |
372 EXPECT_EQ(0, dispatcher_host_->num_succeeded_connections()); | |
373 } | |
374 #endif | |
375 | |
376 } // namespace | |
377 } // namespace content | |
OLD | NEW |