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 // End-to-end tests for WebSocket. Usage guidelines: | |
6 // There are at least 4 sets of end-to-end tests in the source tree: | |
7 // 1) Blink layout tests. These are easy to write, and efficient because the | |
rvargas (doing something else)
2015/01/21 00:47:04
I don't think this file (net) should be talking ab
Adam Rice
2015/01/21 09:45:56
I think the end-to-end tests need to be viewed hol
rvargas (doing something else)
2015/01/21 19:46:53
I don't agree with the conclusion. net_unittests s
Adam Rice
2015/01/22 12:06:28
I didn't find out about the PPAPI tests until I'd
| |
8 // client and server processes are both re-used. They are easy to write as | |
9 // they are just Javascript. They should be used for the majority of | |
10 // functional tests. | |
11 // 2) Browser tests in //chrome/browser/net/websocket_browsertest.cc. These | |
12 // are inefficient because both the server and client are restarted for each | |
13 // test. They are also hard to write and hard to debug. They should generally | |
14 // only be used for testing UI-related features. | |
15 // 3) PPAPI tests in //chrome/test/ppapi/ppapi_browsertest.cc. These are | |
16 // very hard to write and debug, and should only be used for verifying the | |
17 // operation of the Pepper API. | |
18 // 4) These tests. They are somewhat inefficient because the server is restarted | |
rvargas (doing something else)
2015/01/21 00:47:05
This comment makes sense by itself: when it is ok
Adam Rice
2015/01/22 12:06:28
Okay. This comment is now by itself.
| |
19 // for each test. They are well-suited for tests which require special server | |
20 // configurations. | |
21 // | |
22 // Tests should generally not be duplicated in the different places, except for | |
rvargas (doing something else)
2015/01/21 00:47:04
isn't this always true?
Adam Rice
2015/01/21 09:45:56
Yes. But you don't have to look far to find pointl
rvargas (doing something else)
2015/01/21 19:46:53
To be honest, I don't think a line saying don't du
Adam Rice
2015/01/22 12:06:28
Removed.
| |
23 // regression tests and basic smoke tests. | |
24 | |
25 #include <string> | |
26 | |
27 #include "base/bind.h" | |
28 #include "base/bind_helpers.h" | |
29 #include "base/callback.h" | |
30 #include "base/memory/scoped_ptr.h" | |
31 #include "base/message_loop/message_loop.h" | |
32 #include "base/run_loop.h" | |
33 #include "net/base/auth.h" | |
34 #include "net/base/network_delegate.h" | |
35 #include "net/base/test_data_directory.h" | |
36 #include "net/proxy/proxy_service.h" | |
37 #include "net/test/spawned_test_server/spawned_test_server.h" | |
38 #include "net/url_request/url_request_test_util.h" | |
39 #include "net/websockets/websocket_channel.h" | |
40 #include "net/websockets/websocket_event_interface.h" | |
41 #include "testing/gtest/include/gtest/gtest.h" | |
42 #include "url/origin.h" | |
43 | |
44 namespace net { | |
45 | |
46 namespace { | |
47 | |
48 static const char kEchoServer[] = "echo-with-no-extension"; | |
49 | |
50 // An implementation of WebSocketEventInterface that waits for and records the | |
51 // results of the connect. | |
52 class ConnectTestingEventInterface : public WebSocketEventInterface { | |
rvargas (doing something else)
2015/01/21 00:47:04
Nit: I think this class is slightly too long to ha
Adam Rice
2015/01/21 09:45:56
Done.
| |
53 public: | |
54 ConnectTestingEventInterface() : fail_(true) {} | |
55 | |
56 void WaitForResponse() { run_loop_.Run(); } | |
57 | |
58 // fail() is true if the handshake failed (ie. OnFailChannel was called). | |
rvargas (doing something else)
2015/01/21 00:47:04
Shouldn't it be called failed_ then? And the comme
Adam Rice
2015/01/21 09:45:55
Okay. I made just this definition online, so that
| |
59 bool fail() const { return fail_; } | |
60 | |
61 // Only set if the handshake failed, otherwise empty. | |
62 // Failure messages appear on the console and are checked by the layout tests, | |
rvargas (doing something else)
2015/01/21 00:47:04
layout tests?
Adam Rice
2015/01/21 09:45:56
Blink layout tests. I clarified the comment slight
rvargas (doing something else)
2015/01/21 19:46:53
My point is that this file should not know what a
Adam Rice
2015/01/22 12:06:28
Done.
| |
63 // so they are expected to stay reasonably stable across versions. | |
64 std::string failure_message() const { return failure_message_; } | |
65 | |
66 std::string selected_subprotocol() const { return selected_subprotocol_; } | |
67 | |
68 std::string extensions() const { return extensions_; } | |
69 | |
70 ChannelState OnAddChannelResponse(bool fail, | |
71 const std::string& selected_subprotocol, | |
72 const std::string& extensions) override { | |
73 fail_ = fail; | |
74 selected_subprotocol_ = selected_subprotocol; | |
75 extensions_ = extensions; | |
76 QuitNestedEventLoop(); | |
77 return fail ? CHANNEL_DELETED : CHANNEL_ALIVE; | |
78 } | |
79 | |
80 ChannelState OnDataFrame(bool fin, | |
81 WebSocketMessageType type, | |
82 const std::vector<char>& data) override { | |
83 return CHANNEL_ALIVE; | |
84 } | |
85 | |
86 ChannelState OnFlowControl(int64 quota) override { return CHANNEL_ALIVE; } | |
87 | |
88 ChannelState OnClosingHandshake() override { return CHANNEL_ALIVE; } | |
89 | |
90 ChannelState OnDropChannel(bool was_clean, | |
91 uint16 code, | |
92 const std::string& reason) override { | |
93 return CHANNEL_DELETED; | |
94 } | |
95 | |
96 ChannelState OnFailChannel(const std::string& message) override { | |
97 fail_ = true; | |
98 failure_message_ = message; | |
99 QuitNestedEventLoop(); | |
100 return CHANNEL_DELETED; | |
101 } | |
102 | |
103 ChannelState OnStartOpeningHandshake( | |
104 scoped_ptr<WebSocketHandshakeRequestInfo> request) override { | |
105 return CHANNEL_ALIVE; | |
106 } | |
107 | |
108 ChannelState OnFinishOpeningHandshake( | |
109 scoped_ptr<WebSocketHandshakeResponseInfo> response) override { | |
110 return CHANNEL_ALIVE; | |
111 } | |
112 | |
113 ChannelState OnSSLCertificateError( | |
114 scoped_ptr<SSLErrorCallbacks> ssl_error_callbacks, | |
115 const GURL& url, | |
116 const SSLInfo& ssl_info, | |
117 bool fatal) override { | |
118 base::MessageLoop::current()->PostTask( | |
119 FROM_HERE, base::Bind(&SSLErrorCallbacks::CancelSSLRequest, | |
120 base::Owned(ssl_error_callbacks.release()), | |
121 ERR_SSL_PROTOCOL_ERROR, &ssl_info)); | |
122 return CHANNEL_ALIVE; | |
123 } | |
124 | |
125 private: | |
126 void QuitNestedEventLoop() { run_loop_.Quit(); } | |
127 | |
128 bool fail_; | |
129 std::string selected_subprotocol_; | |
130 std::string extensions_; | |
131 std::string failure_message_; | |
132 base::RunLoop run_loop_; | |
133 | |
134 DISALLOW_COPY_AND_ASSIGN(ConnectTestingEventInterface); | |
135 }; | |
136 | |
137 // A subclass of TestNetworkDelegate that additionally implements the | |
138 // OnResolveProxy callback and records the information passed to it. | |
139 class TestNetworkDelegateWithProxyInfo : public TestNetworkDelegate { | |
140 public: | |
141 TestNetworkDelegateWithProxyInfo() {} | |
142 | |
143 struct OnResolveProxyInfo { | |
rvargas (doing something else)
2015/01/21 00:47:04
nit: Don't declare a type named OnFoo. That patter
Adam Rice
2015/01/21 09:45:55
Thanks!
| |
144 GURL url; | |
145 ProxyInfo proxy_info; | |
146 }; | |
147 | |
148 const OnResolveProxyInfo& on_resolve_proxy_info() const { | |
149 return on_resolve_proxy_info_; | |
150 } | |
151 | |
152 protected: | |
153 void OnResolveProxy(const GURL& url, | |
154 int load_flags, | |
155 const ProxyService& proxy_service, | |
156 ProxyInfo* result) override { | |
157 on_resolve_proxy_info_.url = url; | |
158 on_resolve_proxy_info_.proxy_info = *result; | |
159 } | |
160 | |
161 private: | |
162 OnResolveProxyInfo on_resolve_proxy_info_; | |
163 | |
164 DISALLOW_COPY_AND_ASSIGN(TestNetworkDelegateWithProxyInfo); | |
165 }; | |
166 | |
167 class WebSocketEndToEndTest : public ::testing::Test { | |
168 protected: | |
169 WebSocketEndToEndTest() | |
170 : event_interface_(new ConnectTestingEventInterface), | |
171 network_delegate_(new TestNetworkDelegateWithProxyInfo), | |
172 context_(true), | |
173 channel_(make_scoped_ptr(event_interface_), &context_), | |
174 initialised_context_(false) {} | |
175 | |
176 // Initialise the URLRequestContext. Normally done automatically by | |
177 // ConnectAndWait(). This method is for the use of tests that need the | |
178 // URLRequestContext initialised before calling ConnectAndWait(). | |
179 void InitialiseContext() { | |
180 context_.set_network_delegate(network_delegate_.get()); | |
181 context_.Init(); | |
182 initialised_context_ = true; | |
183 } | |
184 | |
185 // Send the connect request to |socket_url| and wait for a response. Returns | |
186 // true if the handshake succeeded. | |
187 bool ConnectAndWait(const GURL& socket_url) { | |
188 if (!initialised_context_) { | |
189 InitialiseContext(); | |
190 } | |
191 std::vector<std::string> sub_protocols; | |
192 url::Origin origin("http://localhost"); | |
193 channel_.SendAddChannelRequest(GURL(socket_url), sub_protocols, origin); | |
194 event_interface_->WaitForResponse(); | |
195 return !event_interface_->fail(); | |
196 } | |
197 | |
198 ConnectTestingEventInterface* event_interface_; // owned by channel_ | |
199 scoped_ptr<TestNetworkDelegateWithProxyInfo> network_delegate_; | |
200 TestURLRequestContext context_; | |
201 WebSocketChannel channel_; | |
202 bool initialised_context_; | |
203 }; | |
204 | |
205 // None of these tests work on Android. | |
206 // TODO(ricea): Make these tests work on Android. See crbug.com/441711. | |
207 #if defined(OS_ANDROID) | |
208 #define DISABLED_ON_ANDROID(test) DISABLED_##test | |
209 #else | |
210 #define DISABLED_ON_ANDROID(test) test | |
211 #endif | |
212 | |
213 // Basic test of connectivity. If this test fails, nothing else can be expected | |
214 // to work. | |
215 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(BasicSmokeTest)) { | |
216 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS, | |
217 SpawnedTestServer::kLocalhost, | |
218 GetWebSocketTestDataDirectory()); | |
219 ASSERT_TRUE(ws_server.Start()); | |
220 EXPECT_TRUE(ConnectAndWait(ws_server.GetURL(kEchoServer))); | |
221 } | |
222 | |
223 // Test for issue crbug.com/433695 "Unencrypted WebSocket connection via | |
224 // authenticated proxy times out" | |
225 // TODO(ricea): Enable this when the issue is fixed. | |
226 TEST_F(WebSocketEndToEndTest, DISABLED_HttpsProxyUnauthedFails) { | |
227 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, | |
228 SpawnedTestServer::kLocalhost, | |
229 base::FilePath()); | |
230 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS, | |
231 SpawnedTestServer::kLocalhost, | |
232 GetWebSocketTestDataDirectory()); | |
233 ASSERT_TRUE(proxy_server.StartInBackground()); | |
234 ASSERT_TRUE(ws_server.StartInBackground()); | |
235 ASSERT_TRUE(proxy_server.BlockUntilStarted()); | |
236 ASSERT_TRUE(ws_server.BlockUntilStarted()); | |
237 std::string proxy_config = | |
238 "https=" + proxy_server.host_port_pair().ToString(); | |
239 scoped_ptr<ProxyService> proxy_service( | |
240 ProxyService::CreateFixed(proxy_config)); | |
241 ASSERT_TRUE(proxy_service); | |
242 context_.set_proxy_service(proxy_service.get()); | |
243 EXPECT_FALSE(ConnectAndWait(ws_server.GetURL(kEchoServer))); | |
244 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message()); | |
245 } | |
246 | |
247 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HttpsWssProxyUnauthedFails)) { | |
248 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, | |
249 SpawnedTestServer::kLocalhost, | |
250 base::FilePath()); | |
251 SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, | |
252 SpawnedTestServer::kLocalhost, | |
253 GetWebSocketTestDataDirectory()); | |
254 ASSERT_TRUE(proxy_server.StartInBackground()); | |
255 ASSERT_TRUE(wss_server.StartInBackground()); | |
256 ASSERT_TRUE(proxy_server.BlockUntilStarted()); | |
257 ASSERT_TRUE(wss_server.BlockUntilStarted()); | |
258 std::string proxy_config = | |
259 "https=" + proxy_server.host_port_pair().ToString(); | |
260 scoped_ptr<ProxyService> proxy_service( | |
261 ProxyService::CreateFixed(proxy_config)); | |
262 ASSERT_TRUE(proxy_service); | |
263 context_.set_proxy_service(proxy_service.get()); | |
264 EXPECT_FALSE(ConnectAndWait(wss_server.GetURL(kEchoServer))); | |
265 EXPECT_EQ("Proxy authentication failed", event_interface_->failure_message()); | |
266 } | |
267 | |
268 // Regression test for crbug/426736 "WebSocket connections not using configured | |
269 // system HTTPS Proxy". | |
270 TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HttpsProxyUsed)) { | |
271 SpawnedTestServer proxy_server(SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, | |
272 SpawnedTestServer::kLocalhost, | |
273 base::FilePath()); | |
274 SpawnedTestServer ws_server(SpawnedTestServer::TYPE_WS, | |
275 SpawnedTestServer::kLocalhost, | |
276 GetWebSocketTestDataDirectory()); | |
277 ASSERT_TRUE(proxy_server.StartInBackground()); | |
278 ASSERT_TRUE(ws_server.StartInBackground()); | |
279 ASSERT_TRUE(proxy_server.BlockUntilStarted()); | |
280 ASSERT_TRUE(ws_server.BlockUntilStarted()); | |
281 std::string proxy_config = "https=" + | |
282 proxy_server.host_port_pair().ToString() + ";" + | |
283 "http=" + proxy_server.host_port_pair().ToString(); | |
284 scoped_ptr<ProxyService> proxy_service( | |
285 ProxyService::CreateFixed(proxy_config)); | |
286 context_.set_proxy_service(proxy_service.get()); | |
287 InitialiseContext(); | |
288 | |
289 // The test server doesn't have an unauthenticated proxy mode. WebSockets | |
290 // cannot provide auth information that isn't already cached, so it's | |
291 // necessary to preflight an HTTP request to authenticate against the proxy. | |
292 std::string scheme("http"); | |
293 GURL::Replacements replacements; | |
294 replacements.SetSchemeStr(scheme); | |
295 // It doesn't matter what the URL is, as long as it is an HTTP navigation. | |
296 GURL http_page = | |
297 ws_server.GetURL("connect_check.html").ReplaceComponents(replacements); | |
298 TestDelegate delegate; | |
299 delegate.set_credentials( | |
300 AuthCredentials(base::ASCIIToUTF16("foo"), base::ASCIIToUTF16("bar"))); | |
301 { | |
302 scoped_ptr<URLRequest> request( | |
303 context_.CreateRequest(http_page, DEFAULT_PRIORITY, &delegate, NULL)); | |
304 request->Start(); | |
305 // TestDelegate exits the message loop when the request completes by | |
306 // default. | |
307 base::RunLoop().Run(); | |
308 EXPECT_TRUE(delegate.auth_required_called()); | |
309 } | |
310 | |
311 GURL ws_url = ws_server.GetURL(kEchoServer); | |
312 EXPECT_TRUE(ConnectAndWait(ws_url)); | |
313 const TestNetworkDelegateWithProxyInfo::OnResolveProxyInfo& info = | |
314 network_delegate_->on_resolve_proxy_info(); | |
315 EXPECT_EQ(ws_url, info.url); | |
316 EXPECT_TRUE(info.proxy_info.is_http()); | |
317 } | |
318 | |
319 } // namespace | |
320 | |
321 } // namespace net | |
OLD | NEW |