Index: content/test/test_file_error_injector.cc |
diff --git a/content/test/test_file_error_injector.cc b/content/test/test_file_error_injector.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e4204e6ade4c7ca5b6597ee7a2fc47ed54d04cd4 |
--- /dev/null |
+++ b/content/test/test_file_error_injector.cc |
@@ -0,0 +1,355 @@ |
+// 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_file_error_injector.h" |
+ |
+#include <map> |
+#include <vector> |
+ |
+#include "base/compiler_specific.h" |
+#include "base/logging.h" |
+#include "content/browser/download/download_file_impl.h" |
+#include "content/browser/download/download_file_manager.h" |
+#include "content/browser/renderer_host/resource_dispatcher_host.h" |
+ |
+class DownloadFileWithErrors; |
+ |
+namespace { |
+ |
+// Structure that encapsulates the information needed to inject a file error. |
+struct FileErrorInfo { |
+ FileErrorInfo() |
+ : file_index(-1), |
+ code(FILE_OPERATION_INITIALIZE), |
+ operation_instance(-1), |
+ net_error(net::OK) { |
+ } |
+ |
+ int file_index; // 0-based. |
+ FileOperationCode code; |
+ int operation_instance; // 0-based. |
+ net::Error net_error; |
+}; |
+ |
+// List of errors. |
+typedef std::vector<FileErrorInfo> ErrorList; |
+ |
+// Structure that associates a file with a set of errors. |
+struct FileErrors { |
+ FileErrors() : file(NULL) {} |
+ |
+ DownloadFileWithErrors* file; |
+ ErrorList error_list; |
+}; |
+ |
+DownloadFileManager* GetDownloadFileManager() { |
+ ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); |
+ DCHECK(rdh != NULL); |
+ return rdh->download_file_manager(); |
+} |
+ |
+std::string DebugString(FileOperationCode code) { |
+ |
+#define TO_STRING(code) case FILE_OPERATION_##code: return #code |
+ |
+ switch (code) { |
+ TO_STRING(INITIALIZE); |
+ TO_STRING(WRITE); |
+ TO_STRING(RENAME); |
+ default: |
+ break; |
+ } |
+ |
+#undef TO_STRING |
+ |
+ return "Unknown"; |
+} |
+ |
+} // namespace |
+ |
+class TestFileErrorInjectorImpl : public TestFileErrorInjector { |
+ public: |
+ TestFileErrorInjectorImpl(); |
+ |
+ // TestFileErrorInjector interface. |
+ virtual bool InjectError(int file_index, |
+ FileOperationCode operation, |
+ int operation_instance, |
+ net::Error net_error) OVERRIDE; |
+ virtual size_t CurrentFileCount() const OVERRIDE; |
+ virtual size_t FileCreationCount() const OVERRIDE { return file_counter_; } |
+ |
+ // Callbacks from the download file. |
+ virtual int DownloadFileCreated(DownloadFileWithErrors* download_file); |
+ virtual void DestroyingDownloadFile(DownloadFileWithErrors* download_file); |
+ |
+ private: |
+ virtual ~TestFileErrorInjectorImpl(); |
+ |
+ // The number of files we've created. |
+ int file_counter_; |
+ |
+ // Our injected error list, mapped by file index. |
+ std::map<int, FileErrors> injected_errors_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); |
+}; |
+ |
+// A class that performs file operations and injects errors. |
+class DownloadFileWithErrors: public DownloadFileImpl { |
+ public: |
+ DownloadFileWithErrors(const DownloadCreateInfo* info, |
+ DownloadRequestHandleInterface* request_handle, |
+ content::DownloadManager* download_manager, |
+ bool calculate_hash, |
+ const net::BoundNetLog& bound_net_log, |
+ scoped_refptr<TestFileErrorInjectorImpl> injector); |
+ |
+ ~DownloadFileWithErrors(); |
+ |
+ // DownloadFile interface. |
+ virtual net::Error Initialize() OVERRIDE; |
+ virtual net::Error AppendDataToFile(const char* data, |
+ size_t data_len) OVERRIDE; |
+ virtual net::Error Rename(const FilePath& full_path) OVERRIDE; |
+ |
+ // Error generating helpers. |
+ net::Error ShouldReturnError(FileOperationCode code, |
+ net::Error original_net_error); |
+ |
+ void AddError(const FileErrorInfo& info); |
+ void SetErrorList(int index, |
+ const ErrorList& error_list); |
+ int index() const { return index_; } |
+ |
+ private: |
+ // Map from instance number to file error information. |
+ typedef std::map<int, FileErrorInfo> InstanceMap; |
+ |
+ // Map of errors by operation code |
+ typedef std::map<FileOperationCode, |
+ InstanceMap> ErrorMap; |
+ |
+ // The class that manages errors. |
+ scoped_refptr<TestFileErrorInjectorImpl> injector_; |
+ |
+ // Our file index. |
+ int index_; |
+ |
+ // Our injected error list. |
+ ErrorMap error_map_; |
+ |
+ // Count per operation. 0-based. |
+ std::map<FileOperationCode, int> operation_counter_; |
+}; |
+ |
+// A factory for constructing DownloadFiles that inject errors. |
+class DownloadFileWithErrorsFactory |
+ : public DownloadFileManager::DownloadFileFactory { |
+ public: |
+ |
+ explicit DownloadFileWithErrorsFactory( |
+ scoped_refptr<TestFileErrorInjectorImpl> injector); |
+ |
+ virtual ~DownloadFileWithErrorsFactory(); |
+ |
+ virtual content::DownloadFile* CreateFile( |
+ DownloadCreateInfo* info, |
+ const DownloadRequestHandle& request_handle, |
+ content::DownloadManager* download_manager, |
+ bool calculate_hash, |
+ const net::BoundNetLog& bound_net_log); |
+ |
+ private: |
+ |
+ scoped_refptr<TestFileErrorInjectorImpl> injector_; |
+}; |
+ |
+ |
+// Implementations. |
+ |
+// static |
+TestFileErrorInjector* TestFileErrorInjector::Create() { |
+ return new TestFileErrorInjectorImpl; |
+} |
+ |
+TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() : file_counter_(0) { |
+ DownloadFileWithErrorsFactory* download_file_factory = |
+ new DownloadFileWithErrorsFactory(this); |
+ DownloadFileManager* download_file_manager = GetDownloadFileManager(); |
+ DCHECK(download_file_manager); |
+ // Transfers ownership. |
+ download_file_manager->SetFileFactory(download_file_factory); |
+} |
+ |
+TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { |
+} |
+ |
+bool TestFileErrorInjectorImpl::InjectError(int file_index, |
+ FileOperationCode operation, |
+ int operation_instance, |
+ net::Error net_error) { |
+ DCHECK_LE(0, file_index); |
+ DCHECK_LE(0, operation_instance); |
+ |
+ // Fill in a new entry. |
+ FileErrorInfo info; |
+ info.file_index = file_index; |
+ info.code = operation; |
+ info.operation_instance = operation_instance; |
+ info.net_error = net_error; |
+ |
+ // Creates an empty entry if necessary. |
+ FileErrors& file_errors = injected_errors_[file_index]; |
+ file_errors.error_list.push_back(info); |
+ |
+ // If the file already exists, simply add this entry to the error list. |
cbentzel
2012/02/24 02:25:12
Do you need to handle this case?
ahendrickson
2012/02/24 22:48:39
Removed.
|
+ if (file_errors.file != NULL) |
+ file_errors.file->AddError(info); |
+ |
+ return true; |
+} |
+ |
+size_t TestFileErrorInjectorImpl::CurrentFileCount() const { |
+ size_t count = 0; |
+ |
+ // Count the map entries with a non-NULL file pointer. |
+ for (std::map<int, FileErrors>::const_iterator it = injected_errors_.begin(); |
+ it != injected_errors_.end(); |
+ ++it) { |
+ if (it->second.file != NULL) |
+ count++; |
+ } |
+ |
+ return count; |
+} |
+ |
+int TestFileErrorInjectorImpl::DownloadFileCreated( |
+ DownloadFileWithErrors* download_file) { |
+ DCHECK(download_file != NULL); |
+ |
+ // Creates an empty instance if necessary. |
+ FileErrors& file_errors = injected_errors_[file_counter_]; |
+ DCHECK(file_errors.file == NULL); |
+ file_errors.file = download_file; // Set the file. |
+ |
+ download_file->SetErrorList(file_counter_, file_errors.error_list); |
+ |
+ return file_counter_++; |
+} |
+ |
+void TestFileErrorInjectorImpl::DestroyingDownloadFile( |
+ DownloadFileWithErrors* download_file) { |
+ DCHECK(download_file != NULL); |
+ |
+ // Mark as gone by making the file NULL. |
+ injected_errors_[download_file->index()].file = NULL; |
+} |
+ |
+DownloadFileWithErrors::DownloadFileWithErrors( |
+ const DownloadCreateInfo* info, |
+ DownloadRequestHandleInterface* request_handle, |
+ content::DownloadManager* download_manager, |
+ bool calculate_hash, |
+ const net::BoundNetLog& bound_net_log, |
+ scoped_refptr<TestFileErrorInjectorImpl> injector) |
+ : DownloadFileImpl(info, |
+ request_handle, |
+ download_manager, |
+ calculate_hash, |
+ bound_net_log), |
+ injector_(injector), |
+ index_(-1) { |
+ if (injector_) |
+ injector_->DownloadFileCreated(this); |
+} |
+ |
+DownloadFileWithErrors::~DownloadFileWithErrors() { |
+ if (injector_) |
+ injector_->DestroyingDownloadFile(this); |
+} |
+ |
+ |
+net::Error DownloadFileWithErrors::Initialize() { |
+ return ShouldReturnError(FILE_OPERATION_INITIALIZE, |
+ DownloadFileImpl::Initialize()); |
+} |
+ |
+net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, |
+ size_t data_len) { |
+ return ShouldReturnError(FILE_OPERATION_WRITE, |
+ DownloadFileImpl::AppendDataToFile(data, data_len)); |
+} |
+ |
+net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { |
+ return ShouldReturnError(FILE_OPERATION_RENAME, |
+ DownloadFileImpl::Rename(full_path)); |
+} |
+ |
+net::Error DownloadFileWithErrors::ShouldReturnError( |
+ FileOperationCode code, |
+ net::Error original_net_error) { |
+ int counter = operation_counter_[code]; |
+ ++operation_counter_[code]; |
+ |
+ if (error_map_.find(code) == error_map_.end()) |
+ return original_net_error; // No errors for this operation. |
+ |
+ InstanceMap& instance_map = error_map_[code]; |
+ |
+ if (instance_map.find(counter) == instance_map.end()) |
+ return original_net_error; // No error for this instance of the operation. |
+ |
+ DVLOG(20) << " " << __FUNCTION__ << "()" |
+ << " code = " << ::DebugString(code) << " (" << code << ")" |
+ << " counter = " << counter |
+ << " original_error = " << original_net_error |
+ << " new error = " << instance_map[counter].net_error; |
+ |
+ return instance_map[counter].net_error; // Error! |
+} |
+ |
+void DownloadFileWithErrors::AddError( |
+ const FileErrorInfo& info) { |
+ // Get the instance map for the operation code. |
+ InstanceMap& instance_map = error_map_[info.code]; |
+ |
+ // Duplicate entries are an error. |
+ DCHECK(instance_map.end() == instance_map.find(info.operation_instance)); |
+ |
+ // Set the error information in the map. |
+ instance_map[info.operation_instance] = info; |
+} |
+ |
+void DownloadFileWithErrors::SetErrorList( |
+ int index, const ErrorList& error_list) { |
+ DCHECK_EQ(-1, index_); |
+ DCHECK_LE(0, index); |
+ index_ = index; |
+ |
+ // Parcel out the error list by operation code and instance. |
+ for (size_t i = 0; i < error_list.size(); ++i) |
+ AddError(error_list[i]); |
+} |
+ |
+DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( |
+ scoped_refptr<TestFileErrorInjectorImpl> injector) : injector_(injector) { |
+} |
+ |
+DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { |
+} |
+ |
+content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( |
+ DownloadCreateInfo* info, |
+ const DownloadRequestHandle& request_handle, |
+ content::DownloadManager* download_manager, |
+ bool calculate_hash, |
+ const net::BoundNetLog& bound_net_log) { |
+ return new DownloadFileWithErrors(info, |
+ new DownloadRequestHandle(request_handle), |
+ download_manager, |
+ calculate_hash, |
+ bound_net_log, |
+ injector_); |
+} |