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

Unified Diff: net/url_request/url_fetcher_impl_unittest.cc

Issue 11464028: Introduce ERR_NETWORK_CHANGED and allow URLFetcher to automatically retry on that error. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years 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
« net/url_request/url_fetcher_core.cc ('K') | « net/url_request/url_fetcher_impl.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) {
« net/url_request/url_fetcher_core.cc ('K') | « net/url_request/url_fetcher_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698