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

Side by Side Diff: chrome/browser/net/predictor_browsertest.cc

Issue 1881463003: Add a browsertest suite for net predictor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactor, disable preconnect + intercept request for determinism Created 4 years, 7 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 | « chrome/browser/net/predictor.cc ('k') | chrome/test/data/predictor/empty.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include "base/base64.h" 8 #include "base/base64.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/json/json_string_value_serializer.h" 10 #include "base/json/json_string_value_serializer.h"
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/memory/ptr_util.h"
12 #include "base/synchronization/lock.h" 13 #include "base/synchronization/lock.h"
13 #include "base/thread_task_runner_handle.h" 14 #include "base/thread_task_runner_handle.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/net/predictor.h" 17 #include "chrome/browser/net/predictor.h"
17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/pref_names.h" 21 #include "chrome/common/pref_names.h"
20 #include "chrome/test/base/in_process_browser_test.h" 22 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h" 23 #include "chrome/test/base/ui_test_utils.h"
22 #include "components/prefs/pref_service.h" 24 #include "components/prefs/pref_service.h"
23 #include "content/public/common/content_switches.h" 25 #include "content/public/common/content_switches.h"
26 #include "content/public/test/browser_test_utils.h"
24 #include "content/public/test/test_utils.h" 27 #include "content/public/test/test_utils.h"
25 #include "net/base/host_port_pair.h" 28 #include "net/base/host_port_pair.h"
26 #include "net/base/ip_endpoint.h" 29 #include "net/base/ip_endpoint.h"
27 #include "net/base/net_errors.h" 30 #include "net/base/net_errors.h"
28 #include "net/dns/host_resolver_proc.h" 31 #include "net/dns/host_resolver_proc.h"
29 #include "net/dns/mock_host_resolver.h" 32 #include "net/dns/mock_host_resolver.h"
30 #include "net/socket/stream_socket.h" 33 #include "net/socket/stream_socket.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h" 34 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h" 35 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h"
36 #include "net/test/embedded_test_server/http_request.h"
37 #include "net/test/embedded_test_server/http_response.h"
38 #include "net/test/url_request/url_request_failed_job.h"
39 #include "net/url_request/url_request_filter.h"
40 #include "net/url_request/url_request_interceptor.h"
41 #include "net/url_request/url_request_test_job.h"
33 #include "testing/gmock/include/gmock/gmock.h" 42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "url/gurl.h"
34 44
35 using content::BrowserThread; 45 using content::BrowserThread;
36 using testing::HasSubstr; 46 using testing::HasSubstr;
37 47
38 namespace { 48 namespace {
39 49
50 net::URLRequestJob* EmptyRequestJob(net::URLRequest* request,
mmenke 2016/05/06 19:54:01 CreateEmptyBodyRequestJob? The method itself isn'
Charlie Harrison 2016/05/09 19:47:05 Done.
51 net::NetworkDelegate* delegate) {
52 const char kPlainTextHeaders[] =
53 "HTTP/1.1 200 OK\n"
54 "Content-Type: text/plain\n"
55 "Access-Control-Allow-Origin: *\n"
56 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\n"
mmenke 2016/05/06 19:54:01 I don't think we need the expires header?
Charlie Harrison 2016/05/09 19:47:04 Done.
57 "\n";
58 return new net::URLRequestTestJob(
59 request, delegate,
60 std::string(kPlainTextHeaders, arraysize(kPlainTextHeaders)), "", true);
mmenke 2016/05/06 19:54:00 std::string(kPlainTextHeaders, arraysize(kPlainTex
Charlie Harrison 2016/05/09 19:47:04 Done.
61 }
62
63 net::URLRequestJob* NotFoundRequestJob(net::URLRequest* request,
mmenke 2016/05/06 19:54:01 CreateFailingRequestJob? (It's not a 404 response
Charlie Harrison 2016/05/09 19:47:03 Done.
64 net::NetworkDelegate* delegate) {
65 return new net::URLRequestFailedJob(request, delegate, net::ERR_ABORTED);
mmenke 2016/05/06 19:54:01 ERR_ABORTED is a magical error code, that net shou
Charlie Harrison 2016/05/09 19:47:04 Done.
66 }
67
40 const char kBlinkPreconnectFeature[] = "LinkPreconnect"; 68 const char kBlinkPreconnectFeature[] = "LinkPreconnect";
41 const char kChromiumHostname[] = "chromium.org"; 69 const char kChromiumHostname[] = "chromium.org";
42 const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-" 70 const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-"
43 "characters-should-not-send-an-ipc-message-to-the-browser-" 71 "characters-should-not-send-an-ipc-message-to-the-browser-"
44 "0000000000000000000000000000000000000000000000000000000000000000000000000" 72 "0000000000000000000000000000000000000000000000000000000000000000000000000"
45 "0000000000000000000000000000000000000000000000000000000000000000000000000" 73 "0000000000000000000000000000000000000000000000000000000000000000000000000"
46 "000000000000000000000000000000000000000000000000000000.org"; 74 "000000000000000000000000000000000000000000000000000000.org";
47 75
48 // Gets notified by the EmbeddedTestServer on incoming connections being 76 // Gets notified by the EmbeddedTestServer on incoming connections being
49 // accepted or read from, keeps track of them and exposes that info to 77 // accepted or read from, keeps track of them and exposes that info to
50 // the tests. 78 // the tests.
51 // A port being reused is currently considered an error. If a test 79 // A port being reused is currently considered an error. If a test
52 // needs to verify multiple connections are opened in sequence, that will need 80 // needs to verify multiple connections are opened in sequence, that will need
53 // to be changed. 81 // to be changed.
54 class ConnectionListener 82 class ConnectionListener
55 : public net::test_server::EmbeddedTestServerConnectionListener { 83 : public net::test_server::EmbeddedTestServerConnectionListener {
56 public: 84 public:
57 ConnectionListener() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} 85 ConnectionListener()
86 : accept_n_(0),
87 accept_n_loop_(nullptr),
88 task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
58 89
59 ~ConnectionListener() override {} 90 ~ConnectionListener() override {}
60 91
61 // Get called from the EmbeddedTestServer thread to be notified that 92 // Get called from the EmbeddedTestServer thread to be notified that
62 // a connection was accepted. 93 // a connection was accepted.
63 void AcceptedSocket(const net::StreamSocket& connection) override { 94 void AcceptedSocket(const net::StreamSocket& connection) override {
64 base::AutoLock lock(lock_); 95 base::AutoLock lock(lock_);
65 uint16_t socket = GetPort(connection); 96 uint16_t socket = GetPort(connection);
66 EXPECT_TRUE(sockets_.find(socket) == sockets_.end()); 97 EXPECT_TRUE(sockets_.find(socket) == sockets_.end());
67 98
68 sockets_[socket] = SOCKET_ACCEPTED; 99 sockets_[socket] = SOCKET_ACCEPTED;
69 task_runner_->PostTask(FROM_HERE, accept_loop_.QuitClosure()); 100 task_runner_->PostTask(FROM_HERE, accept_loop_.QuitClosure());
101 CheckAccepted();
70 } 102 }
71 103
72 // Get called from the EmbeddedTestServer thread to be notified that 104 // Get called from the EmbeddedTestServer thread to be notified that
73 // a connection was read from. 105 // a connection was read from.
74 void ReadFromSocket(const net::StreamSocket& connection) override { 106 void ReadFromSocket(const net::StreamSocket& connection, int rv) override {
107 // Don't log a read if no data was transferred. This case often happens if
108 // the sockets of the test server are being flushed and disconnected.
109 if (rv <= 0)
110 return;
75 base::AutoLock lock(lock_); 111 base::AutoLock lock(lock_);
76 uint16_t socket = GetPort(connection); 112 uint16_t socket = GetPort(connection);
77 EXPECT_FALSE(sockets_.find(socket) == sockets_.end()); 113 EXPECT_FALSE(sockets_.find(socket) == sockets_.end());
78 114
79 sockets_[socket] = SOCKET_READ_FROM; 115 sockets_[socket] = SOCKET_READ_FROM;
80 task_runner_->PostTask(FROM_HERE, read_loop_.QuitClosure()); 116 task_runner_->PostTask(FROM_HERE, read_loop_.QuitClosure());
81 } 117 }
82 118
83 // Returns the number of sockets that were accepted by the server. 119 // Returns the number of sockets that were accepted by the server.
84 size_t GetAcceptedSocketCount() const { 120 size_t GetAcceptedSocketCount() const {
85 base::AutoLock lock(lock_); 121 base::AutoLock lock(lock_);
86 return sockets_.size(); 122 return sockets_.size();
87 } 123 }
88 124
89 // Returns the number of sockets that were read from by the server. 125 // Returns the number of sockets that were read from by the server.
90 size_t GetReadSocketCount() const { 126 size_t GetReadSocketCount() const {
91 base::AutoLock lock(lock_); 127 base::AutoLock lock(lock_);
92 size_t read_sockets = 0; 128 size_t read_sockets = 0;
93 for (const auto& socket : sockets_) { 129 for (const auto& socket : sockets_) {
94 if (socket.second == SOCKET_READ_FROM) 130 if (socket.second == SOCKET_READ_FROM)
95 ++read_sockets; 131 ++read_sockets;
96 } 132 }
97 return read_sockets; 133 return read_sockets;
98 } 134 }
99 135
100 void WaitUntilFirstConnectionAccepted() { accept_loop_.Run(); } 136 void WaitUntilFirstConnectionAccepted() { accept_loop_.Run(); }
137 void WaitUntilFirstConnectionRead() { read_loop_.Run(); }
101 138
102 void WaitUntilFirstConnectionRead() { read_loop_.Run(); } 139 // The UI thread will wait for exactly |n| items in soeckts_.
mmenke 2016/05/06 19:54:01 nit: |sockets_|
Charlie Harrison 2016/05/09 19:47:04 Done.
140 void WaitForAcceptedConnectionsOnUI(int n) {
141 DCHECK_CURRENTLY_ON(BrowserThread::UI);
142 base::RunLoop run_loop;
143 {
144 base::AutoLock lock(lock_);
145 accept_n_ = n;
146 accept_n_loop_ = &run_loop;
147 BrowserThread::PostTask(
148 BrowserThread::IO, FROM_HERE,
149 base::Bind(&ConnectionListener::CheckAcceptedLocked,
150 base::Unretained(this)));
151 }
152 run_loop.Run();
153 }
154
155 void CheckAcceptedLocked() {
156 base::AutoLock lock(lock_);
157 CheckAccepted();
158 }
159
160 void CheckAccepted() {
161 if (accept_n_loop_ && accept_n_) {
162 if (accept_n_ == sockets_.size()) {
163 task_runner_->PostTask(FROM_HERE, accept_n_loop_->QuitClosure());
164 accept_n_loop_ = nullptr;
165 accept_n_ = 0;
166 }
167 }
168 }
103 169
104 private: 170 private:
105 static uint16_t GetPort(const net::StreamSocket& connection) { 171 static uint16_t GetPort(const net::StreamSocket& connection) {
106 // Get the remote port of the peer, since the local port will always be the 172 // Get the remote port of the peer, since the local port will always be the
107 // port the test server is listening on. This isn't strictly correct - it's 173 // port the test server is listening on. This isn't strictly correct - it's
108 // possible for multiple peers to connect with the same remote port but 174 // possible for multiple peers to connect with the same remote port but
109 // different remote IPs - but the tests here assume that connections to the 175 // different remote IPs - but the tests here assume that connections to the
110 // test server (running on localhost) will always come from localhost, and 176 // test server (running on localhost) will always come from localhost, and
111 // thus the peer port is all thats needed to distinguish two connections. 177 // thus the peer port is all thats needed to distinguish two connections.
112 // This also would be problematic if the OS reused ports, but that's not 178 // This also would be problematic if the OS reused ports, but that's not
113 // something to worry about for these tests. 179 // something to worry about for these tests.
114 net::IPEndPoint address; 180 net::IPEndPoint address;
115 EXPECT_EQ(net::OK, connection.GetPeerAddress(&address)); 181 EXPECT_EQ(net::OK, connection.GetPeerAddress(&address));
116 return address.port(); 182 return address.port();
117 } 183 }
118 184
119 enum SocketStatus { SOCKET_ACCEPTED, SOCKET_READ_FROM }; 185 enum SocketStatus { SOCKET_ACCEPTED, SOCKET_READ_FROM };
120 186
121 typedef base::hash_map<uint16_t, SocketStatus> SocketContainer; 187 typedef base::hash_map<uint16_t, SocketStatus> SocketContainer;
122 SocketContainer sockets_; 188 SocketContainer sockets_;
123 189
124 base::RunLoop accept_loop_; 190 base::RunLoop accept_loop_;
125 base::RunLoop read_loop_; 191 base::RunLoop read_loop_;
192
193 // If accept_n_ > 0, then the object is waiting for |accept_n_| sockets to be
mmenke 2016/05/06 19:54:01 nit: |accept_n_|
Charlie Harrison 2016/05/09 19:47:04 Done.
194 // accepted before quiting the loop.
195 size_t accept_n_;
196 base::RunLoop* accept_n_loop_;
197
126 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 198 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
127 199
128 mutable base::Lock lock_; 200 mutable base::Lock lock_;
129 201
130 DISALLOW_COPY_AND_ASSIGN(ConnectionListener); 202 DISALLOW_COPY_AND_ASSIGN(ConnectionListener);
131 }; 203 };
132 204
133 // Records a history of all hostnames for which resolving has been requested, 205 // Records a history of all hostnames for which resolving has been requested,
134 // and immediately fails the resolution requests themselves. 206 // and immediately fails the resolution requests themselves.
135 class HostResolutionRequestRecorder : public net::HostResolverProc { 207 class HostResolutionRequestRecorder : public net::HostResolverProc {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 // requested and thus is running a nested message loop. 267 // requested and thus is running a nested message loop.
196 bool is_waiting_for_hostname_; 268 bool is_waiting_for_hostname_;
197 269
198 // A list of hostnames for which resolution has already been requested. Only 270 // A list of hostnames for which resolution has already been requested. Only
199 // to be accessed from the UI thread. 271 // to be accessed from the UI thread.
200 std::vector<std::string> requested_hostnames_; 272 std::vector<std::string> requested_hostnames_;
201 273
202 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder); 274 DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder);
203 }; 275 };
204 276
277 // This class intercepts URLRequests and responds with empty 200s. Note that the
278 // port of the URL must match the port given in the constructor.
mmenke 2016/05/06 19:54:01 Update comment.
Charlie Harrison 2016/05/09 19:47:04 Done.
279 class MatchingPortRequestInterceptor : public net::URLRequestInterceptor {
280 public:
281 MatchingPortRequestInterceptor(
282 int port,
283 base::Callback<net::URLRequestJob*(net::URLRequest*,
284 net::NetworkDelegate*)> job_callback)
285 : callback_(job_callback), port_(port) {}
mmenke 2016/05/06 19:54:01 suggest a clearer name for both the argument and t
Charlie Harrison 2016/05/09 19:47:05 Done.
286 ~MatchingPortRequestInterceptor() override {}
287
288 private:
289 net::URLRequestJob* MaybeInterceptRequest(
290 net::URLRequest* request,
291 net::NetworkDelegate* network_delegate) const override {
292 if (request->url().EffectiveIntPort() != port_)
293 return nullptr;
294 return callback_.Run(request, network_delegate);
295 }
mmenke 2016/05/06 19:54:01 nit: Blank ine between methods and member variabl
Charlie Harrison 2016/05/09 19:47:04 Done.
296 base::Callback<net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)>
297 callback_;
298 int port_;
mmenke 2016/05/06 19:54:00 nit: both these can be const
Charlie Harrison 2016/05/09 19:47:05 Done.
299 DISALLOW_COPY_AND_ASSIGN(MatchingPortRequestInterceptor);
mmenke 2016/05/06 19:54:01 nit: Blank line before DISALLOW_COPY_AND_ASSIGN
Charlie Harrison 2016/05/09 19:47:04 Done.
300 };
301
302 class CrossSitePredictorObserver
mmenke 2016/05/06 19:54:01 Add description
Charlie Harrison 2016/05/09 19:47:04 Done.
303 : public chrome_browser_net::PredictorObserver {
304 public:
305 CrossSitePredictorObserver(const GURL& source_host,
306 const GURL& cross_site_host)
307 : source_host_(source_host),
308 cross_site_host_(cross_site_host),
309 cross_site_learned_(0),
310 cross_site_preconnected_(0),
311 same_site_preconnected_(0) {}
312
313 void OnPreconnectUrl(
314 const GURL& original_url,
315 const GURL& first_party_for_cookies,
316 chrome_browser_net::UrlInfo::ResolutionMotivation motivation,
317 int count) override {
318 base::AutoLock lock(lock_);
319 if (original_url == cross_site_host_) {
320 cross_site_preconnected_ = std::max(cross_site_preconnected_, count);
321 } else if (original_url == source_host_) {
322 same_site_preconnected_ = std::max(same_site_preconnected_, count);
323 } else {
324 ADD_FAILURE() << "Preconnected" << original_url
325 << " When should only be preconnecting the source host: "
326 << source_host_
327 << " or the cross site host: " << cross_site_host_;
328 }
329 }
330
331 void OnLearnFromNavigation(const GURL& referring_url,
332 const GURL& target_url) override {
333 base::AutoLock lock(lock_);
334 // There are three possibilities:
335 // source => target
336 // source => source
337 // target => target
338 if (referring_url == source_host_ && target_url == cross_site_host_) {
339 cross_site_learned_++;
340 } else if (referring_url == source_host_ && target_url == source_host_) {
341 // Same site learned. Branch retained for clarity.
342 } else if (!(referring_url == cross_site_host_ &&
343 target_url == cross_site_host_)) {
344 ADD_FAILURE() << "Learned " << referring_url << " => " << target_url
345 << " When should only be learning the source host: "
346 << source_host_
347 << " or the cross site host: " << cross_site_host_;
348 }
349 }
350
351 void ResetCounts() {
352 base::AutoLock lock(lock_);
353 cross_site_learned_ = 0;
354 cross_site_preconnected_ = 0;
355 same_site_preconnected_ = 0;
356 }
357
358 int cross_site_learned() const {
mmenke 2016/05/06 19:54:00 These should use the BigSlowFunctionNamingScheme b
Charlie Harrison 2016/05/09 19:47:04 Done.
359 base::AutoLock lock(lock_);
360 return cross_site_learned_;
361 }
362
363 int cross_site_preconnected() const {
364 base::AutoLock lock(lock_);
365 return cross_site_preconnected_;
366 }
367
368 int same_site_preconnected() const {
369 base::AutoLock lock(lock_);
370 return same_site_preconnected_;
371 }
372
373 private:
374 const GURL source_host_;
375 const GURL cross_site_host_;
376
377 int cross_site_learned_;
378
379 int cross_site_preconnected_;
380 int same_site_preconnected_;
381 mutable base::Lock lock_;
mmenke 2016/05/06 19:54:00 suggest not making this mutable, and getting rid o
Charlie Harrison 2016/05/09 19:47:04 Done.
382 DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver);
mmenke 2016/05/06 19:54:01 nit: Blank line before DISALLOW_COPY_AND_ASSIGN
Charlie Harrison 2016/05/09 19:47:04 Done.
383 };
384
205 } // namespace 385 } // namespace
206 386
207 namespace chrome_browser_net { 387 namespace chrome_browser_net {
208 388
209 class PredictorBrowserTest : public InProcessBrowserTest { 389 class PredictorBrowserTest : public InProcessBrowserTest {
210 public: 390 public:
211 PredictorBrowserTest() 391 PredictorBrowserTest()
212 : startup_url_("http://host1:1"), 392 : startup_url_("http://host1:1"),
213 referring_url_("http://host2:1"), 393 referring_url_("http://host2:1"),
214 target_url_("http://host3:1"), 394 target_url_("http://host3:1"),
215 host_resolution_request_recorder_(new HostResolutionRequestRecorder) { 395 host_resolution_request_recorder_(new HostResolutionRequestRecorder),
396 cross_site_test_server_(new net::EmbeddedTestServer()) {}
397 void StartInterceptingCrossSite() {
mmenke 2016/05/06 19:54:00 Should have thread-safety DCHECKs on all of these
Charlie Harrison 2016/05/09 19:47:04 Done. Put it on the most relevant methods.
398 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
399 "http", cross_site_test_server()->GetURL("/").host(),
400 base::WrapUnique(new MatchingPortRequestInterceptor(
401 cross_site_test_server()->GetURL("/").EffectiveIntPort(),
mmenke 2016/05/06 19:54:01 The test server's GetURL method isn't guaranteed t
Charlie Harrison 2016/05/09 19:47:05 Done.
402 base::Bind(&EmptyRequestJob))));
403 }
404 void StopInterceptingCrossSite() {
mmenke 2016/05/06 19:54:00 Suggest you make this static, per above comment.
Charlie Harrison 2016/05/09 19:47:04 Done.
405 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(
406 "http", cross_site_test_server()->GetURL("/").host());
407 }
408 void StartInterceptingCrossSiteOnUI() {
409 content::BrowserThread::PostTask(
410 content::BrowserThread::IO, FROM_HERE,
411 base::Bind(&PredictorBrowserTest::StartInterceptingCrossSite,
412 base::Unretained(this)));
413 }
414 void StopInterceptingCrossSiteOnUI() {
415 content::BrowserThread::PostTask(
416 content::BrowserThread::IO, FROM_HERE,
417 base::Bind(&PredictorBrowserTest::StopInterceptingCrossSite,
418 base::Unretained(this)));
216 } 419 }
mmenke 2016/05/06 19:54:01 Suggest putting these 4 methods below SetUpOnIOThr
mmenke 2016/05/06 19:54:01 nit: Suggest a blank line between methods.
Charlie Harrison 2016/05/09 19:47:03 Done.
Charlie Harrison 2016/05/09 19:47:04 Done.
217 420
218 protected: 421 protected:
219 void SetUpInProcessBrowserTestFixture() override { 422 void SetUpInProcessBrowserTestFixture() override {
220 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc( 423 scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc(
221 host_resolution_request_recorder_.get())); 424 host_resolution_request_recorder_.get()));
222 InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); 425 InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
223 } 426 }
224 427
225 void SetUpCommandLine(base::CommandLine* command_line) override { 428 void SetUpCommandLine(base::CommandLine* command_line) override {
226 command_line->AppendSwitch( 429 command_line->AppendSwitch(
227 switches::kEnableExperimentalWebPlatformFeatures); 430 switches::kEnableExperimentalWebPlatformFeatures);
228 command_line->AppendSwitchASCII( 431 command_line->AppendSwitchASCII(
229 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature); 432 switches::kEnableBlinkFeatures, kBlinkPreconnectFeature);
230 } 433 }
231 434
435 // Override the test server to redirect requests matching some path. This is
436 // used because the predictor only learns simple redirects with a path of "/"
437 std::unique_ptr<net::test_server::HttpResponse> RedirectForPathHandler(
mmenke 2016/05/06 19:54:02 This should be static. Actually, could even just
Charlie Harrison 2016/05/09 19:47:04 Done.
438 const std::string& path,
439 const GURL& redirect_url,
440 const net::test_server::HttpRequest& request) {
441 if (request.GetURL().path() != path)
442 return nullptr;
443 std::unique_ptr<net::test_server::BasicHttpResponse> response(
444 new net::test_server::BasicHttpResponse);
445 response->set_code(net::HTTP_MOVED_PERMANENTLY);
446 response->AddCustomHeader("Location", redirect_url.spec());
447 return std::move(response);
mmenke 2016/05/06 19:54:01 Is the std::move needed here? May be because it's
Charlie Harrison 2016/05/09 19:47:03 Yeah it's needed.
448 }
449
232 void SetUpOnMainThread() override { 450 void SetUpOnMainThread() override {
451 cross_site_test_server_->ServeFilesFromSourceDirectory("chrome/test/data/");
452
233 connection_listener_.reset(new ConnectionListener()); 453 connection_listener_.reset(new ConnectionListener());
454 cross_site_connection_listener_.reset(new ConnectionListener());
234 embedded_test_server()->SetConnectionListener(connection_listener_.get()); 455 embedded_test_server()->SetConnectionListener(connection_listener_.get());
456 cross_site_test_server_->SetConnectionListener(
457 cross_site_connection_listener_.get());
235 ASSERT_TRUE(embedded_test_server()->Start()); 458 ASSERT_TRUE(embedded_test_server()->Start());
459 ASSERT_TRUE(cross_site_test_server_->Start());
460
461 embedded_test_server()->RegisterRequestHandler(base::Bind(
462 &PredictorBrowserTest::RedirectForPathHandler, base::Unretained(this),
463 "/", cross_site_test_server()->GetURL("/title1.html")));
464
465 predictor()->set_preconnect_enabled_for_test(true);
466 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
467 base::Bind(&PredictorBrowserTest::SetUpOnIOThread,
468 base::Unretained(this)));
469 }
470
471 void SetUpOnIOThread() {
472 // Ignore all favicon requests. These are tricky to deal with because they
473 // are scheduled on the UI thread and are not accounted for in the load
474 // event. The interceptor will respond with 404s, and won't connect any
475 // sockets to the test server.
476 AddUrlInterceptor(cross_site_test_server()->GetURL("/favicon.ico"));
236 } 477 }
237 478
238 void TearDownOnMainThread() override { 479 void TearDownOnMainThread() override {
239 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); 480 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
240 } 481 }
241 482
242 // Navigates to a data URL containing the given content, with a MIME type of 483 // Navigates to a data URL containing the given content, with a MIME type of
243 // text/html. 484 // text/html.
244 void NavigateToDataURLWithContent(const std::string& content) { 485 void NavigateToDataURLWithContent(const std::string& content) {
245 std::string encoded_content; 486 std::string encoded_content;
246 base::Base64Encode(content, &encoded_content); 487 base::Base64Encode(content, &encoded_content);
247 std::string data_uri_content = "data:text/html;base64," + encoded_content; 488 std::string data_uri_content = "data:text/html;base64," + encoded_content;
248 ui_test_utils::NavigateToURL(browser(), GURL(data_uri_content)); 489 ui_test_utils::NavigateToURL(browser(), GURL(data_uri_content));
249 } 490 }
250 491
251 void TearDownInProcessBrowserTestFixture() override { 492 void TearDownInProcessBrowserTestFixture() override {
252 InProcessBrowserTest::TearDownInProcessBrowserTestFixture(); 493 InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
253 scoped_host_resolver_proc_.reset(); 494 scoped_host_resolver_proc_.reset();
254 } 495 }
255 496
256 void LearnAboutInitialNavigation(const GURL& url) { 497 void LearnAboutInitialNavigation(const GURL& url) {
257 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 498 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
258 BrowserThread::PostTask(BrowserThread::IO,
259 FROM_HERE,
260 base::Bind(&Predictor::LearnAboutInitialNavigation, 499 base::Bind(&Predictor::LearnAboutInitialNavigation,
261 base::Unretained(predictor), 500 base::Unretained(predictor()), url));
262 url));
263 content::RunAllPendingInMessageLoop(BrowserThread::IO); 501 content::RunAllPendingInMessageLoop(BrowserThread::IO);
264 } 502 }
265 503
266 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) { 504 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
267 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 505 BrowserThread::PostTask(
268 BrowserThread::PostTask(BrowserThread::IO, 506 BrowserThread::IO, FROM_HERE,
269 FROM_HERE, 507 base::Bind(&Predictor::LearnFromNavigation,
270 base::Bind(&Predictor::LearnFromNavigation, 508 base::Unretained(predictor()), referring_url, target_url));
271 base::Unretained(predictor),
272 referring_url,
273 target_url));
274 content::RunAllPendingInMessageLoop(BrowserThread::IO); 509 content::RunAllPendingInMessageLoop(BrowserThread::IO);
275 } 510 }
276 511
277 void PrepareFrameSubresources(const GURL& url) { 512 void PrepareFrameSubresources(const GURL& url) {
278 Predictor* predictor = browser()->profile()->GetNetworkPredictor(); 513 predictor()->PredictFrameSubresources(url, GURL());
279 predictor->PredictFrameSubresources(url, GURL());
280 } 514 }
281 515
282 void GetListFromPrefsAsString(const char* list_path, 516 void GetListFromPrefsAsString(const char* list_path,
283 std::string* value_as_string) const { 517 std::string* value_as_string) const {
284 PrefService* prefs = browser()->profile()->GetPrefs(); 518 PrefService* prefs = browser()->profile()->GetPrefs();
285 const base::ListValue* list_value = prefs->GetList(list_path); 519 const base::ListValue* list_value = prefs->GetList(list_path);
286 JSONStringValueSerializer serializer(value_as_string); 520 JSONStringValueSerializer serializer(value_as_string);
287 serializer.Serialize(*list_value); 521 serializer.Serialize(*list_value);
288 } 522 }
289 523
290 bool HasHostBeenRequested(const std::string& hostname) const { 524 bool HasHostBeenRequested(const std::string& hostname) const {
291 return host_resolution_request_recorder_->HasHostBeenRequested(hostname); 525 return host_resolution_request_recorder_->HasHostBeenRequested(hostname);
292 } 526 }
293 527
294 void WaitUntilHostHasBeenRequested(const std::string& hostname) { 528 void WaitUntilHostHasBeenRequested(const std::string& hostname) {
295 host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname); 529 host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname);
296 } 530 }
297 531
298 int RequestedHostnameCount() const { 532 int RequestedHostnameCount() const {
299 return host_resolution_request_recorder_->RequestedHostnameCount(); 533 return host_resolution_request_recorder_->RequestedHostnameCount();
300 } 534 }
301 535
536 net::EmbeddedTestServer* cross_site_test_server() {
537 return cross_site_test_server_.get();
538 }
539
540 Predictor* predictor() { return browser()->profile()->GetNetworkPredictor(); }
541
542 void InstallPredictorObserver() {
543 observer_.reset(
544 new CrossSitePredictorObserver(embedded_test_server()->base_url(),
545 cross_site_test_server()->base_url()));
546 BrowserThread::PostTask(
547 BrowserThread::IO, FROM_HERE,
548 base::Bind(&PredictorBrowserTest::InstallPredictorObserverOnIOThread,
549 base::Unretained(this), base::Unretained(predictor())));
550 }
551
552 void InstallPredictorObserverOnIOThread(
553 chrome_browser_net::Predictor* predictor) {
554 predictor->SetObserver(observer_.get());
555 }
556
557 CrossSitePredictorObserver* observer() { return observer_.get(); }
558
559 // Navigate to an html file on embedded_test_server and tell it to request
560 // |num_cors| resources from the cross_site_test_server. It then waits for
561 // those requests to complete. Note that "cors" here means using cors-mode in
562 // correspondence with the fetch spec.
563 void NavigateToCrossSiteHTMLURL(int num_cors, const char* file_suffix) {
mmenke 2016/05/06 19:54:00 nit: HtmlUrl (A lot of class and methods capitali
Charlie Harrison 2016/05/09 19:47:05 Done.
564 const GURL& base_url = cross_site_test_server()->base_url();
565 std::string path = base::StringPrintf(
566 "/predictor/"
567 "predictor_cross_site%s.html?subresourceHost=%s&"
568 "numCORSResources=%d",
569 file_suffix, base_url.spec().c_str(), num_cors);
570 ui_test_utils::NavigateToURL(browser(),
571 embedded_test_server()->GetURL(path));
572 bool result = false;
573 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
574 browser()->tab_strip_model()->GetActiveWebContents(),
575 "startFetchesAndWaitForReply()", &result));
576 EXPECT_TRUE(result);
577 }
578
579 static void AddUrlInterceptor(const GURL& url) {
mmenke 2016/05/06 19:54:00 This method name doesn't make the behavior clear.
mmenke 2016/05/06 19:54:01 I guess this is needed because failed requests are
Charlie Harrison 2016/05/09 19:47:04 Actually, I think this could use the regular inter
580 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
581 url, base::WrapUnique(new MatchingPortRequestInterceptor(
582 url.EffectiveIntPort(), base::Bind(&NotFoundRequestJob))));
583 }
584
302 const GURL startup_url_; 585 const GURL startup_url_;
303 const GURL referring_url_; 586 const GURL referring_url_;
304 const GURL target_url_; 587 const GURL target_url_;
305 std::unique_ptr<ConnectionListener> connection_listener_; 588 std::unique_ptr<ConnectionListener> connection_listener_;
589 std::unique_ptr<ConnectionListener> cross_site_connection_listener_;
306 590
307 private: 591 private:
308 scoped_refptr<HostResolutionRequestRecorder> 592 scoped_refptr<HostResolutionRequestRecorder>
309 host_resolution_request_recorder_; 593 host_resolution_request_recorder_;
310 std::unique_ptr<net::ScopedDefaultHostResolverProc> 594 std::unique_ptr<net::ScopedDefaultHostResolverProc>
311 scoped_host_resolver_proc_; 595 scoped_host_resolver_proc_;
596 std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_;
597 std::unique_ptr<CrossSitePredictorObserver> observer_;
312 }; 598 };
313 599
314 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PRE_ShutdownStartupCycle) { 600 // Test the html test harness used to initiate cross site fetches. These
601 // initiate cross site subresource requests to the cross site test server.
602 // Inspect the predictor's internal state to make sure that they are properly
603 // logged.
604 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteUseOneSocket) {
605 InstallPredictorObserver();
606 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
607 EXPECT_EQ(1u, cross_site_connection_listener_->GetAcceptedSocketCount());
608 EXPECT_EQ(1, observer()->cross_site_learned());
609 EXPECT_EQ(2, observer()->same_site_preconnected());
610 }
611
612 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteUseThreeSockets) {
613 InstallPredictorObserver();
614 NavigateToCrossSiteHTMLURL(3 /* num_cors */, "" /* file_suffix */);
615 EXPECT_EQ(3u, cross_site_connection_listener_->GetAcceptedSocketCount());
616 EXPECT_EQ(3, observer()->cross_site_learned());
617 EXPECT_EQ(2, observer()->same_site_preconnected());
618 }
619
620 // The following tests confirm that Chrome accurately predicts preconnects after
621 // learning from navigations. Note that every "learned" connection adds ~.33 to
622 // the expected connection number, which starts at 2. Every preconnect Chrome
623 // performs multiplies the expected connections by .66.
624 //
625 // In order to simplify things, many of the following tests intercept requests
626 // and disable preconnects to the cross site test server. This allows the test
627 // server to maintain a "clean slate" with no connected sockets, so that when
628 // the tests need to check that predictor initiated preconnects occur, there are
629 // no races and the connections are deterministic.
mmenke 2016/05/06 19:54:01 Could we just wait until we see the expected numbe
630 //
631 // One additional complexity is that if a preconnect from A to B is learned, an
632 // extra preconnect will be issued if the host part of A and B match (ignoring
633 // port). TODO(csharrison): This logic could probably be removed from the
634 // predictor.
635 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
636 CrossSiteSimplePredictionAfterOneNavigation) {
637 predictor()->set_preconnect_enabled_for_test(false);
638 StartInterceptingCrossSiteOnUI();
639
640 InstallPredictorObserver();
641 NavigateToCrossSiteHTMLURL(2 /* num_cors */, "" /* file_suffix */);
642 EXPECT_EQ(2, observer()->cross_site_learned());
643
644 StopInterceptingCrossSiteOnUI();
645 predictor()->set_preconnect_enabled_for_test(true);
646 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
647
648 // Navigate again and confirm a preconnect. Note that because the two
649 // embedded test servers have the same host_piece, an extra preconnect is
650 // issued. This results in ceil(2.66) + 1 = 4 preconnects.
651 ui_test_utils::NavigateToURL(browser(),
652 embedded_test_server()->GetURL("/title1.html"));
653 EXPECT_EQ(4, observer()->cross_site_preconnected());
654 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
655 }
656
657 // This test does not intercept initial requests / preconnects to the cross site
658 // test server.
659 IN_PROC_BROWSER_TEST_F(
660 PredictorBrowserTest,
661 CrossSiteSimplePredictionAfterOneNavigationNoInterceptor) {
662 InstallPredictorObserver();
663 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
664 EXPECT_EQ(1, observer()->cross_site_learned());
665 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(1u);
666
667 // Navigate again and confirm a preconnect. Note that because the two
668 // embedded test servers have the same host_piece, an extra preconnect is
669 // issued. This results in ceil(2.33) + 1 = 4 preconnects.
670 ui_test_utils::NavigateToURL(browser(),
671 embedded_test_server()->GetURL("/title1.html"));
672 // Just check that predictor has initiated preconnects to the cross site test
673 // server. It's tricky to reset the connections to the test server, and
674 // sockets can be reused.
675 EXPECT_EQ(4, observer()->cross_site_preconnected());
676 }
677
678 // Expect that the predictor correctly predicts subframe navigations.
679 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeCrossSitePrediction) {
680 InstallPredictorObserver();
681 predictor()->set_preconnect_enabled_for_test(false);
682 StartInterceptingCrossSiteOnUI();
683
684 InstallPredictorObserver();
685 ui_test_utils::NavigateToURL(
686 browser(), embedded_test_server()->GetURL(
687 "/predictor/predictor_cross_site_subframe_nav.html"));
688 bool result = false;
689 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
690 browser()->tab_strip_model()->GetActiveWebContents(),
691 base::StringPrintf(
692 "navigateSubframe('%s')",
693 cross_site_test_server()->GetURL("/title1.html").spec().c_str()),
694 &result));
695 EXPECT_TRUE(result);
696 EXPECT_EQ(1, observer()->cross_site_learned());
697
698 StopInterceptingCrossSiteOnUI();
699 predictor()->set_preconnect_enabled_for_test(true);
700 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
701
702 // Navigate again and confirm a preconnect. Note that because the two
703 // embedded test servers have the same host_piece, an extra preconnect is
704 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
705 ui_test_utils::NavigateToURL(browser(),
706 embedded_test_server()->GetURL("/title1.html"));
707 EXPECT_EQ(4, observer()->cross_site_preconnected());
708 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
709 }
710
711 // Expect that the predictor correctly preconnects an already learned resource
712 // if the host shows up in a subframe.
713 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeInitiatesPreconnects) {
714 InstallPredictorObserver();
715 predictor()->set_preconnect_enabled_for_test(false);
716 StartInterceptingCrossSiteOnUI();
717
718 // Navigate to the normal cross site URL to learn the relationship.
719 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
720 EXPECT_EQ(1, observer()->cross_site_learned());
721
722 predictor()->set_preconnect_enabled_for_test(true);
723 StopInterceptingCrossSiteOnUI();
724 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
725
726 // Navigate again and confirm a preconnect. Note that because the two
727 // embedded test servers have the same host_piece, an extra preconnect is
728 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
729 NavigateToDataURLWithContent(
730 "<iframe src=\"" + embedded_test_server()->GetURL("/title1.html").spec() +
731 "\"></iframe>");
732 EXPECT_EQ(4, observer()->cross_site_preconnected());
733 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
734 }
735
736 // Expect that the predictor correctly learns the subresources a subframe needs
737 // to preconnect to.
738 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeLearning) {
739 InstallPredictorObserver();
740 predictor()->set_preconnect_enabled_for_test(false);
741 StartInterceptingCrossSiteOnUI();
742
743 std::string path = base::StringPrintf(
744 "/predictor/"
745 "predictor_cross_site.html?subresourceHost=%s&"
746 "numCORSResources=1&sendImmediately=1",
747 cross_site_test_server()->base_url().spec().c_str());
748 NavigateToDataURLWithContent(
749 base::StringPrintf("<iframe src=\"%s\"></iframe>",
750 embedded_test_server()->GetURL(path).spec().c_str()));
751 EXPECT_EQ(1, observer()->cross_site_learned());
752
753 StopInterceptingCrossSiteOnUI();
754 predictor()->set_preconnect_enabled_for_test(true);
755 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
756
757 // Navigate again and confirm a preconnect. Note that because the two
758 // embedded test servers have the same host_piece, an extra preconnect is
759 // issued. This results in ceil(2 + .33) + 1 = 4 preconnects.
760 NavigateToDataURLWithContent(
761 "<iframe src=\"" + embedded_test_server()->GetURL("/title1.html").spec() +
762 "\"></iframe>");
763 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
764 EXPECT_EQ(4u, cross_site_connection_listener_->GetAcceptedSocketCount());
765 EXPECT_EQ(4, observer()->cross_site_preconnected());
766 }
767
768 // This tests the implementation details of the predictor. The current predictor
769 // only learns via the referrer header.
770 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteNoReferrerNoLearning) {
771 InstallPredictorObserver();
772 NavigateToCrossSiteHTMLURL(1 /* num_cors */,
773 "_no_referrer" /* file_suffix */);
774 cross_site_connection_listener_->WaitUntilFirstConnectionAccepted();
775 EXPECT_EQ(1u, cross_site_connection_listener_->GetAcceptedSocketCount());
776 EXPECT_EQ(0, observer()->cross_site_learned());
777 EXPECT_EQ(2, observer()->same_site_preconnected());
778 }
779
780 // This test navigates to an html file with a tag:
781 // <meta name="referrer" content="never">
782 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
783 CrossSiteNoReferrerNoPredictionAfterOneNavigation) {
784 InstallPredictorObserver();
785 predictor()->set_preconnect_enabled_for_test(false);
786 StartInterceptingCrossSiteOnUI();
787
788 NavigateToCrossSiteHTMLURL(2 /* num_cors */,
789 "_no_referrer" /* file_suffix */);
790 EXPECT_EQ(0, observer()->cross_site_learned());
791
792 StopInterceptingCrossSiteOnUI();
793 predictor()->set_preconnect_enabled_for_test(false);
794 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
795
796 // Navigate again and confirm that no preconnects occurred.
797 ui_test_utils::NavigateToURL(browser(),
798 embedded_test_server()->GetURL("/title1.html"));
799 EXPECT_EQ(0, observer()->cross_site_preconnected());
800 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
801 }
802
803 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
804 CrossSiteSimplePredictionAfterTwoNavigations) {
805 InstallPredictorObserver();
806 predictor()->set_preconnect_enabled_for_test(false);
807 StartInterceptingCrossSiteOnUI();
808
809 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
810 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
811
812 StopInterceptingCrossSiteOnUI();
813 predictor()->set_preconnect_enabled_for_test(true);
814 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
815
816 // Navigate again and confirm a preconnect. Note that because the two
817 // embedded test servers have the same host_piece, an extra preconnect is
818 // issued. This results in ceil((2 + .33) + .33) + 1 ~= 4 preconnects.
819 ui_test_utils::NavigateToURL(browser(),
820 embedded_test_server()->GetURL("/title1.html"));
821 EXPECT_EQ(4, observer()->cross_site_preconnected());
822 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
823 }
824
825 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
826 CrossSiteSimplePredictionAfterTwoNavigations2) {
827 InstallPredictorObserver();
828 predictor()->set_preconnect_enabled_for_test(false);
829 StartInterceptingCrossSiteOnUI();
830
831 NavigateToCrossSiteHTMLURL(2 /* num_cors */, "" /* file_suffix */);
832 NavigateToCrossSiteHTMLURL(2 /* num_cors */, "" /* file_suffix */);
833
834 StopInterceptingCrossSiteOnUI();
835 predictor()->set_preconnect_enabled_for_test(true);
836 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
837
838 // ((2 + .66) + .66) + 1 ~= 4.2.
839 ui_test_utils::NavigateToURL(browser(),
840 embedded_test_server()->GetURL("/title1.html"));
841 EXPECT_EQ(5, observer()->cross_site_preconnected());
842 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(5u);
843 }
844
845 // The first navigation uses a subresource. Subsequent navigations don't use
846 // that subresource. This tests how the predictor forgets about these bad
847 // navigations.
848 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ForgetBadPrediction) {
849 InstallPredictorObserver();
850
851 NavigateToCrossSiteHTMLURL(1 /* num_cors */, "" /* file_suffix */);
852 EXPECT_EQ(1, observer()->cross_site_learned());
853
854 ui_test_utils::NavigateToURL(browser(),
855 embedded_test_server()->GetURL("/title1.html"));
856 // (2 + .33) + 1 = 3.33.
857 EXPECT_EQ(4, observer()->cross_site_preconnected());
858 observer()->ResetCounts();
859 ui_test_utils::NavigateToURL(browser(),
860 embedded_test_server()->GetURL("/title1.html"));
861 // ceil((2 + .33) * .66) + 1 = 3.
862 EXPECT_EQ(3, observer()->cross_site_preconnected());
863 observer()->ResetCounts();
864 ui_test_utils::NavigateToURL(browser(),
865 embedded_test_server()->GetURL("/title1.html"));
866 // ceil((2 + .33) * .66 * .66) + 1 = 3.
867 EXPECT_EQ(3, observer()->cross_site_preconnected());
868 observer()->ResetCounts();
869
870 ui_test_utils::NavigateToURL(browser(),
871 embedded_test_server()->GetURL("/title1.html"));
872 // Finally, (2 + .33) * .66^3 ~= .67. Not enough for a preconnect.
873 EXPECT_EQ(0, observer()->cross_site_preconnected());
874 }
875
876 // The predictor does not follow redirects if the original url had a non-empty
877 // path (a path that was more than just "/").
878 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
879 CrossSiteRedirectNoPredictionWithPath) {
880 InstallPredictorObserver();
881 predictor()->set_preconnect_enabled_for_test(false);
882 StartInterceptingCrossSiteOnUI();
883
884 ui_test_utils::NavigateToURL(
885 browser(),
886 embedded_test_server()->GetURL(base::StringPrintf(
887 "/server-redirect?%s",
888 cross_site_test_server()->GetURL("/title1.html").spec().c_str())));
889 EXPECT_EQ(0, observer()->cross_site_learned());
890
891 StopInterceptingCrossSiteOnUI();
892 predictor()->set_preconnect_enabled_for_test(true);
893 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
894
895 ui_test_utils::NavigateToURL(browser(),
896 embedded_test_server()->GetURL("/title1.html"));
897 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
898 EXPECT_EQ(0, observer()->cross_site_preconnected());
899 }
900
901 // The predictor does follow redirects if the original url had an empty path
902 // (a path that was more than just "/"). Use the registered "/" path to redirect
903 // to the target test server.
904 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
905 CrossSiteRedirectPredictionWithNoPath) {
906 InstallPredictorObserver();
907 predictor()->set_preconnect_enabled_for_test(false);
908 StartInterceptingCrossSiteOnUI();
909
910 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
911 EXPECT_EQ(1, observer()->cross_site_learned());
912
913 StopInterceptingCrossSiteOnUI();
914 predictor()->set_preconnect_enabled_for_test(true);
915 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
916
917 ui_test_utils::NavigateToURL(browser(),
918 embedded_test_server()->GetURL("/title1.html"));
919 // Preconnect 4 sockets because ceil(2 + .33) + 1 = 4.
920 EXPECT_EQ(4, observer()->cross_site_preconnected());
921 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
922 }
923
924 // This test uses "localhost" instead of "127.0.0.1" to avoid extra preconnects
925 // to hosts with the same host piece (ignoring port). Note that the preconnect
926 // observer is not used here due to its strict checks on hostname.
927 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
928 CrossSiteRedirectPredictionWithNoPathDifferentHostName) {
929 predictor()->set_preconnect_enabled_for_test(false);
930 StartInterceptingCrossSiteOnUI();
931
932 GURL localhost_source = GURL(base::StringPrintf(
933 "http://localhost:%s/predictor/"
934 "predictor_cross_site.html?subresourceHost=%s&numCORSResources=1",
935 embedded_test_server()->base_url().port().c_str(),
936 cross_site_test_server()->base_url().spec().c_str()));
937 ui_test_utils::NavigateToURL(browser(), localhost_source);
938 bool result = false;
939 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
940 browser()->tab_strip_model()->GetActiveWebContents(),
941 "startFetchesAndWaitForReply()", &result));
942 EXPECT_TRUE(result);
943
944 StopInterceptingCrossSiteOnUI();
945 predictor()->set_preconnect_enabled_for_test(true);
946 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
947
948 ui_test_utils::NavigateToURL(
949 browser(), GURL(base::StringPrintf(
950 "http://localhost:%s/title1.html",
951 embedded_test_server()->base_url().port().c_str())));
952 // Preconnect 3 sockets because ceil(2 + .33) = 3. Note that this time there
953 // is no additional connection due to same host.
954 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(3u);
955 }
956
957 // Perform the "/" redirect twice and make sure the predictor updates twice.
958 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
959 CrossSiteTwoRedirectsPredictionWithNoPath) {
960 InstallPredictorObserver();
961 predictor()->set_preconnect_enabled_for_test(false);
962 StartInterceptingCrossSiteOnUI();
963
964 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
965 EXPECT_EQ(1, observer()->cross_site_learned());
966
967 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
968 EXPECT_EQ(2, observer()->cross_site_learned());
969
970 StopInterceptingCrossSiteOnUI();
971 predictor()->set_preconnect_enabled_for_test(true);
972 EXPECT_EQ(0u, cross_site_connection_listener_->GetAcceptedSocketCount());
973
974 ui_test_utils::NavigateToURL(browser(),
975 embedded_test_server()->GetURL("/title1.html"));
976 // 4 preconnects expected because (2 + .33) + .33 + 1 = 3.66.
977 EXPECT_EQ(4, observer()->cross_site_preconnected());
978 cross_site_connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
979 }
980
981 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
982 PRE_ShutdownStartupCyclePreresolve) {
315 // Prepare state that will be serialized on this shut-down and read on next 983 // Prepare state that will be serialized on this shut-down and read on next
316 // start-up. 984 // start-up. Ensure preresolution over preconnection.
317 LearnAboutInitialNavigation(startup_url_); 985 LearnAboutInitialNavigation(startup_url_);
986 // The target url will have a expected connection count of 2 after this call.
318 LearnFromNavigation(referring_url_, target_url_); 987 LearnFromNavigation(referring_url_, target_url_);
319 } 988
320 989 // In order to reduce the expected connection count < .8, issue predictions 3
321 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCycle) { 990 // times. 2 * .66^3 ~= .58.
991 PrepareFrameSubresources(referring_url_);
992 PrepareFrameSubresources(referring_url_);
993 PrepareFrameSubresources(referring_url_);
994 }
995
996 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCyclePreresolve) {
322 // Make sure that the Preferences file is actually wiped of all DNS prefetch 997 // Make sure that the Preferences file is actually wiped of all DNS prefetch
323 // related data after start-up. 998 // related data after start-up.
324 std::string cleared_startup_list; 999 std::string cleared_startup_list;
325 std::string cleared_referral_list; 1000 std::string cleared_referral_list;
326 GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList, 1001 GetListFromPrefsAsString(prefs::kDnsPrefetchingStartupList,
327 &cleared_startup_list); 1002 &cleared_startup_list);
328 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList, 1003 GetListFromPrefsAsString(prefs::kDnsPrefetchingHostReferralList,
329 &cleared_referral_list); 1004 &cleared_referral_list);
330 1005
331 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host()))); 1006 EXPECT_THAT(cleared_startup_list, Not(HasSubstr(startup_url_.host())));
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 1130
456 // Second navigation to content with an img. 1131 // Second navigation to content with an img.
457 std::string img_content = 1132 std::string img_content =
458 "<img src=\"" + preconnect_url.spec() + "test.gif\">"; 1133 "<img src=\"" + preconnect_url.spec() + "test.gif\">";
459 NavigateToDataURLWithContent(img_content); 1134 NavigateToDataURLWithContent(img_content);
460 connection_listener_->WaitUntilFirstConnectionRead(); 1135 connection_listener_->WaitUntilFirstConnectionRead();
461 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount()); 1136 EXPECT_EQ(2u, connection_listener_->GetAcceptedSocketCount());
462 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount()); 1137 EXPECT_EQ(1u, connection_listener_->GetReadSocketCount());
463 } 1138 }
464 1139
1140 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectOne) {
mmenke 2016/05/06 19:54:00 Suggest putting these first (Think that putting th
Charlie Harrison 2016/05/09 19:47:04 Done.
1141 predictor()->PreconnectUrl(
1142 embedded_test_server()->base_url(), GURL(),
1143 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
1144 false /* allow credentials */, 1);
1145 connection_listener_->WaitForAcceptedConnectionsOnUI(1u);
1146 }
1147
1148 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectTwo) {
1149 predictor()->PreconnectUrl(
1150 embedded_test_server()->base_url(), GURL(),
1151 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
1152 false /* allow credentials */, 2);
1153 connection_listener_->WaitForAcceptedConnectionsOnUI(2u);
1154 }
1155
1156 IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectFour) {
1157 predictor()->PreconnectUrl(
1158 embedded_test_server()->base_url(), GURL(),
1159 UrlInfo::ResolutionMotivation::EARLY_LOAD_MOTIVATED,
1160 false /* allow credentials */, 4);
1161 connection_listener_->WaitForAcceptedConnectionsOnUI(4u);
1162 }
1163
465 } // namespace chrome_browser_net 1164 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/test/data/predictor/empty.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698