Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/test/test_file_error_injector.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/compiler_specific.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "content/browser/download/download_file_impl.h" | |
| 13 #include "content/browser/download/download_file_manager.h" | |
| 14 #include "content/browser/renderer_host/resource_dispatcher_host.h" | |
| 15 | |
| 16 class DownloadFileWithErrors; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Structure that encapsulates the information needed to inject a file error. | |
| 21 struct FileErrorInfo { | |
| 22 FileErrorInfo() | |
| 23 : file_index(-1), | |
| 24 code(FILE_OPERATION_INITIALIZE), | |
| 25 operation_instance(-1), | |
| 26 net_error(net::OK) { | |
| 27 } | |
| 28 | |
| 29 int file_index; // 0-based. | |
| 30 FileOperationCode code; | |
| 31 int operation_instance; // 0-based. | |
| 32 net::Error net_error; | |
| 33 }; | |
| 34 | |
| 35 // List of errors. | |
| 36 typedef std::vector<FileErrorInfo> ErrorList; | |
| 37 | |
| 38 // Structure that associates a file with a set of errors. | |
| 39 struct FileErrors { | |
| 40 FileErrors() : file(NULL) {} | |
| 41 | |
| 42 DownloadFileWithErrors* file; | |
| 43 ErrorList error_list; | |
| 44 }; | |
| 45 | |
| 46 DownloadFileManager* GetDownloadFileManager() { | |
| 47 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); | |
| 48 DCHECK(rdh != NULL); | |
| 49 return rdh->download_file_manager(); | |
| 50 } | |
| 51 | |
| 52 std::string DebugString(FileOperationCode code) { | |
| 53 | |
| 54 #define TO_STRING(code) case FILE_OPERATION_##code: return #code | |
| 55 | |
| 56 switch (code) { | |
| 57 TO_STRING(INITIALIZE); | |
| 58 TO_STRING(WRITE); | |
| 59 TO_STRING(RENAME); | |
| 60 default: | |
| 61 break; | |
| 62 } | |
| 63 | |
| 64 #undef TO_STRING | |
| 65 | |
| 66 return "Unknown"; | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 class TestFileErrorInjectorImpl : public TestFileErrorInjector { | |
| 72 public: | |
| 73 TestFileErrorInjectorImpl(); | |
| 74 | |
| 75 // TestFileErrorInjector interface. | |
| 76 virtual bool InjectError(int file_index, | |
| 77 FileOperationCode operation, | |
| 78 int operation_instance, | |
| 79 net::Error net_error) OVERRIDE; | |
| 80 virtual size_t CurrentFileCount() const OVERRIDE; | |
| 81 virtual size_t FileCreationCount() const OVERRIDE { return file_counter_; } | |
| 82 | |
| 83 // Callbacks from the download file. | |
| 84 virtual int DownloadFileCreated(DownloadFileWithErrors* download_file); | |
| 85 virtual void DestroyingDownloadFile(DownloadFileWithErrors* download_file); | |
| 86 | |
| 87 private: | |
| 88 virtual ~TestFileErrorInjectorImpl(); | |
| 89 | |
| 90 // The number of files we've created. | |
| 91 int file_counter_; | |
| 92 | |
| 93 // Our injected error list, mapped by file index. | |
| 94 std::map<int, FileErrors> injected_errors_; | |
| 95 | |
| 96 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); | |
| 97 }; | |
| 98 | |
| 99 // A class that performs file operations and injects errors. | |
| 100 class DownloadFileWithErrors: public DownloadFileImpl { | |
| 101 public: | |
| 102 DownloadFileWithErrors(const DownloadCreateInfo* info, | |
| 103 DownloadRequestHandleInterface* request_handle, | |
| 104 content::DownloadManager* download_manager, | |
| 105 bool calculate_hash, | |
| 106 const net::BoundNetLog& bound_net_log, | |
| 107 scoped_refptr<TestFileErrorInjectorImpl> injector); | |
| 108 | |
| 109 ~DownloadFileWithErrors(); | |
| 110 | |
| 111 // DownloadFile interface. | |
| 112 virtual net::Error Initialize() OVERRIDE; | |
| 113 virtual net::Error AppendDataToFile(const char* data, | |
| 114 size_t data_len) OVERRIDE; | |
| 115 virtual net::Error Rename(const FilePath& full_path) OVERRIDE; | |
| 116 | |
| 117 // Error generating helpers. | |
| 118 net::Error ShouldReturnError(FileOperationCode code, | |
| 119 net::Error original_net_error); | |
| 120 | |
| 121 void AddError(const FileErrorInfo& info); | |
| 122 void SetErrorList(int index, | |
| 123 const ErrorList& error_list); | |
| 124 int index() const { return index_; } | |
| 125 | |
| 126 private: | |
| 127 // Map from instance number to file error information. | |
| 128 typedef std::map<int, FileErrorInfo> InstanceMap; | |
| 129 | |
| 130 // Map of errors by operation code | |
| 131 typedef std::map<FileOperationCode, | |
| 132 InstanceMap> ErrorMap; | |
| 133 | |
| 134 // The class that manages errors. | |
| 135 scoped_refptr<TestFileErrorInjectorImpl> injector_; | |
| 136 | |
| 137 // Our file index. | |
| 138 int index_; | |
| 139 | |
| 140 // Our injected error list. | |
| 141 ErrorMap error_map_; | |
| 142 | |
| 143 // Count per operation. 0-based. | |
| 144 std::map<FileOperationCode, int> operation_counter_; | |
| 145 }; | |
| 146 | |
| 147 // A factory for constructing DownloadFiles that inject errors. | |
| 148 class DownloadFileWithErrorsFactory | |
| 149 : public DownloadFileManager::DownloadFileFactory { | |
| 150 public: | |
| 151 | |
| 152 explicit DownloadFileWithErrorsFactory( | |
| 153 scoped_refptr<TestFileErrorInjectorImpl> injector); | |
| 154 | |
| 155 virtual ~DownloadFileWithErrorsFactory(); | |
| 156 | |
| 157 virtual content::DownloadFile* CreateFile( | |
| 158 DownloadCreateInfo* info, | |
| 159 const DownloadRequestHandle& request_handle, | |
| 160 content::DownloadManager* download_manager, | |
| 161 bool calculate_hash, | |
| 162 const net::BoundNetLog& bound_net_log); | |
| 163 | |
| 164 private: | |
| 165 | |
| 166 scoped_refptr<TestFileErrorInjectorImpl> injector_; | |
| 167 }; | |
| 168 | |
| 169 | |
| 170 // Implementations. | |
| 171 | |
| 172 // static | |
| 173 TestFileErrorInjector* TestFileErrorInjector::Create() { | |
| 174 return new TestFileErrorInjectorImpl; | |
| 175 } | |
| 176 | |
| 177 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() : file_counter_(0) { | |
| 178 DownloadFileWithErrorsFactory* download_file_factory = | |
| 179 new DownloadFileWithErrorsFactory(this); | |
| 180 DownloadFileManager* download_file_manager = GetDownloadFileManager(); | |
| 181 DCHECK(download_file_manager); | |
| 182 // Transfers ownership. | |
| 183 download_file_manager->SetFileFactory(download_file_factory); | |
| 184 } | |
| 185 | |
| 186 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { | |
| 187 } | |
| 188 | |
| 189 bool TestFileErrorInjectorImpl::InjectError(int file_index, | |
| 190 FileOperationCode operation, | |
| 191 int operation_instance, | |
| 192 net::Error net_error) { | |
| 193 DCHECK_LE(0, file_index); | |
| 194 DCHECK_LE(0, operation_instance); | |
| 195 | |
| 196 // Fill in a new entry. | |
| 197 FileErrorInfo info; | |
| 198 info.file_index = file_index; | |
| 199 info.code = operation; | |
| 200 info.operation_instance = operation_instance; | |
| 201 info.net_error = net_error; | |
| 202 | |
| 203 // Creates an empty entry if necessary. | |
| 204 FileErrors& file_errors = injected_errors_[file_index]; | |
| 205 file_errors.error_list.push_back(info); | |
| 206 | |
| 207 // 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.
| |
| 208 if (file_errors.file != NULL) | |
| 209 file_errors.file->AddError(info); | |
| 210 | |
| 211 return true; | |
| 212 } | |
| 213 | |
| 214 size_t TestFileErrorInjectorImpl::CurrentFileCount() const { | |
| 215 size_t count = 0; | |
| 216 | |
| 217 // Count the map entries with a non-NULL file pointer. | |
| 218 for (std::map<int, FileErrors>::const_iterator it = injected_errors_.begin(); | |
| 219 it != injected_errors_.end(); | |
| 220 ++it) { | |
| 221 if (it->second.file != NULL) | |
| 222 count++; | |
| 223 } | |
| 224 | |
| 225 return count; | |
| 226 } | |
| 227 | |
| 228 int TestFileErrorInjectorImpl::DownloadFileCreated( | |
| 229 DownloadFileWithErrors* download_file) { | |
| 230 DCHECK(download_file != NULL); | |
| 231 | |
| 232 // Creates an empty instance if necessary. | |
| 233 FileErrors& file_errors = injected_errors_[file_counter_]; | |
| 234 DCHECK(file_errors.file == NULL); | |
| 235 file_errors.file = download_file; // Set the file. | |
| 236 | |
| 237 download_file->SetErrorList(file_counter_, file_errors.error_list); | |
| 238 | |
| 239 return file_counter_++; | |
| 240 } | |
| 241 | |
| 242 void TestFileErrorInjectorImpl::DestroyingDownloadFile( | |
| 243 DownloadFileWithErrors* download_file) { | |
| 244 DCHECK(download_file != NULL); | |
| 245 | |
| 246 // Mark as gone by making the file NULL. | |
| 247 injected_errors_[download_file->index()].file = NULL; | |
| 248 } | |
| 249 | |
| 250 DownloadFileWithErrors::DownloadFileWithErrors( | |
| 251 const DownloadCreateInfo* info, | |
| 252 DownloadRequestHandleInterface* request_handle, | |
| 253 content::DownloadManager* download_manager, | |
| 254 bool calculate_hash, | |
| 255 const net::BoundNetLog& bound_net_log, | |
| 256 scoped_refptr<TestFileErrorInjectorImpl> injector) | |
| 257 : DownloadFileImpl(info, | |
| 258 request_handle, | |
| 259 download_manager, | |
| 260 calculate_hash, | |
| 261 bound_net_log), | |
| 262 injector_(injector), | |
| 263 index_(-1) { | |
| 264 if (injector_) | |
| 265 injector_->DownloadFileCreated(this); | |
| 266 } | |
| 267 | |
| 268 DownloadFileWithErrors::~DownloadFileWithErrors() { | |
| 269 if (injector_) | |
| 270 injector_->DestroyingDownloadFile(this); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 net::Error DownloadFileWithErrors::Initialize() { | |
| 275 return ShouldReturnError(FILE_OPERATION_INITIALIZE, | |
| 276 DownloadFileImpl::Initialize()); | |
| 277 } | |
| 278 | |
| 279 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, | |
| 280 size_t data_len) { | |
| 281 return ShouldReturnError(FILE_OPERATION_WRITE, | |
| 282 DownloadFileImpl::AppendDataToFile(data, data_len)); | |
| 283 } | |
| 284 | |
| 285 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { | |
| 286 return ShouldReturnError(FILE_OPERATION_RENAME, | |
| 287 DownloadFileImpl::Rename(full_path)); | |
| 288 } | |
| 289 | |
| 290 net::Error DownloadFileWithErrors::ShouldReturnError( | |
| 291 FileOperationCode code, | |
| 292 net::Error original_net_error) { | |
| 293 int counter = operation_counter_[code]; | |
| 294 ++operation_counter_[code]; | |
| 295 | |
| 296 if (error_map_.find(code) == error_map_.end()) | |
| 297 return original_net_error; // No errors for this operation. | |
| 298 | |
| 299 InstanceMap& instance_map = error_map_[code]; | |
| 300 | |
| 301 if (instance_map.find(counter) == instance_map.end()) | |
| 302 return original_net_error; // No error for this instance of the operation. | |
| 303 | |
| 304 DVLOG(20) << " " << __FUNCTION__ << "()" | |
| 305 << " code = " << ::DebugString(code) << " (" << code << ")" | |
| 306 << " counter = " << counter | |
| 307 << " original_error = " << original_net_error | |
| 308 << " new error = " << instance_map[counter].net_error; | |
| 309 | |
| 310 return instance_map[counter].net_error; // Error! | |
| 311 } | |
| 312 | |
| 313 void DownloadFileWithErrors::AddError( | |
| 314 const FileErrorInfo& info) { | |
| 315 // Get the instance map for the operation code. | |
| 316 InstanceMap& instance_map = error_map_[info.code]; | |
| 317 | |
| 318 // Duplicate entries are an error. | |
| 319 DCHECK(instance_map.end() == instance_map.find(info.operation_instance)); | |
| 320 | |
| 321 // Set the error information in the map. | |
| 322 instance_map[info.operation_instance] = info; | |
| 323 } | |
| 324 | |
| 325 void DownloadFileWithErrors::SetErrorList( | |
| 326 int index, const ErrorList& error_list) { | |
| 327 DCHECK_EQ(-1, index_); | |
| 328 DCHECK_LE(0, index); | |
| 329 index_ = index; | |
| 330 | |
| 331 // Parcel out the error list by operation code and instance. | |
| 332 for (size_t i = 0; i < error_list.size(); ++i) | |
| 333 AddError(error_list[i]); | |
| 334 } | |
| 335 | |
| 336 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( | |
| 337 scoped_refptr<TestFileErrorInjectorImpl> injector) : injector_(injector) { | |
| 338 } | |
| 339 | |
| 340 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { | |
| 341 } | |
| 342 | |
| 343 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( | |
| 344 DownloadCreateInfo* info, | |
| 345 const DownloadRequestHandle& request_handle, | |
| 346 content::DownloadManager* download_manager, | |
| 347 bool calculate_hash, | |
| 348 const net::BoundNetLog& bound_net_log) { | |
| 349 return new DownloadFileWithErrors(info, | |
| 350 new DownloadRequestHandle(request_handle), | |
| 351 download_manager, | |
| 352 calculate_hash, | |
| 353 bound_net_log, | |
| 354 injector_); | |
| 355 } | |
| OLD | NEW |