Chromium Code Reviews| 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) { |