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

Unified Diff: chrome/browser/net/predictor_browsertest.cc

Issue 1989363007: Move predictor dns unit tests to browser tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/net/predictor_browsertest.cc
diff --git a/chrome/browser/net/predictor_browsertest.cc b/chrome/browser/net/predictor_browsertest.cc
index be8568ae32814a97956936b9c6ac16cc3cb4b7b7..cc4718f7c3d664ba83f09894a0fa2c3292c1c9bf 100644
--- a/chrome/browser/net/predictor_browsertest.cc
+++ b/chrome/browser/net/predictor_browsertest.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <memory>
+#include <set>
#include "base/base64.h"
#include "base/bind.h"
@@ -83,12 +84,14 @@ std::unique_ptr<net::test_server::HttpResponse> RedirectForPathHandler(
}
const char kBlinkPreconnectFeature[] = "LinkPreconnect";
-const char kChromiumHostname[] = "chromium.org";
-const char kInvalidLongHostname[] = "illegally-long-hostname-over-255-"
- "characters-should-not-send-an-ipc-message-to-the-browser-"
- "0000000000000000000000000000000000000000000000000000000000000000000000000"
- "0000000000000000000000000000000000000000000000000000000000000000000000000"
- "000000000000000000000000000000000000000000000000000000.org";
+const char kChromiumHost[] = "http://chromium.org";
eroman 2016/05/27 00:56:38 nit: Can you call this a "url" or "origin" now?
Charlie Harrison 2016/05/27 11:55:53 Done.
+const char kInvalidLongHost[] =
eroman 2016/05/27 00:56:38 same
Charlie Harrison 2016/05/27 11:55:53 Done.
+ "http://"
+ "illegally-long-hostname-over-255-characters-should-not-send-an-ipc-"
+ "message-to-the-browser-"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000.org";
// Gets notified by the EmbeddedTestServer on incoming connections being
// accepted or read from, keeps track of them and exposes that info to
@@ -245,78 +248,6 @@ class ConnectionListener
DISALLOW_COPY_AND_ASSIGN(ConnectionListener);
};
-// Records a history of all hostnames for which resolving has been requested,
-// and immediately fails the resolution requests themselves.
-class HostResolutionRequestRecorder : public net::HostResolverProc {
- public:
- HostResolutionRequestRecorder()
- : HostResolverProc(NULL),
- is_waiting_for_hostname_(false) {
- }
-
- int Resolve(const std::string& host,
- net::AddressFamily address_family,
- net::HostResolverFlags host_resolver_flags,
- net::AddressList* addrlist,
- int* os_error) override {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&HostResolutionRequestRecorder::AddToHistory,
- base::Unretained(this),
- host));
- return net::ERR_NAME_NOT_RESOLVED;
- }
-
- int RequestedHostnameCount() const {
- return requested_hostnames_.size();
- }
-
- bool HasHostBeenRequested(const std::string& hostname) const {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return std::find(requested_hostnames_.begin(),
- requested_hostnames_.end(),
- hostname) != requested_hostnames_.end();
- }
-
- void WaitUntilHostHasBeenRequested(const std::string& hostname) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(!is_waiting_for_hostname_);
- if (HasHostBeenRequested(hostname))
- return;
- waiting_for_hostname_ = hostname;
- is_waiting_for_hostname_ = true;
- content::RunMessageLoop();
- }
-
- private:
- ~HostResolutionRequestRecorder() override {}
-
- void AddToHistory(const std::string& hostname) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- requested_hostnames_.push_back(hostname);
- if (is_waiting_for_hostname_ && waiting_for_hostname_ == hostname) {
- is_waiting_for_hostname_ = false;
- waiting_for_hostname_.clear();
- base::MessageLoop::current()->QuitWhenIdle();
- }
- }
-
- // The hostname which WaitUntilHostHasBeenRequested is currently waiting for
- // to be requested.
- std::string waiting_for_hostname_;
-
- // Whether WaitUntilHostHasBeenRequested is waiting for a hostname to be
- // requested and thus is running a nested message loop.
- bool is_waiting_for_hostname_;
-
- // A list of hostnames for which resolution has already been requested. Only
- // to be accessed from the UI thread.
- std::vector<std::string> requested_hostnames_;
-
- DISALLOW_COPY_AND_ASSIGN(HostResolutionRequestRecorder);
-};
-
// This class intercepts URLRequests and responds with the URLRequestJob*
// callback provided by the constructor. Note that the port of the URL must
// match the port given in the constructor.
@@ -362,7 +293,8 @@ class CrossSitePredictorObserver
cross_site_host_(cross_site_host),
cross_site_learned_(0),
cross_site_preconnected_(0),
- same_site_preconnected_(0) {}
+ same_site_preconnected_(0),
+ dns_run_loop_(nullptr) {}
void OnPreconnectUrl(
const GURL& original_url,
@@ -402,6 +334,16 @@ class CrossSitePredictorObserver
}
}
+ void OnDnsLookupFinished(const GURL& url, bool found) override {
+ base::AutoLock lock(lock_);
+ if (found) {
+ successful_dns_lookups_.insert(url);
+ } else {
+ unsuccessful_dns_lookups_.insert(url);
+ }
+ CheckForWaitingLoop();
+ }
+
void ResetCounts() {
base::AutoLock lock(lock_);
cross_site_learned_ = 0;
@@ -424,10 +366,72 @@ class CrossSitePredictorObserver
return same_site_preconnected_;
}
+ // Spins a run loop until |url| is added to one of the lookup maps.
+ void WaitUntilHostLookedUp(const GURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::RunLoop run_loop;
+ {
+ base::AutoLock lock(lock_);
+ DCHECK(waiting_on_dns_.is_empty());
+ DCHECK(!dns_run_loop_);
+ waiting_on_dns_ = url;
+ dns_run_loop_ = &run_loop;
+ CheckForWaitingLoop();
+ }
+ run_loop.Run();
+ }
+
+ bool HasHostBeenLookedUpLocked(const GURL& url) {
+ lock_.AssertAcquired();
+ return successful_dns_lookups_.find(url) != successful_dns_lookups_.end() ||
eroman 2016/05/27 00:56:38 optional: can use ContainsKey() to simplify the va
Charlie Harrison 2016/05/27 11:55:52 Done.
+ unsuccessful_dns_lookups_.find(url) !=
+ unsuccessful_dns_lookups_.end();
+ }
+
+ bool HasHostBeenLookedUp(const GURL& url) {
+ base::AutoLock lock(lock_);
+ return HasHostBeenLookedUpLocked(url);
+ }
+
+ void CheckForWaitingLoop() {
+ lock_.AssertAcquired();
+ if (waiting_on_dns_.is_empty())
+ return;
+ if (!HasHostBeenLookedUpLocked(waiting_on_dns_))
+ return;
+ DCHECK(dns_run_loop_);
+ DCHECK(task_runner_);
+ waiting_on_dns_ = GURL();
+ task_runner_->PostTask(FROM_HERE, dns_run_loop_->QuitClosure());
+ dns_run_loop_ = nullptr;
+ }
+
+ size_t TotalHostsLookedUp() {
+ base::AutoLock lock(lock_);
+ return successful_dns_lookups_.size() + unsuccessful_dns_lookups_.size();
+ }
+
+ // Note: this method expects the URL to have been looked up.
+ bool HostFound(const GURL& url) {
+ base::AutoLock lock(lock_);
+ EXPECT_TRUE(HasHostBeenLookedUpLocked(url)) << "Expected to have looked up"
eroman 2016/05/27 00:56:38 nit: add a space at the end of the string.
Charlie Harrison 2016/05/27 11:55:53 Done.
+ << url.spec();
+ return successful_dns_lookups_.find(url) != successful_dns_lookups_.end();
+ }
+
+ void set_task_runner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ task_runner_.swap(task_runner);
+ }
+
private:
const GURL source_host_;
const GURL cross_site_host_;
+ GURL waiting_on_dns_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
// Protects all following members. They are read and updated from different
// threads.
base::Lock lock_;
@@ -436,6 +440,10 @@ class CrossSitePredictorObserver
int cross_site_preconnected_;
int same_site_preconnected_;
+ std::set<GURL> successful_dns_lookups_;
+ std::set<GURL> unsuccessful_dns_lookups_;
+ base::RunLoop* dns_run_loop_;
+
DISALLOW_COPY_AND_ASSIGN(CrossSitePredictorObserver);
};
@@ -446,16 +454,27 @@ namespace chrome_browser_net {
class PredictorBrowserTest : public InProcessBrowserTest {
public:
PredictorBrowserTest()
- : startup_url_("http://host1:1"),
- referring_url_("http://host2:1"),
- target_url_("http://host3:1"),
- host_resolution_request_recorder_(new HostResolutionRequestRecorder),
- cross_site_test_server_(new net::EmbeddedTestServer()) {}
+ : startup_url_("http://host1/"),
+ referring_url_("http://host2/"),
+ target_url_("http://host3/"),
+ rule_based_resolver_proc_(new net::RuleBasedHostResolverProc(nullptr)),
+ cross_site_test_server_(new net::EmbeddedTestServer()) {
+ rule_based_resolver_proc_->AddRuleWithLatency("www.example.test",
+ "127.0.0.1", 50);
+ rule_based_resolver_proc_->AddRuleWithLatency("gmail.google.com",
+ "127.0.0.1", 70);
+ rule_based_resolver_proc_->AddRuleWithLatency("mail.google.com",
+ "127.0.0.1", 44);
+ rule_based_resolver_proc_->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
+ rule_based_resolver_proc_->AddSimulatedFailure("*.notfound");
+ rule_based_resolver_proc_->AddRuleWithLatency("delay.google.com",
+ "127.0.0.1", 1000 * 60);
+ }
protected:
void SetUpInProcessBrowserTestFixture() override {
scoped_host_resolver_proc_.reset(new net::ScopedDefaultHostResolverProc(
- host_resolution_request_recorder_.get()));
+ rule_based_resolver_proc_.get()));
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
}
@@ -466,6 +485,8 @@ class PredictorBrowserTest : public InProcessBrowserTest {
switches::kEnableBlinkFeatures, kBlinkPreconnectFeature);
command_line->AppendSwitchASCII(switches::kEnableFeatures,
"PreconnectMore");
+ command_line->AppendSwitchASCII(switches::kEnableFeatures,
+ "UsePredictorDNSQueue");
}
void SetUpOnMainThread() override {
@@ -488,6 +509,7 @@ class PredictorBrowserTest : public InProcessBrowserTest {
predictor()->SetPreconnectEnabledForTest(true);
InstallPredictorObserver(embedded_test_server()->base_url(),
cross_site_test_server()->base_url());
+ observer()->set_task_runner(task_runner_);
StartInterceptingCrossSiteOnUI();
}
@@ -573,16 +595,24 @@ class PredictorBrowserTest : public InProcessBrowserTest {
serializer.Serialize(*list_value);
}
- bool HasHostBeenRequested(const std::string& hostname) const {
- return host_resolution_request_recorder_->HasHostBeenRequested(hostname);
+ void WaitUntilHostsLookedUp(const network_hints::UrlList& names) {
+ for (const GURL& url : names)
+ observer()->WaitUntilHostLookedUp(url);
}
- void WaitUntilHostHasBeenRequested(const std::string& hostname) {
- host_resolution_request_recorder_->WaitUntilHostHasBeenRequested(hostname);
+ void FloodResolveRequestsOnUIThread(const network_hints::UrlList& names) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PredictorBrowserTest::FloodResolveRequests, this, names));
}
- int RequestedHostnameCount() const {
- return host_resolution_request_recorder_->RequestedHostnameCount();
+ void FloodResolveRequests(const network_hints::UrlList& names) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (int i = 0; i < 10; i++) {
+ predictor()->DnsPrefetchMotivatedList(names,
+ UrlInfo::PAGE_SCAN_MOTIVATED);
+ }
}
net::EmbeddedTestServer* cross_site_test_server() {
@@ -639,6 +669,56 @@ class PredictorBrowserTest : public InProcessBrowserTest {
EXPECT_TRUE(test_server->FlushAllSocketsAndConnectionsOnUIThread());
}
+ // Note this method also expects that all the urls (found or not) were looked
+ // up.
+ void ExpectFoundUrls(
+ const network_hints::UrlList& found_names,
+ const network_hints::UrlList& not_found_names) {
+ for (const auto& name : found_names) {
+ EXPECT_TRUE(observer()->HostFound(name)) << "Expected to have found "
+ << name.spec();
+ }
+ for (const auto& name : not_found_names) {
+ EXPECT_FALSE(observer()->HostFound(name)) << "Did not expect to find "
+ << name.spec();
+ }
+ }
+
+ // This method verifies that |url| is in the predictors |results_| map. This
eroman 2016/05/27 00:56:38 nit: predictors --> predictor's
Charlie Harrison 2016/05/27 11:55:52 Done.
+ // is used for pending lookups, and lookups performed before the observer is
+ // attached.
+ void ExpectUrlRequestedFromPredictorOnUIThread(const GURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PredictorBrowserTest::ExpectUrlRequestedFromPredictor,
+ base::Unretained(this), url));
+ }
+
+ void ExpectUrlRequestedFromPredictor(const GURL& url) {
+ EXPECT_NE(predictor()->results_.find(url), predictor()->results_.end());
+ }
+
+ void DiscardAllResultsOnUIThread() {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&Predictor::DiscardAllResults,
+ base::Unretained(predictor())));
+ }
+
+ void ExpectValidPeakPendingLookupsOnUI(size_t num_names_requested) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PredictorBrowserTest::ExpectValidPeakPendingLookups,
+ base::Unretained(this), num_names_requested));
+ }
+
+ void ExpectValidPeakPendingLookups(size_t num_names_requested) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ EXPECT_LE(predictor()->peak_pending_lookups_, num_names_requested);
+ EXPECT_LE(predictor()->peak_pending_lookups_,
+ predictor()->max_concurrent_dns_lookups());
+ }
+
CrossSitePredictorObserver* observer() { return observer_.get(); }
// Navigate to an html file on embedded_test_server and tell it to request
@@ -669,8 +749,7 @@ class PredictorBrowserTest : public InProcessBrowserTest {
std::unique_ptr<ConnectionListener> cross_site_connection_listener_;
private:
- scoped_refptr<HostResolutionRequestRecorder>
- host_resolution_request_recorder_;
+ scoped_refptr<net::RuleBasedHostResolverProc> rule_based_resolver_proc_;
std::unique_ptr<net::ScopedDefaultHostResolverProc>
scoped_host_resolver_proc_;
std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_;
@@ -678,6 +757,66 @@ class PredictorBrowserTest : public InProcessBrowserTest {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SingleLookupTest) {
+ DiscardAllResultsOnUIThread();
+ GURL goog("http://www.example.test/");
eroman 2016/05/27 00:56:38 probably better to call this "url" -- not actually
Charlie Harrison 2016/05/27 11:55:53 Done.
+
+ // Try to flood the predictor with many concurrent requests.
+ network_hints::UrlList names{goog};
+ FloodResolveRequestsOnUIThread(names);
+ observer()->WaitUntilHostLookedUp(goog);
+ EXPECT_TRUE(observer()->HostFound(goog));
+ ExpectValidPeakPendingLookupsOnUI(1u);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ConcurrentLookupTest) {
+ DiscardAllResultsOnUIThread();
+ GURL goog("http://www.example.test"), goog2("http://gmail.google.com"),
eroman 2016/05/27 00:56:38 same here -- at least for one of them.
Charlie Harrison 2016/05/27 11:55:53 Done.
+ goog3("http://mail.google.com"), goog4("http://gmail.com");
+ GURL bad1("http://bad1.notfound"), bad2("http://bad2.notfound");
+
+ UrlList found_names{goog, goog3, goog2, goog4, goog};
+ UrlList not_found_names{bad1, bad2};
+ FloodResolveRequestsOnUIThread(found_names);
+ FloodResolveRequestsOnUIThread(not_found_names);
+
+ WaitUntilHostsLookedUp(found_names);
+ WaitUntilHostsLookedUp(not_found_names);
+ ExpectFoundUrls(found_names, not_found_names);
+ ExpectValidPeakPendingLookupsOnUI(found_names.size() +
+ not_found_names.size());
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, MassiveConcurrentLookupTest) {
+ DiscardAllResultsOnUIThread();
+ UrlList not_found_names;
+ for (int i = 0; i < 100; i++) {
+ not_found_names.push_back(
+ GURL(base::StringPrintf("http://host%d.notfound:80", i)));
+ }
+ FloodResolveRequestsOnUIThread(not_found_names);
+
+ WaitUntilHostsLookedUp(not_found_names);
+ ExpectFoundUrls(network_hints::UrlList(), not_found_names);
+ ExpectValidPeakPendingLookupsOnUI(not_found_names.size());
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest,
+ ShutdownWhenResolutionIsPendingTest) {
+ GURL delayed_url("http://delay.google.com:80");
+ UrlList names{delayed_url};
+
+ // Flood with delayed requests, then wait.
+ FloodResolveRequestsOnUIThread(names);
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ base::TimeDelta::FromMilliseconds(500));
+ base::MessageLoop::current()->Run();
+
+ ExpectUrlRequestedFromPredictor(delayed_url);
+ EXPECT_FALSE(observer()->HasHostBeenLookedUp(delayed_url));
+}
+
IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SimplePreconnectOne) {
predictor()->PreconnectUrl(
embedded_test_server()->base_url(), GURL(),
@@ -1128,24 +1267,28 @@ IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ShutdownStartupCyclePreresolve) {
// But also make sure this data has been first loaded into the Predictor, by
// inspecting that the Predictor starts making the expected hostname requests.
PrepareFrameSubresources(referring_url_);
- WaitUntilHostHasBeenRequested(startup_url_.host());
- WaitUntilHostHasBeenRequested(target_url_.host());
+ observer()->WaitUntilHostLookedUp(target_url_);
+
+ // Verify that both urls were requested by the predictor. Note that the
+ // startup URL may be requested before the observer attaches itself.
+ ExpectUrlRequestedFromPredictor(startup_url_);
+ EXPECT_FALSE(observer()->HostFound(target_url_));
}
-// Flaky on Windows: http://crbug.com/469120
-#if defined(OS_WIN)
-#define MAYBE_DnsPrefetch DISABLED_DnsPrefetch
-#else
-#define MAYBE_DnsPrefetch DnsPrefetch
-#endif
-IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, MAYBE_DnsPrefetch) {
- int hostnames_requested_before_load = RequestedHostnameCount();
- ui_test_utils::NavigateToURL(
- browser(),
- GURL(embedded_test_server()->GetURL("/predictor/dns_prefetch.html")));
- WaitUntilHostHasBeenRequested(kChromiumHostname);
- ASSERT_FALSE(HasHostBeenRequested(kInvalidLongHostname));
- ASSERT_EQ(hostnames_requested_before_load + 1, RequestedHostnameCount());
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, DnsPrefetch) {
+ // Navigate once to make sure all initial hostnames are requested.
+ ui_test_utils::NavigateToURL(browser(),
+ embedded_test_server()->GetURL("/title1.html"));
+
+ size_t hosts_looked_up_before_load = observer()->TotalHostsLookedUp();
+
+ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
+ "/predictor/dns_prefetch.html"));
+ observer()->WaitUntilHostLookedUp(GURL(kChromiumHost));
+ ASSERT_FALSE(observer()->HasHostBeenLookedUp(GURL(kInvalidLongHost)));
+
+ EXPECT_FALSE(observer()->HostFound(GURL(kChromiumHost)));
+ ASSERT_EQ(hosts_looked_up_before_load + 1, observer()->TotalHostsLookedUp());
}
// Tests that preconnect warms up a socket connection to a test server.
« no previous file with comments | « chrome/browser/net/predictor.cc ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698