summaryrefslogtreecommitdiffstats
path: root/content/test
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-29 16:48:19 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-29 16:48:19 +0000
commit91c06e5e57d38760631ed240b1161a2af613b974 (patch)
treec24a23ab720050396179a46ddc4c64a4426dcbaa /content/test
parentc7fd73291df44ad9c03c04d8aba6e5d694bf2864 (diff)
downloadchromium_src-91c06e5e57d38760631ed240b1161a2af613b974.zip
chromium_src-91c06e5e57d38760631ed240b1161a2af613b974.tar.gz
chromium_src-91c06e5e57d38760631ed240b1161a2af613b974.tar.bz2
Add a scoper object for URLFetcher::Factory
This should make it much safer to use (i.e. memory-safe). BUG=90585 Review URL: http://codereview.chromium.org/7524033 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94694 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/test')
-rw-r--r--content/test/test_url_fetcher_factory.cc213
-rw-r--r--content/test/test_url_fetcher_factory.h237
2 files changed, 450 insertions, 0 deletions
diff --git a/content/test/test_url_fetcher_factory.cc b/content/test/test_url_fetcher_factory.cc
new file mode 100644
index 0000000..ad6e512
--- /dev/null
+++ b/content/test/test_url_fetcher_factory.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/test/test_url_fetcher_factory.h"
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "net/url_request/url_request_status.h"
+
+ScopedURLFetcherFactory::ScopedURLFetcherFactory(URLFetcher::Factory* factory) {
+ DCHECK(!URLFetcher::factory());
+ URLFetcher::set_factory(factory);
+}
+
+ScopedURLFetcherFactory::~ScopedURLFetcherFactory() {
+ DCHECK(URLFetcher::factory());
+ URLFetcher::set_factory(NULL);
+}
+
+TestURLFetcher::TestURLFetcher(int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d)
+ : URLFetcher(url, request_type, d),
+ id_(id),
+ original_url_(url),
+ did_receive_last_chunk_(false) {
+}
+
+TestURLFetcher::~TestURLFetcher() {
+}
+
+void TestURLFetcher::AppendChunkToUpload(const std::string& data,
+ bool is_last_chunk) {
+ DCHECK(!did_receive_last_chunk_);
+ did_receive_last_chunk_ = is_last_chunk;
+ chunks_.push_back(data);
+}
+
+void TestURLFetcher::set_status(const net::URLRequestStatus& status) {
+ fake_status_ = status;
+}
+
+void TestURLFetcher::SetResponseString(const std::string& response) {
+ SetResponseDestinationForTesting(STRING);
+ fake_response_string_ = response;
+}
+
+void TestURLFetcher::SetResponseFilePath(const FilePath& path) {
+ SetResponseDestinationForTesting(TEMP_FILE);
+ fake_response_file_path_ = path;
+}
+
+bool TestURLFetcher::GetResponseAsString(
+ std::string* out_response_string) const {
+ if (GetResponseDestinationForTesting() != STRING)
+ return false;
+
+ *out_response_string = fake_response_string_;
+ return true;
+}
+
+bool TestURLFetcher::GetResponseAsFilePath(
+ bool take_ownership, FilePath* out_response_path) const {
+ if (GetResponseDestinationForTesting() != TEMP_FILE)
+ return false;
+
+ *out_response_path = fake_response_file_path_;
+ return true;
+}
+
+TestURLFetcherFactory::TestURLFetcherFactory()
+ : ScopedURLFetcherFactory(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+}
+
+TestURLFetcherFactory::~TestURLFetcherFactory() {}
+
+URLFetcher* TestURLFetcherFactory::CreateURLFetcher(
+ int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d) {
+ TestURLFetcher* fetcher = new TestURLFetcher(id, url, request_type, d);
+ fetchers_[id] = fetcher;
+ return fetcher;
+}
+
+TestURLFetcher* TestURLFetcherFactory::GetFetcherByID(int id) const {
+ Fetchers::const_iterator i = fetchers_.find(id);
+ return i == fetchers_.end() ? NULL : i->second;
+}
+
+void TestURLFetcherFactory::RemoveFetcherFromMap(int id) {
+ Fetchers::iterator i = fetchers_.find(id);
+ DCHECK(i != fetchers_.end());
+ fetchers_.erase(i);
+}
+
+const GURL& TestURLFetcher::url() const {
+ return fake_url_;
+}
+
+const net::URLRequestStatus& TestURLFetcher::status() const {
+ return fake_status_;
+}
+
+int TestURLFetcher::response_code() const {
+ return fake_response_code_;
+}
+
+// This class is used by the FakeURLFetcherFactory below.
+class FakeURLFetcher : public URLFetcher {
+ public:
+ // Normal URL fetcher constructor but also takes in a pre-baked response.
+ FakeURLFetcher(const GURL& url, RequestType request_type, Delegate* d,
+ const std::string& response_data, bool success)
+ : URLFetcher(url, request_type, d),
+ url_(url),
+ response_data_(response_data),
+ success_(success),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+ }
+
+ // Start the request. This will call the given delegate asynchronously
+ // with the pre-baked response as parameter.
+ virtual void Start() {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&FakeURLFetcher::RunDelegate));
+ }
+
+ private:
+ virtual ~FakeURLFetcher() {
+ }
+
+ // This is the method which actually calls the delegate that is passed in the
+ // constructor.
+ void RunDelegate() {
+ net::URLRequestStatus status;
+ status.set_status(success_ ? net::URLRequestStatus::SUCCESS :
+ net::URLRequestStatus::FAILED);
+ delegate()->OnURLFetchComplete(this, url_, status, success_ ? 200 : 500,
+ net::ResponseCookies(), response_data_);
+ }
+
+ // Pre-baked response data and flag which indicates whether the request should
+ // be successful or not.
+ GURL url_;
+ std::string response_data_;
+ bool success_;
+
+ // Method factory used to run the delegate.
+ ScopedRunnableMethodFactory<FakeURLFetcher> method_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeURLFetcher);
+};
+
+FakeURLFetcherFactory::FakeURLFetcherFactory()
+ : ScopedURLFetcherFactory(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+}
+
+FakeURLFetcherFactory::FakeURLFetcherFactory(
+ URLFetcher::Factory* default_factory)
+ : ScopedURLFetcherFactory(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ default_factory_(default_factory) {
+}
+
+FakeURLFetcherFactory::~FakeURLFetcherFactory() {}
+
+URLFetcher* FakeURLFetcherFactory::CreateURLFetcher(
+ int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d) {
+ FakeResponseMap::const_iterator it = fake_responses_.find(url);
+ if (it == fake_responses_.end()) {
+ if (default_factory_ == NULL) {
+ // If we don't have a baked response for that URL we return NULL.
+ DLOG(ERROR) << "No baked response for URL: " << url.spec();
+ return NULL;
+ } else {
+ return default_factory_->CreateURLFetcher(id, url, request_type, d);
+ }
+ }
+ return new FakeURLFetcher(url, request_type, d,
+ it->second.first, it->second.second);
+}
+
+void FakeURLFetcherFactory::SetFakeResponse(const std::string& url,
+ const std::string& response_data,
+ bool success) {
+ // Overwrite existing URL if it already exists.
+ fake_responses_[GURL(url)] = std::make_pair(response_data, success);
+}
+
+void FakeURLFetcherFactory::ClearFakeReponses() {
+ fake_responses_.clear();
+}
+
+URLFetcherFactory::URLFetcherFactory() {}
+
+URLFetcherFactory::~URLFetcherFactory() {}
+
+URLFetcher* URLFetcherFactory::CreateURLFetcher(
+ int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d) {
+ return new URLFetcher(url, request_type, d);
+}
diff --git a/content/test/test_url_fetcher_factory.h b/content/test/test_url_fetcher_factory.h
new file mode 100644
index 0000000..f402875
--- /dev/null
+++ b/content/test/test_url_fetcher_factory.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_TEST_TEST_URL_FETCHER_FACTORY_H_
+#define CONTENT_TEST_TEST_URL_FETCHER_FACTORY_H_
+#pragma once
+
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/threading/non_thread_safe.h"
+#include "content/common/url_fetcher.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_status.h"
+
+// Changes URLFetcher's Factory for the lifetime of the object.
+// Note that this scoper cannot be nested (to make it even harder to misuse).
+class ScopedURLFetcherFactory : public base::NonThreadSafe {
+ public:
+ explicit ScopedURLFetcherFactory(URLFetcher::Factory* factory);
+ virtual ~ScopedURLFetcherFactory();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedURLFetcherFactory);
+};
+
+// TestURLFetcher and TestURLFetcherFactory are used for testing consumers of
+// URLFetcher. TestURLFetcherFactory is a URLFetcher::Factory that creates
+// TestURLFetchers. TestURLFetcher::Start is overriden to do nothing. It is
+// expected that you'll grab the delegate from the TestURLFetcher and invoke
+// the callback method when appropriate. In this way it's easy to mock a
+// URLFetcher.
+// Typical usage:
+// // TestURLFetcher requires a MessageLoop:
+// MessageLoopForUI message_loop;
+// // And io_thread to release URLRequestContextGetter in URLFetcher::Core.
+// BrowserThread io_thread(BrowserThread::IO, &message_loop);
+// // Create factory (it automatically sets itself as URLFetcher's factory).
+// TestURLFetcherFactory factory;
+// // Do something that triggers creation of a URLFetcher.
+// TestURLFetcher* fetcher = factory.GetFetcherByID(expected_id);
+// DCHECK(fetcher);
+// // Notify delegate with whatever data you want.
+// fetcher->delegate()->OnURLFetchComplete(...);
+// // Make sure consumer of URLFetcher does the right thing.
+// ...
+//
+// Note: if you don't know when your request objects will be created you
+// might want to use the FakeUrlFetcher and FakeUrlFetcherFactory classes
+// below.
+
+class TestURLFetcher : public URLFetcher {
+ public:
+ TestURLFetcher(int id,
+ const GURL& url,
+ RequestType request_type,
+ Delegate* d);
+ virtual ~TestURLFetcher();
+
+ // Overriden to do nothing. It is assumed the caller will notify the delegate.
+ virtual void Start() {}
+
+ // Overriden to cache the chunks uploaded. Caller can read back the uploaded
+ // chunks with the upload_data() accessor.
+ virtual void AppendChunkToUpload(const std::string& data, bool is_last_chunk);
+
+ // Unique ID in our factory.
+ int id() const { return id_; }
+
+ // URL we were created with. Because of how we're using URLFetcher url()
+ // always returns an empty URL. Chances are you'll want to use original_url()
+ // in your tests.
+ const GURL& original_url() const { return original_url_; }
+
+ // Returns the data uploaded on this URLFetcher.
+ const std::string& upload_data() const { return URLFetcher::upload_data(); }
+
+ // Returns the chunks of data uploaded on this URLFetcher.
+ const std::list<std::string>& upload_chunks() const { return chunks_; }
+
+ // Returns the delegate installed on the URLFetcher.
+ Delegate* delegate() const { return URLFetcher::delegate(); }
+
+ void set_url(const GURL& url) { fake_url_ = url; }
+ virtual const GURL& url() const;
+
+ void set_status(const net::URLRequestStatus& status);
+ virtual const net::URLRequestStatus& status() const;
+
+ void set_response_code(int response_code) {
+ fake_response_code_ = response_code;
+ }
+ virtual int response_code() const;
+
+ // Set string data.
+ void SetResponseString(const std::string& response);
+
+ // Set File data.
+ void SetResponseFilePath(const FilePath& path);
+
+ // Override response access functions to return fake data.
+ virtual bool GetResponseAsString(std::string* out_response_string) const;
+ virtual bool GetResponseAsFilePath(bool take_ownership,
+ FilePath* out_response_path) const;
+
+ private:
+ const int id_;
+ const GURL original_url_;
+ std::list<std::string> chunks_;
+ bool did_receive_last_chunk_;
+
+ // User can use set_* methods to provide values returned by getters.
+ // Setting the real values is not possible, because the real class
+ // has no setters. The data is a private member of a class defined
+ // in a .cc file, so we can't get at it with friendship.
+ GURL fake_url_;
+ net::URLRequestStatus fake_status_;
+ int fake_response_code_;
+ std::string fake_response_string_;
+ FilePath fake_response_file_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestURLFetcher);
+};
+
+// Simple URLFetcher::Factory method that creates TestURLFetchers. All fetchers
+// are registered in a map by the id passed to the create method.
+class TestURLFetcherFactory : public URLFetcher::Factory,
+ public ScopedURLFetcherFactory {
+ public:
+ TestURLFetcherFactory();
+ virtual ~TestURLFetcherFactory();
+
+ virtual URLFetcher* CreateURLFetcher(int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d);
+ TestURLFetcher* GetFetcherByID(int id) const;
+ void RemoveFetcherFromMap(int id);
+
+ private:
+ // Maps from id passed to create to the returned URLFetcher.
+ typedef std::map<int, TestURLFetcher*> Fetchers;
+ Fetchers fetchers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestURLFetcherFactory);
+};
+
+// The FakeUrlFetcher and FakeUrlFetcherFactory classes are similar to the
+// ones above but don't require you to know when exactly the URLFetcher objects
+// will be created.
+//
+// These classes let you set pre-baked HTTP responses for particular URLs.
+// E.g., if the user requests http://a.com/ then respond with an HTTP/500.
+//
+// We assume that the thread that is calling Start() on the URLFetcher object
+// has a message loop running.
+//
+// This class is not thread-safe. You should not call SetFakeResponse or
+// ClearFakeResponse at the same time you call CreateURLFetcher. However, it is
+// OK to start URLFetcher objects while setting or clearning fake responses
+// since already created URLFetcher objects will not be affected by any changes
+// made to the fake responses (once a URLFetcher object is created you cannot
+// change its fake response).
+//
+// Example usage:
+// FakeURLFetcherFactory factory;
+//
+// // You know that class SomeService will request url http://a.com/ and you
+// // want to test the service class by returning an error.
+// factory.SetFakeResponse("http://a.com/", "", false);
+// // But if the service requests http://b.com/asdf you want to respond with
+// // a simple html page and an HTTP/200 code.
+// factory.SetFakeResponse("http://b.com/asdf",
+// "<html><body>hello world</body></html>",
+// true);
+//
+// SomeService service;
+// service.Run(); // Will eventually request these two URLs.
+
+class FakeURLFetcherFactory : public URLFetcher::Factory,
+ public ScopedURLFetcherFactory {
+ public:
+ FakeURLFetcherFactory();
+ // FakeURLFetcherFactory that will delegate creating URLFetcher for unknown
+ // url to the given factory.
+ explicit FakeURLFetcherFactory(URLFetcher::Factory* default_factory);
+ virtual ~FakeURLFetcherFactory();
+
+ // If no fake response is set for the given URL this method will delegate the
+ // call to |default_factory_| if it is not NULL, or return NULL if it is
+ // NULL.
+ // Otherwise, it will return a URLFetcher object which will respond with the
+ // pre-baked response that the client has set by calling SetFakeResponse().
+ virtual URLFetcher* CreateURLFetcher(int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d);
+
+ // Sets the fake response for a given URL. If success is true we will serve
+ // an HTTP/200 and an HTTP/500 otherwise. The |response_data| may be empty.
+ void SetFakeResponse(const std::string& url,
+ const std::string& response_data,
+ bool success);
+
+ // Clear all the fake responses that were previously set via
+ // SetFakeResponse().
+ void ClearFakeReponses();
+
+ private:
+ typedef std::map<GURL, std::pair<std::string, bool> > FakeResponseMap;
+ FakeResponseMap fake_responses_;
+ URLFetcher::Factory* default_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeURLFetcherFactory);
+};
+
+// This is an implementation of URLFetcher::Factory that will create a real
+// URLFetcher. It can be use in conjunction with a FakeURLFetcherFactory in
+// integration tests to control the behavior of some requests but execute
+// all the other ones.
+class URLFetcherFactory : public URLFetcher::Factory {
+ public:
+ URLFetcherFactory();
+ virtual ~URLFetcherFactory();
+
+ // This method will create a real URLFetcher.
+ virtual URLFetcher* CreateURLFetcher(int id,
+ const GURL& url,
+ URLFetcher::RequestType request_type,
+ URLFetcher::Delegate* d);
+
+};
+
+#endif // CONTENT_TEST_TEST_URL_FETCHER_FACTORY_H_