Index: net/url_request/url_fetcher_impl_unittest.cc |
diff --git a/net/url_request/url_fetcher_impl_unittest.cc b/net/url_request/url_fetcher_impl_unittest.cc |
index 1c6b77b71f7143ec3a7bbdb4a671a16b394893bd..1a9260f192e0e1633fbfcdc137272e6f647b5ac2 100644 |
--- a/net/url_request/url_fetcher_impl_unittest.cc |
+++ b/net/url_request/url_fetcher_impl_unittest.cc |
@@ -10,10 +10,13 @@ |
#include "base/file_util.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/message_loop_proxy.h" |
+#include "base/stringprintf.h" |
#include "base/synchronization/waitable_event.h" |
#include "base/threading/thread.h" |
#include "build/build_config.h" |
#include "crypto/nss_util.h" |
+#include "net/base/mock_host_resolver.h" |
+#include "net/base/network_change_notifier.h" |
#include "net/http/http_response_headers.h" |
#include "net/test/test_server.h" |
#include "net/url_request/url_fetcher_delegate.h" |
@@ -72,6 +75,24 @@ class ThrottlingTestURLRequestContextGetter |
TestURLRequestContext* const context_; |
}; |
+class TestNetworkChangeNotifier : public NetworkChangeNotifier { |
pauljensen
2012/12/07 23:00:05
Using GMOCK for this might be a few lines shorter,
Joao da Silva
2012/12/10 15:32:42
These tests still need to invoke NotifyObserversOf
|
+ public: |
+ TestNetworkChangeNotifier() : connection_type_(CONNECTION_UNKNOWN) {} |
+ |
+ // Implementation of NetworkChangeNotifier: |
+ virtual ConnectionType GetCurrentConnectionType() const OVERRIDE { |
+ return connection_type_; |
+ } |
+ |
+ void SetCurrentConnectionType(ConnectionType type) { |
+ connection_type_ = type; |
+ NotifyObserversOfConnectionTypeChange(); |
+ } |
+ |
+ private: |
+ ConnectionType connection_type_; |
+}; |
+ |
} // namespace |
class URLFetcherTest : public testing::Test, |
@@ -106,6 +127,11 @@ class URLFetcherTest : public testing::Test, |
return context_.get(); |
} |
+ void UseTestNetworkChangeNotifier() { |
+ disable_default_notifier_.reset(new NetworkChangeNotifier::DisableForTest); |
+ network_change_notifier_.reset(new TestNetworkChangeNotifier); |
pauljensen
2012/12/07 23:00:05
Could |disable_default_notifier_| and |network_cha
Joao da Silva
2012/12/10 15:32:42
Done.
Joao da Silva
2012/12/10 15:32:42
Done.
|
+ } |
+ |
protected: |
// testing::Test: |
virtual void SetUp() OVERRIDE { |
@@ -132,14 +158,16 @@ class URLFetcherTest : public testing::Test, |
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; |
URLFetcherImpl* fetcher_; |
- const scoped_ptr<TestURLRequestContext> context_; |
+ scoped_ptr<TestURLRequestContext> context_; |
+ |
+ scoped_ptr<NetworkChangeNotifier::DisableForTest> disable_default_notifier_; |
+ scoped_ptr<TestNetworkChangeNotifier> network_change_notifier_; |
}; |
void URLFetcherTest::CreateFetcher(const GURL& url) { |
fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); |
fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( |
io_message_loop_proxy(), request_context())); |
- fetcher_->Start(); |
} |
void URLFetcherTest::OnURLFetchComplete(const URLFetcher* source) { |
@@ -165,6 +193,21 @@ void URLFetcherTest::CleanupAfterFetchComplete() { |
namespace { |
+class URLFetcherMockDNSTest : public URLFetcherTest { |
+ public: |
+ // testing::Test: |
+ virtual void SetUp() OVERRIDE; |
+ |
+ // URLFetcherDelegate: |
+ virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE; |
+ |
+ protected: |
+ GURL test_url_; |
+ scoped_ptr<TestServer> test_server_; |
+ MockHostResolver resolver_; |
+ scoped_ptr<URLFetcher> completed_fetcher_; |
+}; |
+ |
// Version of URLFetcherTest that does a POST instead |
class URLFetcherPostTest : public URLFetcherTest { |
public: |
@@ -426,6 +469,42 @@ class URLFetcherFileTest : public URLFetcherTest { |
base::PlatformFileError expected_file_error_; |
}; |
+void URLFetcherMockDNSTest::SetUp() { |
+ URLFetcherTest::SetUp(); |
+ |
+ context_.reset(); |
+ UseTestNetworkChangeNotifier(); |
+ ASSERT_TRUE(network_change_notifier_); |
+ |
+ resolver_.set_synchronous_mode(false); |
+ resolver_.set_resolve_automatically(false); |
+ resolver_.rules()->AddRule("example.com", "127.0.0.1"); |
+ |
+ context_.reset(new TestURLRequestContext(true)); |
+ context_->set_host_resolver(&resolver_); |
+ context_->Init(); |
+ |
+ test_server_.reset(new TestServer(TestServer::TYPE_HTTP, |
+ TestServer::kLocalhost, |
+ FilePath(kDocRoot))); |
+ ASSERT_TRUE(test_server_->Start()); |
+ |
+ // test_server_.GetURL() returns a URL with 127.0.0.1 (kLocalhost), that is |
+ // immediately resolved by the MockHostResolver. Use a hostname instead to |
+ // trigger an async resolve. |
+ test_url_ = GURL( |
+ base::StringPrintf("http://example.com:%d/defaultresponse", |
+ test_server_->host_port_pair().port())); |
+ ASSERT_TRUE(test_url_.is_valid()); |
+} |
+ |
+void URLFetcherMockDNSTest::OnURLFetchComplete(const URLFetcher* source) { |
+ io_message_loop_proxy()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
+ ASSERT_EQ(fetcher_, source); |
+ EXPECT_EQ(test_url_, source->GetOriginalURL()); |
+ completed_fetcher_.reset(fetcher_); |
+} |
+ |
void URLFetcherPostTest::CreateFetcher(const GURL& url) { |
fetcher_ = new URLFetcherImpl(url, URLFetcher::POST, this); |
fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( |
@@ -828,6 +907,169 @@ TEST_F(URLFetcherTest, CancelAll) { |
delete fetcher_; |
} |
+TEST_F(URLFetcherMockDNSTest, DontRetryOnNetworkChangedByDefault) { |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ |
+ // This posts a task to start the fetcher. |
+ CreateFetcher(test_url_); |
+ fetcher_->Start(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // The fetcher is now running, but is pending the host resolve. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ |
+ // A network change notification aborts the connect job. |
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); |
+ MessageLoop::current()->RunUntilIdle(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ ASSERT_TRUE(completed_fetcher_); |
+ |
+ // And the owner of the fetcher gets the ERR_NETWORK_CHANGED error. |
+ EXPECT_EQ(ERR_NETWORK_CHANGED, completed_fetcher_->GetStatus().error()); |
+} |
+ |
+TEST_F(URLFetcherMockDNSTest, RetryOnNetworkChangedAndFail) { |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ |
+ // This posts a task to start the fetcher. |
+ CreateFetcher(test_url_); |
+ fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); |
+ fetcher_->Start(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // The fetcher is now running, but is pending the host resolve. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ |
+ // Make it fail 3 times. |
+ for (int i = 0; i < 3; ++i) { |
+ // A network change notification aborts the connect job. |
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // But the fetcher retries automatically. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ } |
+ |
+ // A 4th failure doesn't trigger another retry, and propagates the error |
+ // to the owner of the fetcher. |
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); |
+ MessageLoop::current()->RunUntilIdle(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ ASSERT_TRUE(completed_fetcher_); |
+ |
+ // And the owner of the fetcher gets the ERR_NETWORK_CHANGED error. |
+ EXPECT_EQ(ERR_NETWORK_CHANGED, completed_fetcher_->GetStatus().error()); |
+} |
+ |
+TEST_F(URLFetcherMockDNSTest, RetryOnNetworkChangedAndSucceed) { |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ |
+ // This posts a task to start the fetcher. |
+ CreateFetcher(test_url_); |
+ fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); |
+ fetcher_->Start(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // The fetcher is now running, but is pending the host resolve. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ |
+ // Make it fail 3 times. |
+ for (int i = 0; i < 3; ++i) { |
+ // A network change notification aborts the connect job. |
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // But the fetcher retries automatically. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ } |
+ |
+ // Now let it succeed by resolving the pending request. |
+ resolver_.ResolveAllPending(); |
+ MessageLoop::current()->Run(); |
+ |
+ // URLFetcherMockDNSTest::OnURLFetchComplete() will quit the loop. |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ ASSERT_TRUE(completed_fetcher_); |
+ |
+ // This time the request succeeded. |
+ EXPECT_EQ(OK, completed_fetcher_->GetStatus().error()); |
+ EXPECT_EQ(200, completed_fetcher_->GetResponseCode()); |
+} |
+ |
+TEST_F(URLFetcherMockDNSTest, RetryAfterComingBackOnline) { |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ |
+ // This posts a task to start the fetcher. |
+ CreateFetcher(test_url_); |
+ fetcher_->SetAutomaticallyRetryOnNetworkChanges(1); |
+ fetcher_->Start(); |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // The fetcher is now running, but is pending the host resolve. |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ |
+ // Make it fail by changing the connection type to offline. |
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, |
+ NetworkChangeNotifier::GetConnectionType()); |
+ EXPECT_FALSE(NetworkChangeNotifier::IsOffline()); |
+ network_change_notifier_->SetCurrentConnectionType( |
+ NetworkChangeNotifier::CONNECTION_NONE); |
+ // This makes the connect job fail: |
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); |
+ resolver_.ResolveAllPending(); |
+ MessageLoop::current()->RunUntilIdle(); |
+ |
+ // The fetcher is now waiting for the connection to become online again. |
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, |
+ NetworkChangeNotifier::GetConnectionType()); |
+ EXPECT_TRUE(NetworkChangeNotifier::IsOffline()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ // The core is still alive, but it dropped its request. |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ |
+ // It should retry once the connection is back. |
+ network_change_notifier_->SetCurrentConnectionType( |
+ NetworkChangeNotifier::CONNECTION_WIFI); |
+ MessageLoop::current()->RunUntilIdle(); |
+ EXPECT_EQ(1, GetNumFetcherCores()); |
+ ASSERT_FALSE(completed_fetcher_); |
+ EXPECT_TRUE(resolver_.has_pending_requests()); |
+ |
+ // Resolve the pending request; the fetcher should complete now. |
+ resolver_.ResolveAllPending(); |
+ MessageLoop::current()->Run(); |
+ |
+ EXPECT_EQ(0, GetNumFetcherCores()); |
+ EXPECT_FALSE(resolver_.has_pending_requests()); |
+ ASSERT_TRUE(completed_fetcher_); |
+ EXPECT_EQ(OK, completed_fetcher_->GetStatus().error()); |
+ EXPECT_EQ(200, completed_fetcher_->GetResponseCode()); |
+} |
+ |
#if defined(OS_MACOSX) |
// SIGSEGV on Mac: http://crbug.com/60426 |
TEST_F(URLFetcherPostTest, DISABLED_Basic) { |