Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(835)

Side by Side Diff: net/websockets/websocket_end_to_end_test.cc

Issue 722343003: Add end to end tests for WebSockets in net/websockets/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use NetworkDelegate::OnResolveProxy to check proxy usage. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/net.gypi ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
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
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
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 {
53 public:
54 ConnectTestingEventInterface() : fail_(true) {}
55
56 void WaitForResponse() { run_loop_.Run(); }
57
58 // fail() is true if the handshake failed.
tyoshino (SeeGerritForStatus) 2015/01/19 03:59:48 also if FailChannel was called
Adam Rice 2015/01/19 04:50:14 Actually, it always means FailChannel was called.
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,
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 {
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
OLDNEW
« no previous file with comments | « net/net.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698