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

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