Move predictor dns unit tests to browser tests
This patch moves some unit tests for the predictor to browser tests. This
is in preparation for a move where the predictor will call out to //content
for preresolve requests.
The patch also refactors how DNS browser tests work, where
we query off the predictor's observer.
BUG=610750,469120
Review-Url: https://codereview.chromium.org/1989363007
Cr-Commit-Position: refs/heads/master@{#396444}
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index f496d9c..4904ec1 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -1028,6 +1028,8 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LookupFinished(request, url, found);
+ if (observer_)
+ observer_->OnDnsLookupFinished(url, found);
pending_lookups_.erase(request);
delete request;
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h
index f9aa90a..300e341c 100644
--- a/chrome/browser/net/predictor.h
+++ b/chrome/browser/net/predictor.h
@@ -79,6 +79,8 @@
int count) {}
virtual void OnLearnFromNavigation(const GURL& referring_url,
const GURL& target_url) {}
+
+ virtual void OnDnsLookupFinished(const GURL& url, bool found) {}
};
// Predictor is constructed during Profile construction (on the UI thread),
@@ -317,11 +319,6 @@
}
private:
- FRIEND_TEST_ALL_PREFIXES(PredictorTest, BenefitLookupTest);
- FRIEND_TEST_ALL_PREFIXES(PredictorTest, ShutdownWhenResolutionIsPendingTest);
- FRIEND_TEST_ALL_PREFIXES(PredictorTest, SingleLookupTest);
- FRIEND_TEST_ALL_PREFIXES(PredictorTest, ConcurrentLookupTest);
- FRIEND_TEST_ALL_PREFIXES(PredictorTest, MassiveConcurrentLookupTest);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueuePushPopTest);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueueReorderTest);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, ReferrerSerializationTrimTest);
@@ -333,6 +330,7 @@
FRIEND_TEST_ALL_PREFIXES(PredictorTest, ProxyDefinitelyNotEnabled);
FRIEND_TEST_ALL_PREFIXES(PredictorTest, ProxyMaybeEnabled);
friend class WaitForResolutionHelper; // For testing.
+ friend class PredictorBrowserTest;
class LookupRequest;
@@ -423,25 +421,6 @@
// Number of referring URLs processed in an incremental trimming.
static const size_t kUrlsTrimmedPerIncrement;
- // Only for testing. Returns true if hostname has been successfully resolved
- // (name found).
- bool WasFound(const GURL& url) const {
- Results::const_iterator it(results_.find(url));
- return (it != results_.end()) &&
- it->second.was_found();
- }
-
- // Only for testing. Return how long was the resolution
- // or UrlInfo::NullDuration() if it hasn't been resolved yet.
- base::TimeDelta GetResolutionDuration(const GURL& url) {
- if (results_.find(url) == results_.end())
- return UrlInfo::NullDuration();
- return results_[url].resolve_duration();
- }
-
- // Only for testing;
- size_t peak_pending_lookups() const { return peak_pending_lookups_; }
-
// These two members call the appropriate global functions in
// prediction_options.cc depending on which thread they are called on.
virtual bool CanPrefetchAndPrerender() const;
diff --git a/chrome/browser/net/predictor_browsertest.cc b/chrome/browser/net/predictor_browsertest.cc
index be8568a..678d45d 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"
@@ -16,6 +17,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -83,12 +85,14 @@
}
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 kChromiumUrl[] = "http://chromium.org";
+const char kInvalidLongUrl[] =
+ "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 +249,6 @@
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 +294,8 @@
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 +335,16 @@
}
}
+ 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 +367,71 @@
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 ContainsKey(successful_dns_lookups_, url) ||
+ ContainsKey(unsuccessful_dns_lookups_, url);
+ }
+
+ 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 "
+ << url.spec();
+ return ContainsKey(successful_dns_lookups_, url);
+ }
+
+ 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 @@
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 @@
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 @@
switches::kEnableBlinkFeatures, kBlinkPreconnectFeature);
command_line->AppendSwitchASCII(switches::kEnableFeatures,
"PreconnectMore");
+ command_line->AppendSwitchASCII(switches::kEnableFeatures,
+ "UsePredictorDNSQueue");
}
void SetUpOnMainThread() override {
@@ -488,6 +509,7 @@
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 @@
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 @@
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 predictor's |results_| map. This
+ // 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_TRUE(ContainsKey(predictor()->results_, url));
+ }
+
+ 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 @@
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 @@
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, SingleLookupTest) {
+ DiscardAllResultsOnUIThread();
+ GURL url("http://www.example.test/");
+
+ // Try to flood the predictor with many concurrent requests.
+ network_hints::UrlList names{url};
+ FloodResolveRequestsOnUIThread(names);
+ observer()->WaitUntilHostLookedUp(url);
+ EXPECT_TRUE(observer()->HostFound(url));
+ ExpectValidPeakPendingLookupsOnUI(1u);
+}
+
+IN_PROC_BROWSER_TEST_F(PredictorBrowserTest, ConcurrentLookupTest) {
+ DiscardAllResultsOnUIThread();
+ GURL url("http://www.example.test"), goog2("http://gmail.google.com"),
+ goog3("http://mail.google.com"), goog4("http://gmail.com");
+ GURL bad1("http://bad1.notfound"), bad2("http://bad2.notfound");
+
+ UrlList found_names{url, goog3, goog2, goog4};
+ 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 @@
// 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(kChromiumUrl));
+ ASSERT_FALSE(observer()->HasHostBeenLookedUp(GURL(kInvalidLongUrl)));
+
+ EXPECT_FALSE(observer()->HostFound(GURL(kChromiumUrl)));
+ ASSERT_EQ(hosts_looked_up_before_load + 1, observer()->TotalHostsLookedUp());
}
// Tests that preconnect warms up a socket connection to a test server.
diff --git a/chrome/browser/net/predictor_unittest.cc b/chrome/browser/net/predictor_unittest.cc
index b6b13cc..c975a64 100644
--- a/chrome/browser/net/predictor_unittest.cc
+++ b/chrome/browser/net/predictor_unittest.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/net/predictor.h"
#include <stddef.h>
-#include <time.h>
#include <algorithm>
#include <memory>
@@ -18,17 +17,12 @@
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "base/timer/timer.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/net/url_info.h"
-#include "components/network_hints/common/network_hints_common.h"
#include "content/public/test/test_browser_thread.h"
-#include "net/base/address_list.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
-#include "net/base/winsock_init.h"
-#include "net/dns/mock_host_resolver.h"
#include "net/http/transport_security_state.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
@@ -41,234 +35,19 @@
namespace chrome_browser_net {
-class WaitForResolutionHelper;
-
-class WaitForResolutionHelper {
- public:
- WaitForResolutionHelper(Predictor* predictor,
- const UrlList& hosts,
- base::RepeatingTimer* timer,
- int checks_until_quit)
- : predictor_(predictor),
- hosts_(hosts),
- timer_(timer),
- checks_until_quit_(checks_until_quit) {}
-
- void CheckIfResolutionsDone() {
- if (--checks_until_quit_ > 0) {
- for (UrlList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
- if (predictor_->GetResolutionDuration(*i) ==
- UrlInfo::NullDuration())
- return; // We don't have resolution for that host.
- }
-
- // When all hostnames have been resolved, or we've hit the limit,
- // exit the loop.
- timer_->Stop();
- base::MessageLoop::current()->QuitWhenIdle();
- delete timer_;
- delete this;
- }
-
- private:
- Predictor* predictor_;
- const UrlList hosts_;
- base::RepeatingTimer* timer_;
- int checks_until_quit_;
-};
-
class PredictorTest : public testing::Test {
public:
PredictorTest()
: ui_thread_(BrowserThread::UI, &loop_),
- io_thread_(BrowserThread::IO, &loop_),
- host_resolver_(new net::MockCachingHostResolver()) {
- }
-
- protected:
- void SetUp() override {
-#if defined(OS_WIN)
- net::EnsureWinsockInit();
-#endif
- Predictor::set_max_parallel_resolves(
- Predictor::kMaxSpeculativeParallelResolves);
- Predictor::set_max_queueing_delay(
- Predictor::kMaxSpeculativeResolveQueueDelayMs);
- // Since we are using a caching HostResolver, the following latencies will
- // only be incurred by the first request, after which the result will be
- // cached internally by |host_resolver_|.
- net::RuleBasedHostResolverProc* rules = host_resolver_->rules();
- rules->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
- rules->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
- rules->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
- rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
- }
-
- void WaitForResolution(Predictor* predictor, const UrlList& hosts) {
- base::RepeatingTimer* timer = new base::RepeatingTimer();
- // By default allow the loop to run for a minute -- 600 iterations.
- timer->Start(FROM_HERE, TimeDelta::FromMilliseconds(100),
- new WaitForResolutionHelper(predictor, hosts, timer, 600),
- &WaitForResolutionHelper::CheckIfResolutionsDone);
- base::MessageLoop::current()->Run();
- }
-
- void WaitForResolutionWithLimit(
- Predictor* predictor, const UrlList& hosts, int limit) {
- base::RepeatingTimer* timer = new base::RepeatingTimer();
- timer->Start(FROM_HERE, TimeDelta::FromMilliseconds(100),
- new WaitForResolutionHelper(predictor, hosts, timer, limit),
- &WaitForResolutionHelper::CheckIfResolutionsDone);
- base::MessageLoop::current()->Run();
- }
+ io_thread_(BrowserThread::IO, &loop_) {}
private:
- // IMPORTANT: do not move this below |host_resolver_|; the host resolver
- // must not outlive the message loop, otherwise bad things can happen
- // (like posting to a deleted message loop).
base::MessageLoopForUI loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread io_thread_;
-
- protected:
- std::unique_ptr<net::MockCachingHostResolver> host_resolver_;
};
//------------------------------------------------------------------------------
-
-TEST_F(PredictorTest, StartupShutdownTest) {
- Predictor testing_master(true, true);
- testing_master.Shutdown();
-}
-
-
-TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
- std::unique_ptr<net::HostResolver> host_resolver(
- new net::HangingHostResolver());
-
- Predictor testing_master(true, true);
- testing_master.SetHostResolver(host_resolver.get());
-
- GURL localhost("http://localhost:80");
- UrlList names;
- names.push_back(localhost);
-
- testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
- base::TimeDelta::FromMilliseconds(500));
- base::MessageLoop::current()->Run();
-
- EXPECT_FALSE(testing_master.WasFound(localhost));
-
- testing_master.Shutdown();
-
- // Clean up after ourselves.
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-TEST_F(PredictorTest, SingleLookupTest) {
- Predictor testing_master(true, true);
- testing_master.SetHostResolver(host_resolver_.get());
-
- GURL goog("http://www.google.com:80");
-
- UrlList names;
- names.push_back(goog);
-
- // Try to flood the predictor with many concurrent requests.
- for (int i = 0; i < 10; i++)
- testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- WaitForResolution(&testing_master, names);
-
- EXPECT_TRUE(testing_master.WasFound(goog));
-
- base::MessageLoop::current()->RunUntilIdle();
-
- EXPECT_GT(testing_master.peak_pending_lookups(), names.size() / 2);
- EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master.peak_pending_lookups(),
- testing_master.max_concurrent_dns_lookups());
-
- testing_master.Shutdown();
-}
-
-TEST_F(PredictorTest, ConcurrentLookupTest) {
- host_resolver_->rules()->AddSimulatedFailure("*.notfound");
-
- Predictor testing_master(true, true);
- testing_master.SetHostResolver(host_resolver_.get());
-
- GURL goog("http://www.google.com:80"),
- goog2("http://gmail.google.com.com:80"),
- goog3("http://mail.google.com:80"),
- goog4("http://gmail.com:80");
- GURL bad1("http://bad1.notfound:80"),
- bad2("http://bad2.notfound:80");
-
- UrlList names;
- names.push_back(goog);
- names.push_back(goog3);
- names.push_back(bad1);
- names.push_back(goog2);
- names.push_back(bad2);
- names.push_back(goog4);
- names.push_back(goog);
-
- // Try to flood the predictor with many concurrent requests.
- for (int i = 0; i < 10; i++)
- testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- WaitForResolution(&testing_master, names);
-
- EXPECT_TRUE(testing_master.WasFound(goog));
- EXPECT_TRUE(testing_master.WasFound(goog3));
- EXPECT_TRUE(testing_master.WasFound(goog2));
- EXPECT_TRUE(testing_master.WasFound(goog4));
- EXPECT_FALSE(testing_master.WasFound(bad1));
- EXPECT_FALSE(testing_master.WasFound(bad2));
-
- base::MessageLoop::current()->RunUntilIdle();
-
- EXPECT_FALSE(testing_master.WasFound(bad1));
- EXPECT_FALSE(testing_master.WasFound(bad2));
-
- EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master.peak_pending_lookups(),
- testing_master.max_concurrent_dns_lookups());
-
- testing_master.Shutdown();
-}
-
-TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
- host_resolver_->rules()->AddSimulatedFailure("*.notfound");
-
- Predictor testing_master(true, true);
- testing_master.SetHostResolver(host_resolver_.get());
-
- UrlList names;
- for (int i = 0; i < 100; i++)
- names.push_back(GURL(
- "http://host" + base::IntToString(i) + ".notfound:80"));
-
- // Try to flood the predictor with many concurrent requests.
- for (int i = 0; i < 10; i++)
- testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- WaitForResolution(&testing_master, names);
-
- base::MessageLoop::current()->RunUntilIdle();
-
- EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
- EXPECT_LE(testing_master.peak_pending_lookups(),
- testing_master.max_concurrent_dns_lookups());
-
- testing_master.Shutdown();
-}
-
-//------------------------------------------------------------------------------
// Functions to help synthesize and test serializations of subresource referrer
// lists.
@@ -365,12 +144,14 @@
return false;
}
-//------------------------------------------------------------------------------
+TEST_F(PredictorTest, StartupShutdownTest) {
+ Predictor testing_master(true, true);
+ testing_master.Shutdown();
+}
// Make sure nil referral lists really have no entries, and no latency listed.
TEST_F(PredictorTest, ReferrerSerializationNilTest) {
Predictor predictor(true, true);
- predictor.SetHostResolver(host_resolver_.get());
std::unique_ptr<base::ListValue> referral_list(NewEmptySerializationList());
predictor.SerializeReferrers(referral_list.get());
@@ -387,7 +168,6 @@
// serialization without being changed.
TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
Predictor predictor(true, true);
- predictor.SetHostResolver(host_resolver_.get());
const GURL motivation_url("http://www.google.com:91");
const GURL subresource_url("http://icons.google.com:90");
const double kUseRate = 23.4;
@@ -414,7 +194,6 @@
// correct order.
TEST_F(PredictorTest, GetHtmlReferrerLists) {
Predictor predictor(true, true);
- predictor.SetHostResolver(host_resolver_.get());
const double kUseRate = 23.4;
std::unique_ptr<base::ListValue> referral_list(NewEmptySerializationList());
@@ -499,7 +278,6 @@
// Make sure the Trim() functionality works as expected.
TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
Predictor predictor(true, true);
- predictor.SetHostResolver(host_resolver_.get());
GURL motivation_url("http://www.google.com:110");
GURL icon_subresource_url("http://icons.google.com:111");
@@ -688,7 +466,6 @@
TEST_F(PredictorTest, DiscardPredictorResults) {
SimplePredictor predictor(true, true);
- predictor.SetHostResolver(host_resolver_.get());
base::ListValue referral_list;
predictor.SerializeReferrers(&referral_list);
EXPECT_EQ(1U, referral_list.GetSize());