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

Unified 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: Add a "forgetting" test + fix typo Created 4 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/net/predictor_browsertest.cc
diff --git a/chrome/browser/net/predictor_browsertest.cc b/chrome/browser/net/predictor_browsertest.cc
index b06e4ef037cbcde697c896c7965a5d2c9b4b28e6..5d1afafc80af3a08ef880de85db617f83a819546 100644
--- a/chrome/browser/net/predictor_browsertest.cc
+++ b/chrome/browser/net/predictor_browsertest.cc
@@ -16,11 +16,13 @@
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/prefs/pref_service.h"
#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
@@ -30,6 +32,11 @@
#include "net/socket/stream_socket.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+#include "net/url_request/url_request_test_job.h"
#include "testing/gmock/include/gmock/gmock.h"
using content::BrowserThread;
@@ -71,8 +78,12 @@ class ConnectionListener
// Get called from the EmbeddedTestServer thread to be notified that
// a connection was read from.
- void ReadFromSocket(const net::StreamSocket& connection) override {
+ void ReadFromSocket(const net::StreamSocket& connection, int rv) override {
base::AutoLock lock(lock_);
mmenke 2016/04/15 15:44:03 This can be below the rv <= 0 check
Charlie Harrison 2016/04/20 12:36:42 Done.
+ // Don't log a read if no data was transferred. This case often happens if
+ // the sockets of the test server are being flushed and disconnected.
+ if (rv <= 0)
+ return;
uint16_t socket = GetPort(connection);
EXPECT_FALSE(sockets_.find(socket) == sockets_.end());
@@ -88,7 +99,6 @@ class ConnectionListener
// Returns the number of sockets that were read from by the server.
size_t GetReadSocketCount() const {
- base::AutoLock lock(lock_);
size_t read_sockets = 0;
mmenke 2016/04/15 15:44:02 Why did you remove the lock? If this coincides wi
Charlie Harrison 2016/04/20 12:36:43 This was a careless mistake probably from rearrang
for (const auto& socket : sockets_) {
if (socket.second == SOCKET_READ_FROM)
@@ -101,6 +111,11 @@ class ConnectionListener
void WaitUntilFirstConnectionRead() { read_loop_.Run(); }
+ void ClearSockets() {
+ base::AutoLock lock(lock_);
+ sockets_.clear();
+ }
+
private:
static uint16_t GetPort(const net::StreamSocket& connection) {
// Get the remote port of the peer, since the local port will always be the
@@ -202,20 +217,58 @@ class HostResolutionRequestRecorder : public net::HostResolverProc {
DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder);
};
+// This class intercepts URLRequests and responds with 404s.
+class NotFoundRequestInterceptor : public net::URLRequestInterceptor {
mmenke 2016/04/15 15:44:03 Give this a public constructor and destructor, and
Charlie Harrison 2016/04/20 12:36:43 Done.
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ const char kHeaders[] =
+ "HTTP/1.1 404 Not Found\n"
+ "\n";
+ std::string headers(kHeaders, arraysize(kHeaders));
+
+ return new net::URLRequestTestJob(request, network_delegate, headers, "",
+ true);
mmenke 2016/04/15 15:44:02 URLRequestTestJobs are weird. Can we just use URL
Charlie Harrison 2016/04/20 12:36:43 Sure. I'm not sure what the best error is, but ABO
+ }
+};
+
} // namespace
namespace chrome_browser_net {
-class PredictorBrowserTest : public InProcessBrowserTest {
+class PredictorBrowserTest : public InProcessBrowserTest,
+ public PredictorObserver {
public:
PredictorBrowserTest()
: startup_url_("http://host1:1"),
referring_url_("http://host2:1"),
target_url_("http://host3:1"),
- host_resolution_request_recorder_(new HostResolutionRequestRecorder) {
- }
+ source_target_learned_(0),
+ preconnected_target_(0),
+ preconnected_source_(0),
+ host_resolution_request_recorder_(new HostResolutionRequestRecorder),
+ target_test_server_(new net::EmbeddedTestServer()) {}
protected:
+ // PredictorObserver:
+ void OnPreconnectUrl(const GURL& original_url,
mmenke 2016/04/15 15:44:02 I don't think these should be part of the test fix
Charlie Harrison 2016/04/20 12:36:42 Fair enough, done.
+ const GURL& first_party_for_cookies,
+ UrlInfo::ResolutionMotivation motivation,
+ int count) override {
mmenke 2016/04/15 15:44:02 These are called on the IO thread, but you're acce
Charlie Harrison 2016/04/20 12:36:42 I added locks.
+ if (original_url == target_test_server()->base_url())
+ preconnected_target_ = std::max(preconnected_target_, count);
+ else if (original_url == embedded_test_server()->base_url())
+ preconnected_source_ = std::max(preconnected_source_, count);
mmenke 2016/04/15 15:44:02 nit: Use braces in if/else (Style varies in Chrom
mmenke 2016/04/15 15:44:03 If we're preconnecting some other URL, should we f
mmenke 2016/04/15 15:44:03 If it's neither of those URLs, should we fail?
Charlie Harrison 2016/04/20 12:36:42 Done.
Charlie Harrison 2016/04/20 12:36:42 Yeah. Done.
Charlie Harrison 2016/04/20 12:36:43 Yupp, done.
+ }
+
+ void OnLearnFromNavigation(const GURL& referring_url,
+ const GURL& target_url) override {
+ if (referring_url == embedded_test_server()->base_url() &&
+ target_url == target_test_server()->base_url()) {
+ source_target_learned_++;
+ }
mmenke 2016/04/15 15:44:02 What if they aren't equal? Should we do something
Charlie Harrison 2016/04/20 12:36:42 I've added failure conditions.
+ }
+
void SetUpInProcessBrowserTestFixture() override {
scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc(
host_resolution_request_recorder_.get()));
@@ -229,10 +282,41 @@ class PredictorBrowserTest : public InProcessBrowserTest {
switches::kEnableBlinkFeatures, kBlinkPreconnectFeature);
}
+ std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path() != "/")
+ return nullptr;
+ std::unique_ptr<net::test_server::BasicHttpResponse> response(
+ new net::test_server::BasicHttpResponse);
+ response->set_code(net::HTTP_MOVED_PERMANENTLY);
+ response->AddCustomHeader(
+ "Location", target_test_server()->GetURL("/title1.html").spec());
+ return std::move(response);
+ }
+
void SetUpOnMainThread() override {
+ embedded_test_server()->RegisterRequestHandler(base::Bind(
+ &PredictorBrowserTest::HandleRequest, base::Unretained(this)));
+ predictor()->SetObserver(this);
mmenke 2016/04/15 15:44:03 Calling this on the UI thread after the IOThread h
Charlie Harrison 2016/04/20 12:36:42 Done. The tests now call "InstallPredictorObserver
+ predictor()->set_preconnect_enabled(true);
+ target_test_server_->ServeFilesFromSourceDirectory("chrome/test/data/");
+
connection_listener_.reset(new ConnectionListener());
+ target_connection_listener_.reset(new ConnectionListener());
embedded_test_server()->SetConnectionListener(connection_listener_.get());
+ target_test_server_->SetConnectionListener(
+ target_connection_listener_.get());
ASSERT_TRUE(embedded_test_server()->Start());
+ ASSERT_TRUE(target_test_server_->Start());
+
+ // Ignore all favicon requests. These are tricky to deal with because they
+ // are scheduled on the UI thread and are not accounted for in the load
+ // event. The interceptor will respond with 404s, and we won't connect any
+ // sockets to the test server.
mmenke 2016/04/15 15:44:03 nit avoid "we" in comments.
Charlie Harrison 2016/04/20 12:36:43 Done. Removed all "we"s in comments in this file.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PredictorBrowserTest::AddUrlInterceptor,
+ target_test_server()->GetURL("/favicon.ico")));
mmenke 2016/04/13 17:50:23 Do we still learn from these requests? Just wonde
Charlie Harrison 2016/04/13 18:16:00 I think we do still learn from these. They are a h
}
void TearDownOnMainThread() override {
@@ -254,29 +338,22 @@ class PredictorBrowserTest : public InProcessBrowserTest {
}
void LearnAboutInitialNavigation(const GURL& url) {
- Predictor* predictor = browser()->profile()->GetNetworkPredictor();
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&Predictor::LearnAboutInitialNavigation,
- base::Unretained(predictor),
- url));
+ base::Unretained(predictor()), url));
content::RunAllPendingInMessageLoop(BrowserThread::IO);
}
void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
- Predictor* predictor = browser()->profile()->GetNetworkPredictor();
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&Predictor::LearnFromNavigation,
- base::Unretained(predictor),
- referring_url,
- target_url));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&Predictor::LearnFromNavigation,
+ base::Unretained(predictor()), referring_url, target_url));
content::RunAllPendingInMessageLoop(BrowserThread::IO);
}
void PrepareFrameSubresources(const GURL& url) {
- Predictor* predictor = browser()->profile()->GetNetworkPredictor();
- predictor->PredictFrameSubresources(url, GURL());
+ predictor()->PredictFrameSubresources(url, GURL());
}
void GetListFromPrefsAsString(const char* list_path,
@@ -299,17 +376,308 @@ class PredictorBrowserTest : public InProcessBrowserTest {
return host_resolution_request_recorder_->RequestedHostnameCount();
}
+ net::EmbeddedTestServer* target_test_server() {
+ return target_test_server_.get();
+ }
+
+ Predictor* predictor() { return browser()->profile()->GetNetworkPredictor(); }
+
+ // Navigate to an html file and request async fetches. Wait until the fetches
+ // complete before continuing.
+ void NavigateToCrossSiteHTMLURL(int num_cors,
+ int num_non_cors,
mmenke 2016/04/15 15:44:02 Think we should rename cors/non_cors to match the
mmenke 2016/04/15 20:27:17 Oh...The fact that non_cors does not mean same sit
Charlie Harrison 2016/04/20 12:36:43 Ok, I will update with a comment.
Charlie Harrison 2016/04/20 12:36:43 So actually the non cors perform a fetch() to the
+ const char* file_suffix) {
+ const GURL& base_url = target_test_server()->base_url();
+ std::string url = base::StringPrintf(
mmenke 2016/04/15 15:44:03 Not a url - this is a path. As-is, the GetURL(url
Charlie Harrison 2016/04/20 12:36:42 Done.
+ "/predictor/"
+ "predictor_cross_site%s.html?subresourceHost=%s&"
+ "numCORSResources=%d&numNonCORSResources=%d",
+ file_suffix, base_url.spec().c_str(), num_cors, num_non_cors);
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL(url));
+ bool result = false;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ browser()->tab_strip_model()->GetActiveWebContents(), "sendFetches()",
+ &result));
+ EXPECT_TRUE(result);
+ }
+
+ // Simulate the target server restarting. Delete all sockets and reset members
+ // tracking preconnects.
+ void ResetTarget() {
+ preconnected_target_ = 0;
+ target_test_server()->FlushAllSocketsAndConnectionsOnUIThread();
+ target_connection_listener_->ClearSockets();
+ EXPECT_EQ(0u, target_connection_listener_->GetAcceptedSocketCount());
+ }
+
+ static void AddUrlInterceptor(const GURL url) {
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ url, make_scoped_ptr(new NotFoundRequestInterceptor()));
+ }
+
const GURL startup_url_;
const GURL referring_url_;
const GURL target_url_;
- scoped_ptr<ConnectionListener> connection_listener_;
+ std::unique_ptr<ConnectionListener> connection_listener_;
+ std::unique_ptr<ConnectionListener> target_connection_listener_;
+
+ int source_target_learned_;
+ int preconnected_target_;
+ int preconnected_source_;
private:
scoped_refptr<HostResolutionRequestRecorder>
host_resolution_request_recorder_;
- scoped_ptr<net::ScopedDefaultHostResolverProc> scoped_host_resolver_proc_;
+ std::unique_ptr<net::ScopedDefaultHostResolverProc>
+ scoped_host_resolver_proc_;
+ std::unique_ptr<net::EmbeddedTestServer> target_test_server_;
mmenke 2016/04/15 15:44:02 Think this needs a comment. I suggest calling it
Charlie Harrison 2016/04/20 12:36:42 Done. Renamed to "cross_site_test_server".
};
+// Test the html test harness used to initiate cross site fetches. These
+// initiate cross site subresource requests (CORS and non-CORS) to the target
+// test server. Inspect the predictor's internal state to make sure that they
+// are properly logged.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteNonCORSUseOneSocket) {
+ NavigateToCrossSiteHTMLURL(0, 1, "");
mmenke 2016/04/15 15:44:03 Suggest you should add comments with the variable
Charlie Harrison 2016/04/20 12:36:42 Done.
+ EXPECT_EQ(1u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(1, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteNonCORSUseThreeSockets) {
+ NavigateToCrossSiteHTMLURL(0, 3, "");
+ EXPECT_EQ(3u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(3, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteCORSAndNonCORSUseOneSocket) {
+ NavigateToCrossSiteHTMLURL(1, 1, "");
mmenke 2016/04/15 20:27:17 Why do we care so much about the cors vs. non-cors
Charlie Harrison 2016/04/20 12:36:42 It was originally because these separate into priv
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(2, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteCORSUseTwoSockets) {
+ NavigateToCrossSiteHTMLURL(2, 0, "");
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(2, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, CrossSiteNoReferrerNoLearning) {
+ NavigateToCrossSiteHTMLURL(1, 0, "_no_referrer");
+ EXPECT_EQ(1u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+}
+
+// The following tests confirm that we accurately predict preconnects after
+// learning from navigations. Note that every "learned" connection adds ~.33 to
+// the expected connection number, which starts at 2. Every preconnect we
+// perform multiplies the expected connections by .66. One additional complexity
+// is that if we've learned to preconnect to host B on a navigation from host A,
+// we add a preconnect if the host part of A and B match (ignoring port). This
+// logic could probably be removed.
mmenke 2016/04/15 20:27:16 Oh wow...that's funky. Could we have a test where
Charlie Harrison 2016/04/20 12:36:43 Added a test using localhost.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteSimplePredictionAfterOneNavigation) {
+ NavigateToCrossSiteHTMLURL(2, 0, "");
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(2, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ // Navigate again and confirm we preconnect. Note that because the two
+ // embedded test servers have the same host_piece, we preconnect an additional
+ // time. This gives us ceil(2.66) + 1 = 4 preconnects.
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(4u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(4, preconnected_target_);
+}
+
+// Expect that the predictor correctly predicts subframe navigations.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SubframeCrossSitePrediction) {
+ ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL(
+ "/predictor/predictor_cross_site_subframe_nav.html"));
+ bool result = false;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ browser()->tab_strip_model()->GetActiveWebContents(),
+ base::StringPrintf(
+ "navigateSubframe('%s')",
+ target_test_server()->GetURL("/title1.html").spec().c_str()),
+ &result));
+ EXPECT_TRUE(result);
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(1, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ // Navigate again and confirm we preconnect. Note that because the two
+ // embedded test servers have the same host_piece, we preconnect an additional
+ // time. This gives us ceil(2 + .33) + 1 = 4 preconnects.
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(4u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(4, preconnected_target_);
mmenke 2016/04/15 20:27:17 How about also having a test where you just re-nav
Charlie Harrison 2016/04/20 12:36:42 Hm, so this test classifies the subframe as "subre
+}
+
+// This test navigates to an html file with a tag:
+// <meta name="referrer" content="never">
mmenke 2016/04/15 20:27:17 Is this really desired behavior, or just testing a
Charlie Harrison 2016/04/20 12:36:42 Well, the referrer tag is pretty architecturally i
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteNoReferrerNoPredictionAfterOneNavigation) {
+ NavigateToCrossSiteHTMLURL(2, 0, "_no_referrer");
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ // Navigate again and confirm that no preconnects occurred.
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(0u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, preconnected_target_);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteCORSSimplePredictionAfterTwoNavigations) {
+ NavigateToCrossSiteHTMLURL(0, 1, "");
+ NavigateToCrossSiteHTMLURL(0, 1, "");
+
+ ResetTarget();
+
+ // Navigate again and confirm we preconnect. Note that because the two
+ // embedded test servers have the same host_piece, we preconnect an additional
+ // time. This gives us (2 + .33)*.66 + .33 + 1 ~= 2.87.
mmenke 2016/04/15 20:27:17 nit: --we (x3). Well, one's an "us".
Charlie Harrison 2016/04/20 12:36:42 Done.
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(3u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(3, preconnected_target_);
+}
+
+IN_PROC_BROWSER_TEST_F(
+ PredictorBrowserTest,
+ CrossSiteCORSAndNonCORSSimplePredictionAfterTwoNavigations) {
+ NavigateToCrossSiteHTMLURL(1, 1, "");
+ NavigateToCrossSiteHTMLURL(1, 1, "");
+
+ ResetTarget();
+
+ // Navigate again and confirm we preconnect. Note that because the two
+ // embedded test servers have the same host_piece, we preconnect an additional
+ // time. This gives us (((2 + .66)*.66) + .66) + 1 ~= 3.4
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(4u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(4, preconnected_target_);
+}
+
+// The first navigation uses a subresource. Subsequent navigations don't use
+// that subresource. This tests how the predictor forgets about these bad
+// navigations.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ForgetBadPrediction) {
+ NavigateToCrossSiteHTMLURL(1, 0, "");
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ // ceil(2 + .33) + 1 = 4.
+ EXPECT_EQ(4u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(4, preconnected_target_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+
+ // ceil((2 + .33) * .66) + 1 = 3.
+ EXPECT_EQ(3u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(3, preconnected_target_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ // ceil((2 + .33) * .66 * .66) + 1 = 3.
+ EXPECT_EQ(3u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(3, preconnected_target_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ // Finally, (2 + .33) * .66^3 ~= .67. Not enough for a preconnect.
+ EXPECT_EQ(0u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, preconnected_target_);
+}
+
+// The predictor does not follow redirects if the original url had a non-empty
+// path (a path that was more than just "/").
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteRedirectNoPredictionWithPath) {
+ ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL(base::StringPrintf(
+ "/server-redirect?%s",
+ target_test_server()->GetURL("/title1.html").spec().c_str())));
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_EQ(0u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(0, preconnected_target_);
+}
+
+// The predictor does follow redirects if the original url had an empty path
+// (a path that was more than just "/"). Here we use the registered "/" path to
+// redirect to the target test server.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteRedirectPredictionWithNoPath) {
+ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
+ EXPECT_EQ(2u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(1, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ // We preconnect 4 sockets because ceil(2 + .33) + 1 = 4.
+ EXPECT_EQ(4u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(4, preconnected_target_);
+}
+
+// Perform the "/" redirect twice and make sure the predictor updates twice.
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ CrossSiteTwoRedirectsPredictionWithNoPath) {
+ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
+ EXPECT_EQ(1, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/"));
+ EXPECT_EQ(2, source_target_learned_);
+ EXPECT_EQ(2, preconnected_source_);
+
+ ResetTarget();
+
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+ // 3 preconnects expected because (2 + .33) * .66 + .33 + 1 ~= 2.87.
+ EXPECT_EQ(3u, target_connection_listener_->GetAcceptedSocketCount());
+ EXPECT_EQ(3, preconnected_target_);
+}
+
IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, PRE_ShutdownStartupCycle) {
// Prepare state that will be serialized on this shut-down and read on next
// start-up.
@@ -333,6 +701,7 @@ IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCycle) {
// But also make sure this data has been first loaded into the Predictor, by
// inspecting that the Predictor starts making the expected hostname requests.
+ predictor()->set_preconnect_enabled(false);
PrepareFrameSubresources(referring_url_);
WaitUntilHostHasBeenRequested(startup_url_.host());
WaitUntilHostHasBeenRequested(target_url_.host());

Powered by Google App Engine
This is Rietveld 408576698