| Index: content/test/test_file_error_injector.cc
|
| ===================================================================
|
| --- content/test/test_file_error_injector.cc (revision 151499)
|
| +++ content/test/test_file_error_injector.cc (working copy)
|
| @@ -1,457 +0,0 @@
|
| -// Copyright (c) 2012 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/public/test/test_file_error_injector.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/compiler_specific.h"
|
| -#include "base/logging.h"
|
| -#include "content/browser/download/download_create_info.h"
|
| -#include "content/browser/download/download_file_impl.h"
|
| -#include "content/browser/download/download_file_manager.h"
|
| -#include "content/browser/download/download_interrupt_reasons_impl.h"
|
| -#include "content/browser/power_save_blocker.h"
|
| -#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/download_id.h"
|
| -#include "googleurl/src/gurl.h"
|
| -
|
| -namespace content {
|
| -class ByteStreamReader;
|
| -}
|
| -
|
| -namespace {
|
| -
|
| -DownloadFileManager* GetDownloadFileManager() {
|
| - content::ResourceDispatcherHostImpl* rdh =
|
| - content::ResourceDispatcherHostImpl::Get();
|
| - DCHECK(rdh != NULL);
|
| - return rdh->download_file_manager();
|
| -}
|
| -
|
| -// A class that performs file operations and injects errors.
|
| -class DownloadFileWithErrors: public DownloadFileImpl {
|
| - public:
|
| - typedef base::Callback<void(const GURL& url, content::DownloadId id)>
|
| - ConstructionCallback;
|
| - typedef base::Callback<void(const GURL& url)> DestructionCallback;
|
| -
|
| - DownloadFileWithErrors(
|
| - const DownloadCreateInfo* info,
|
| - scoped_ptr<content::ByteStreamReader> stream,
|
| - DownloadRequestHandleInterface* request_handle,
|
| - content::DownloadManager* download_manager,
|
| - bool calculate_hash,
|
| - const net::BoundNetLog& bound_net_log,
|
| - const content::TestFileErrorInjector::FileErrorInfo& error_info,
|
| - const ConstructionCallback& ctor_callback,
|
| - const DestructionCallback& dtor_callback);
|
| -
|
| - ~DownloadFileWithErrors();
|
| -
|
| - // DownloadFile interface.
|
| - virtual content::DownloadInterruptReason Initialize() OVERRIDE;
|
| - virtual content::DownloadInterruptReason AppendDataToFile(
|
| - const char* data, size_t data_len) OVERRIDE;
|
| - virtual void Rename(const FilePath& full_path,
|
| - bool overwrite_existing_file,
|
| - const RenameCompletionCallback& callback) OVERRIDE;
|
| -
|
| - private:
|
| - // Error generating helper.
|
| - content::DownloadInterruptReason ShouldReturnError(
|
| - content::TestFileErrorInjector::FileOperationCode code,
|
| - content::DownloadInterruptReason original_error);
|
| -
|
| - // Used in place of original rename callback to intercept with
|
| - // ShouldReturnError.
|
| - void RenameErrorCallback(
|
| - const RenameCompletionCallback& original_callback,
|
| - content::DownloadInterruptReason original_error,
|
| - const FilePath& path_result);
|
| -
|
| - // Source URL for the file being downloaded.
|
| - GURL source_url_;
|
| -
|
| - // Our injected error. Only one per file.
|
| - content::TestFileErrorInjector::FileErrorInfo error_info_;
|
| -
|
| - // Count per operation. 0-based.
|
| - std::map<content::TestFileErrorInjector::FileOperationCode, int>
|
| - operation_counter_;
|
| -
|
| - // Callback for destruction.
|
| - DestructionCallback destruction_callback_;
|
| -};
|
| -
|
| -DownloadFileWithErrors::DownloadFileWithErrors(
|
| - const DownloadCreateInfo* info,
|
| - scoped_ptr<content::ByteStreamReader> stream,
|
| - DownloadRequestHandleInterface* request_handle,
|
| - content::DownloadManager* download_manager,
|
| - bool calculate_hash,
|
| - const net::BoundNetLog& bound_net_log,
|
| - const content::TestFileErrorInjector::FileErrorInfo& error_info,
|
| - const ConstructionCallback& ctor_callback,
|
| - const DestructionCallback& dtor_callback)
|
| - : DownloadFileImpl(info,
|
| - stream.Pass(),
|
| - request_handle,
|
| - download_manager,
|
| - calculate_hash,
|
| - scoped_ptr<content::PowerSaveBlocker>(NULL).Pass(),
|
| - bound_net_log),
|
| - source_url_(info->url()),
|
| - error_info_(error_info),
|
| - destruction_callback_(dtor_callback) {
|
| - ctor_callback.Run(source_url_, info->download_id);
|
| -}
|
| -
|
| -DownloadFileWithErrors::~DownloadFileWithErrors() {
|
| - destruction_callback_.Run(source_url_);
|
| -}
|
| -
|
| -content::DownloadInterruptReason DownloadFileWithErrors::Initialize() {
|
| - return ShouldReturnError(
|
| - content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
|
| - DownloadFileImpl::Initialize());
|
| -}
|
| -
|
| -content::DownloadInterruptReason DownloadFileWithErrors::AppendDataToFile(
|
| - const char* data, size_t data_len) {
|
| - return ShouldReturnError(
|
| - content::TestFileErrorInjector::FILE_OPERATION_WRITE,
|
| - DownloadFileImpl::AppendDataToFile(data, data_len));
|
| -}
|
| -
|
| -void DownloadFileWithErrors::Rename(
|
| - const FilePath& full_path,
|
| - bool overwrite_existing_file,
|
| - const RenameCompletionCallback& callback) {
|
| - DownloadFileImpl::Rename(
|
| - full_path, overwrite_existing_file,
|
| - base::Bind(&DownloadFileWithErrors::RenameErrorCallback,
|
| - // Unretained since this'll only be called from
|
| - // the DownloadFileImpl slice of the same object.
|
| - base::Unretained(this), callback));
|
| -}
|
| -
|
| -content::DownloadInterruptReason DownloadFileWithErrors::ShouldReturnError(
|
| - content::TestFileErrorInjector::FileOperationCode code,
|
| - content::DownloadInterruptReason original_error) {
|
| - int counter = operation_counter_[code];
|
| - ++operation_counter_[code];
|
| -
|
| - if (code != error_info_.code)
|
| - return original_error;
|
| -
|
| - if (counter != error_info_.operation_instance)
|
| - return original_error;
|
| -
|
| - VLOG(1) << " " << __FUNCTION__ << "()"
|
| - << " url = '" << source_url_.spec() << "'"
|
| - << " code = " << content::TestFileErrorInjector::DebugString(code)
|
| - << " (" << code << ")"
|
| - << " counter = " << counter
|
| - << " original_error = "
|
| - << content::InterruptReasonDebugString(original_error)
|
| - << " (" << original_error << ")"
|
| - << " new error = "
|
| - << content::InterruptReasonDebugString(error_info_.error)
|
| - << " (" << error_info_.error << ")";
|
| -
|
| - return error_info_.error;
|
| -}
|
| -
|
| -void DownloadFileWithErrors::RenameErrorCallback(
|
| - const RenameCompletionCallback& original_callback,
|
| - content::DownloadInterruptReason original_error,
|
| - const FilePath& path_result) {
|
| - original_callback.Run(ShouldReturnError(
|
| - content::TestFileErrorInjector::FILE_OPERATION_RENAME,
|
| - original_error), path_result);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace content {
|
| -
|
| -// A factory for constructing DownloadFiles that inject errors.
|
| -class DownloadFileWithErrorsFactory
|
| - : public DownloadFileManager::DownloadFileFactory {
|
| - public:
|
| -
|
| - DownloadFileWithErrorsFactory(
|
| - const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
|
| - const DownloadFileWithErrors::DestructionCallback& dtor_callback);
|
| - virtual ~DownloadFileWithErrorsFactory();
|
| -
|
| - // DownloadFileFactory interface.
|
| - virtual DownloadFile* CreateFile(
|
| - DownloadCreateInfo* info,
|
| - scoped_ptr<content::ByteStreamReader> stream,
|
| - content::DownloadManager* download_manager,
|
| - bool calculate_hash,
|
| - const net::BoundNetLog& bound_net_log);
|
| -
|
| - bool AddError(
|
| - const TestFileErrorInjector::FileErrorInfo& error_info);
|
| -
|
| - void ClearErrors();
|
| -
|
| - private:
|
| - // Our injected error list, mapped by URL. One per file.
|
| - TestFileErrorInjector::ErrorMap injected_errors_;
|
| -
|
| - // Callback for creation and destruction.
|
| - DownloadFileWithErrors::ConstructionCallback construction_callback_;
|
| - DownloadFileWithErrors::DestructionCallback destruction_callback_;
|
| -};
|
| -
|
| -DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory(
|
| - const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
|
| - const DownloadFileWithErrors::DestructionCallback& dtor_callback)
|
| - : construction_callback_(ctor_callback),
|
| - destruction_callback_(dtor_callback) {
|
| -}
|
| -
|
| -DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() {
|
| -}
|
| -
|
| -content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
|
| - DownloadCreateInfo* info,
|
| - scoped_ptr<content::ByteStreamReader> stream,
|
| - content::DownloadManager* download_manager,
|
| - bool calculate_hash,
|
| - const net::BoundNetLog& bound_net_log) {
|
| - std::string url = info->url().spec();
|
| -
|
| - if (injected_errors_.find(url) == injected_errors_.end()) {
|
| - // Have to create entry, because FileErrorInfo is not a POD type.
|
| - TestFileErrorInjector::FileErrorInfo err_info = {
|
| - url,
|
| - TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
|
| - -1,
|
| - content::DOWNLOAD_INTERRUPT_REASON_NONE
|
| - };
|
| - injected_errors_[url] = err_info;
|
| - }
|
| -
|
| - return new DownloadFileWithErrors(
|
| - info,
|
| - stream.Pass(),
|
| - new DownloadRequestHandle(info->request_handle),
|
| - download_manager,
|
| - calculate_hash,
|
| - bound_net_log,
|
| - injected_errors_[url],
|
| - construction_callback_,
|
| - destruction_callback_);
|
| -}
|
| -
|
| -bool DownloadFileWithErrorsFactory::AddError(
|
| - const TestFileErrorInjector::FileErrorInfo& error_info) {
|
| - // Creates an empty entry if necessary. Duplicate entries overwrite.
|
| - injected_errors_[error_info.url] = error_info;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void DownloadFileWithErrorsFactory::ClearErrors() {
|
| - injected_errors_.clear();
|
| -}
|
| -
|
| -TestFileErrorInjector::TestFileErrorInjector()
|
| - : created_factory_(NULL) {
|
| - // Record the value of the pointer, for later validation.
|
| - created_factory_ =
|
| - new DownloadFileWithErrorsFactory(
|
| - base::Bind(&TestFileErrorInjector::
|
| - RecordDownloadFileConstruction,
|
| - this),
|
| - base::Bind(&TestFileErrorInjector::
|
| - RecordDownloadFileDestruction,
|
| - this));
|
| -
|
| - // We will transfer ownership of the factory to the download file manager.
|
| - scoped_ptr<DownloadFileWithErrorsFactory> download_file_factory(
|
| - created_factory_);
|
| -
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::FILE,
|
| - FROM_HERE,
|
| - base::Bind(&TestFileErrorInjector::AddFactory,
|
| - this,
|
| - base::Passed(&download_file_factory)));
|
| -}
|
| -
|
| -TestFileErrorInjector::~TestFileErrorInjector() {
|
| -}
|
| -
|
| -void TestFileErrorInjector::AddFactory(
|
| - scoped_ptr<DownloadFileWithErrorsFactory> factory) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
|
| -
|
| - DownloadFileManager* download_file_manager = GetDownloadFileManager();
|
| - DCHECK(download_file_manager);
|
| -
|
| - // Convert to base class pointer, for GCC.
|
| - scoped_ptr<DownloadFileManager::DownloadFileFactory> plain_factory(
|
| - factory.release());
|
| -
|
| - download_file_manager->SetFileFactoryForTesting(plain_factory.Pass());
|
| -}
|
| -
|
| -bool TestFileErrorInjector::AddError(const FileErrorInfo& error_info) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK_LE(0, error_info.operation_instance);
|
| - DCHECK(injected_errors_.find(error_info.url) == injected_errors_.end());
|
| -
|
| - // Creates an empty entry if necessary.
|
| - injected_errors_[error_info.url] = error_info;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void TestFileErrorInjector::ClearErrors() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - injected_errors_.clear();
|
| -}
|
| -
|
| -bool TestFileErrorInjector::InjectErrors() {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| -
|
| - ClearFoundFiles();
|
| -
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::FILE,
|
| - FROM_HERE,
|
| - base::Bind(&TestFileErrorInjector::InjectErrorsOnFileThread,
|
| - this,
|
| - injected_errors_,
|
| - created_factory_));
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void TestFileErrorInjector::InjectErrorsOnFileThread(
|
| - ErrorMap map, DownloadFileWithErrorsFactory* factory) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
|
| -
|
| - // Validate that our factory is in use.
|
| - DownloadFileManager* download_file_manager = GetDownloadFileManager();
|
| - DCHECK(download_file_manager);
|
| -
|
| - DownloadFileManager::DownloadFileFactory* file_factory =
|
| - download_file_manager->GetFileFactoryForTesting();
|
| -
|
| - // Validate that we still have the same factory.
|
| - DCHECK_EQ(static_cast<DownloadFileManager::DownloadFileFactory*>(factory),
|
| - file_factory);
|
| -
|
| - // We want to replace all existing injection errors.
|
| - factory->ClearErrors();
|
| -
|
| - for (ErrorMap::const_iterator it = map.begin(); it != map.end(); ++it)
|
| - factory->AddError(it->second);
|
| -}
|
| -
|
| -size_t TestFileErrorInjector::CurrentFileCount() const {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - return files_.size();
|
| -}
|
| -
|
| -size_t TestFileErrorInjector::TotalFileCount() const {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - return found_files_.size();
|
| -}
|
| -
|
| -
|
| -bool TestFileErrorInjector::HadFile(const GURL& url) const {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| -
|
| - return (found_files_.find(url) != found_files_.end());
|
| -}
|
| -
|
| -const content::DownloadId TestFileErrorInjector::GetId(
|
| - const GURL& url) const {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| -
|
| - FileMap::const_iterator it = found_files_.find(url);
|
| - if (it == found_files_.end())
|
| - return content::DownloadId::Invalid();
|
| -
|
| - return it->second;
|
| -}
|
| -
|
| -void TestFileErrorInjector::ClearFoundFiles() {
|
| - found_files_.clear();
|
| -}
|
| -
|
| -void TestFileErrorInjector::DownloadFileCreated(GURL url,
|
| - content::DownloadId id) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK(files_.find(url) == files_.end());
|
| -
|
| - files_[url] = id;
|
| - found_files_[url] = id;
|
| -}
|
| -
|
| -void TestFileErrorInjector::DestroyingDownloadFile(GURL url) {
|
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| - DCHECK(files_.find(url) != files_.end());
|
| -
|
| - files_.erase(url);
|
| -}
|
| -
|
| -void TestFileErrorInjector::RecordDownloadFileConstruction(
|
| - const GURL& url, content::DownloadId id) {
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::UI,
|
| - FROM_HERE,
|
| - base::Bind(&TestFileErrorInjector::DownloadFileCreated,
|
| - this,
|
| - url,
|
| - id));
|
| -}
|
| -
|
| -void TestFileErrorInjector::RecordDownloadFileDestruction(const GURL& url) {
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::UI,
|
| - FROM_HERE,
|
| - base::Bind(&TestFileErrorInjector::DestroyingDownloadFile,
|
| - this,
|
| - url));
|
| -}
|
| -
|
| -// static
|
| -scoped_refptr<TestFileErrorInjector> TestFileErrorInjector::Create() {
|
| - static bool visited = false;
|
| - DCHECK(!visited); // Only allowed to be called once.
|
| - visited = true;
|
| -
|
| - scoped_refptr<TestFileErrorInjector> single_injector(
|
| - new TestFileErrorInjector);
|
| -
|
| - return single_injector;
|
| -}
|
| -
|
| -// static
|
| -std::string TestFileErrorInjector::DebugString(FileOperationCode code) {
|
| - switch (code) {
|
| - case FILE_OPERATION_INITIALIZE:
|
| - return "INITIALIZE";
|
| - case FILE_OPERATION_WRITE:
|
| - return "WRITE";
|
| - case FILE_OPERATION_RENAME:
|
| - return "RENAME";
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - return "Unknown";
|
| -}
|
| -
|
| -} // namespace content
|
|
|