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 TestFileErrorInjectorImpl; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Structure that encapsulates the information needed to inject a file error. | |
| 21 struct FileErrorInfo { | |
|
cbentzel
2012/02/27 02:18:54
This is kind of duplicated in the browsertest. Per
ahendrickson
2012/02/28 03:28:56
Done.
| |
| 22 FileErrorInfo() | |
| 23 : file_index(-1), | |
| 24 code(content::FILE_OPERATION_INITIALIZE), | |
| 25 operation_instance(-1), | |
| 26 net_error(net::OK) { | |
| 27 } | |
| 28 | |
| 29 int file_index; // 0-based index into created DownloadFile instances. | |
| 30 content::FileOperationCode code; // Operation to affect. | |
| 31 int operation_instance; // 0-based count of operation calls. | |
| 32 net::Error net_error; // Error to inject. | |
| 33 }; | |
| 34 | |
| 35 DownloadFileManager* GetDownloadFileManager() { | |
| 36 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); | |
| 37 DCHECK(rdh != NULL); | |
|
cbentzel
2012/02/27 02:18:54
What cases could it be NULL?
ahendrickson
2012/02/28 03:28:56
There are tests (perhaps just unit tests) where RD
| |
| 38 return rdh->download_file_manager(); | |
| 39 } | |
| 40 | |
| 41 std::string DebugString(content::FileOperationCode code) { | |
|
cbentzel
2012/02/27 02:18:54
Is this needed?
ahendrickson
2012/02/28 03:28:56
It's used below. I think it's useful to trace err
| |
| 42 | |
| 43 #define TO_STRING(code) case content::FILE_OPERATION_##code: return #code | |
| 44 | |
| 45 switch (code) { | |
| 46 TO_STRING(INITIALIZE); | |
| 47 TO_STRING(WRITE); | |
| 48 TO_STRING(RENAME); | |
| 49 default: | |
| 50 break; | |
| 51 } | |
| 52 | |
| 53 #undef TO_STRING | |
| 54 | |
| 55 return "Unknown"; | |
| 56 } | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 namespace content { | |
| 61 | |
| 62 // A class that performs file operations and injects errors. | |
| 63 class DownloadFileWithErrors: public DownloadFileImpl { | |
|
cbentzel
2012/02/27 02:18:54
Could this be in an anonymous nested namespace in
ahendrickson
2012/02/28 03:28:56
Done.
| |
| 64 public: | |
| 65 DownloadFileWithErrors(const DownloadCreateInfo* info, | |
| 66 DownloadRequestHandleInterface* request_handle, | |
| 67 content::DownloadManager* download_manager, | |
| 68 bool calculate_hash, | |
| 69 const net::BoundNetLog& bound_net_log, | |
| 70 const FileErrorInfo error_info, | |
| 71 TestFileErrorInjectorImpl* injector); | |
| 72 | |
| 73 ~DownloadFileWithErrors(); | |
| 74 | |
| 75 // DownloadFile interface. | |
| 76 virtual net::Error Initialize() OVERRIDE; | |
| 77 virtual net::Error AppendDataToFile(const char* data, | |
| 78 size_t data_len) OVERRIDE; | |
| 79 virtual net::Error Rename(const FilePath& full_path) OVERRIDE; | |
| 80 | |
| 81 // For |TestFileErrorInjectorImpl| to record lifetime. | |
| 82 int index() const { return error_info_.file_index; } | |
| 83 | |
| 84 private: | |
| 85 // Error generating helper. | |
| 86 net::Error ShouldReturnError(FileOperationCode code, | |
| 87 net::Error original_net_error); | |
| 88 | |
| 89 // The class that injects errors. | |
| 90 TestFileErrorInjectorImpl* injector_; // Needed for destructor. | |
| 91 | |
| 92 // Our injected error. Only one per file. | |
| 93 FileErrorInfo error_info_; | |
| 94 | |
| 95 // Count per operation. 0-based. | |
| 96 std::map<FileOperationCode, int> operation_counter_; | |
| 97 }; | |
| 98 | |
| 99 // A factory for constructing DownloadFiles that inject errors. | |
| 100 class DownloadFileWithErrorsFactory | |
| 101 : public DownloadFileManager::DownloadFileFactory { | |
| 102 public: | |
| 103 | |
| 104 explicit DownloadFileWithErrorsFactory(TestFileErrorInjectorImpl* injector); | |
| 105 virtual ~DownloadFileWithErrorsFactory(); | |
| 106 | |
| 107 // DownloadFileFactory interface. | |
| 108 virtual content::DownloadFile* CreateFile( | |
| 109 DownloadCreateInfo* info, | |
| 110 const DownloadRequestHandle& request_handle, | |
| 111 content::DownloadManager* download_manager, | |
| 112 bool calculate_hash, | |
| 113 const net::BoundNetLog& bound_net_log); | |
| 114 | |
| 115 bool InjectError(int file_index, | |
| 116 content::FileOperationCode operation, | |
| 117 int operation_instance, | |
| 118 net::Error net_error); | |
| 119 | |
| 120 size_t files_created() const { return file_counter_; } | |
| 121 | |
| 122 private: | |
| 123 // The number of files we've created. | |
| 124 int file_counter_; | |
| 125 | |
| 126 // We pass this to DownloadFileWithErrors, for lifetime tracking. | |
| 127 // We own this. | |
| 128 TestFileErrorInjectorImpl* injector_; | |
|
cbentzel
2012/02/26 15:01:48
scoped_ptr is much clearer declaration of ownershi
ahendrickson
2012/02/28 03:28:56
Now using RefCountedThreadSafe.
| |
| 129 | |
| 130 // Our injected error list, mapped by file index. One per file. | |
| 131 std::map<int, FileErrorInfo> injected_errors_; | |
| 132 }; | |
| 133 | |
| 134 } // namespace content | |
| 135 | |
| 136 class TestFileErrorInjectorImpl : public content::TestFileErrorInjector { | |
| 137 public: | |
| 138 TestFileErrorInjectorImpl(); | |
| 139 virtual ~TestFileErrorInjectorImpl(); | |
| 140 | |
| 141 // content::TestFileErrorInjector interface. | |
| 142 virtual bool InjectError(int file_index, | |
| 143 content::FileOperationCode operation, | |
| 144 int operation_instance, | |
| 145 net::Error net_error) OVERRIDE; | |
| 146 virtual size_t CurrentFileCount() const OVERRIDE; | |
| 147 virtual size_t FileCreationCount() const OVERRIDE; | |
| 148 virtual bool HasFile(int file_index) const OVERRIDE; | |
| 149 | |
| 150 // Callbacks from the download file, to record lifetimes. | |
| 151 virtual void DownloadFileCreated( | |
| 152 content::DownloadFileWithErrors* download_file); | |
| 153 virtual void DestroyingDownloadFile( | |
| 154 content::DownloadFileWithErrors* download_file); | |
| 155 | |
| 156 private: | |
| 157 typedef std::map<int, content::DownloadFileWithErrors*> FileMap; | |
| 158 | |
| 159 // Keep track of active DownloadFiles. | |
| 160 FileMap files_; | |
| 161 | |
| 162 content::DownloadFileWithErrorsFactory* download_file_factory_; | |
| 163 | |
| 164 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); | |
| 165 }; | |
| 166 | |
| 167 | |
| 168 // Implementations. | |
| 169 namespace content { | |
| 170 | |
| 171 DownloadFileWithErrors::DownloadFileWithErrors( | |
| 172 const DownloadCreateInfo* info, | |
| 173 DownloadRequestHandleInterface* request_handle, | |
| 174 content::DownloadManager* download_manager, | |
| 175 bool calculate_hash, | |
| 176 const net::BoundNetLog& bound_net_log, | |
| 177 const FileErrorInfo error_info, | |
| 178 TestFileErrorInjectorImpl* injector) | |
| 179 : DownloadFileImpl(info, | |
| 180 request_handle, | |
| 181 download_manager, | |
| 182 calculate_hash, | |
| 183 bound_net_log), | |
| 184 injector_(injector), | |
| 185 error_info_(error_info) { | |
| 186 // Record creation. | |
| 187 injector_->DownloadFileCreated(this); | |
|
cbentzel
2012/02/27 02:18:54
Are you worried at all about thread-safety issues
ahendrickson
2012/02/28 03:28:56
Switched to using RefCountedThreadSafe for the inj
| |
| 188 } | |
| 189 | |
| 190 DownloadFileWithErrors::~DownloadFileWithErrors() { | |
| 191 // Record destruction. | |
| 192 injector_->DestroyingDownloadFile(this); | |
| 193 } | |
| 194 | |
| 195 | |
| 196 net::Error DownloadFileWithErrors::Initialize() { | |
| 197 return ShouldReturnError(FILE_OPERATION_INITIALIZE, | |
| 198 DownloadFileImpl::Initialize()); | |
| 199 } | |
| 200 | |
| 201 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, | |
| 202 size_t data_len) { | |
| 203 return ShouldReturnError(FILE_OPERATION_WRITE, | |
| 204 DownloadFileImpl::AppendDataToFile(data, data_len)); | |
| 205 } | |
| 206 | |
| 207 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { | |
| 208 return ShouldReturnError(FILE_OPERATION_RENAME, | |
| 209 DownloadFileImpl::Rename(full_path)); | |
| 210 } | |
| 211 | |
| 212 net::Error DownloadFileWithErrors::ShouldReturnError( | |
| 213 FileOperationCode code, | |
| 214 net::Error original_net_error) { | |
| 215 int counter = operation_counter_[code]; | |
|
cbentzel
2012/02/27 02:18:54
Looks like the operation_instance is always 0 when
ahendrickson
2012/02/28 03:28:56
Would prefer not to, as I have a use for this in m
| |
| 216 ++operation_counter_[code]; | |
| 217 | |
| 218 if (code != error_info_.code) | |
| 219 return original_net_error; // No error for this operation. | |
|
cbentzel
2012/02/27 02:18:54
Comments not really needed and a bit unclear actua
ahendrickson
2012/02/28 03:28:56
Removed.
| |
| 220 | |
| 221 if (counter != error_info_.operation_instance) | |
| 222 return original_net_error; // No error for this instance of the operation. | |
| 223 | |
| 224 DVLOG(20) << " " << __FUNCTION__ << "()" | |
| 225 << " code = " << ::DebugString(code) << " (" << code << ")" | |
| 226 << " counter = " << counter | |
| 227 << " original_error = " << original_net_error | |
| 228 << " new error = " << error_info_.net_error; | |
| 229 | |
| 230 return error_info_.net_error; // Error! | |
| 231 } | |
| 232 | |
| 233 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( | |
| 234 TestFileErrorInjectorImpl* injector) | |
|
cbentzel
2012/02/27 02:18:54
should be passed in via scoped_ptr if the Factory
ahendrickson
2012/02/28 03:28:56
Now using RefCountedThreadSafe for the injector.
| |
| 235 : file_counter_(0), injector_(injector) { | |
| 236 } | |
| 237 | |
| 238 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { | |
| 239 delete injector_; | |
| 240 injector_ = NULL; | |
| 241 } | |
| 242 | |
| 243 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( | |
| 244 DownloadCreateInfo* info, | |
| 245 const DownloadRequestHandle& request_handle, | |
| 246 content::DownloadManager* download_manager, | |
| 247 bool calculate_hash, | |
| 248 const net::BoundNetLog& bound_net_log) { | |
| 249 // Creates entry if it doesn't exist. | |
| 250 injected_errors_[file_counter_].file_index = file_counter_; // Set index. | |
| 251 return new DownloadFileWithErrors(info, | |
| 252 new DownloadRequestHandle(request_handle), | |
| 253 download_manager, | |
| 254 calculate_hash, | |
| 255 bound_net_log, | |
| 256 injected_errors_[file_counter_++], | |
| 257 injector_); | |
| 258 } | |
| 259 | |
| 260 bool DownloadFileWithErrorsFactory::InjectError( | |
| 261 int file_index, | |
| 262 content::FileOperationCode operation, | |
| 263 int operation_instance, | |
| 264 net::Error net_error) { | |
| 265 DCHECK_LE(0, file_index); | |
| 266 DCHECK_LE(0, operation_instance); | |
| 267 | |
| 268 // Fill in a new entry. | |
| 269 FileErrorInfo info; | |
| 270 info.file_index = file_index; | |
| 271 info.code = operation; | |
| 272 info.operation_instance = operation_instance; | |
| 273 info.net_error = net_error; | |
| 274 | |
| 275 // Creates an empty entry if necessary. | |
| 276 injected_errors_[file_index] = info; | |
| 277 | |
| 278 return true; | |
| 279 } | |
| 280 | |
| 281 } // namespace content | |
| 282 | |
| 283 | |
| 284 // static | |
| 285 content::TestFileErrorInjector* content::TestFileErrorInjector::Create() { | |
| 286 return new TestFileErrorInjectorImpl; | |
| 287 } | |
| 288 | |
| 289 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() | |
| 290 : download_file_factory_(new content::DownloadFileWithErrorsFactory(this)) { | |
| 291 // |DownloadFileWithErrorsFactory| now owns |TestFileErrorInjectorImpl|. | |
| 292 DownloadFileManager* download_file_manager = | |
| 293 GetDownloadFileManager(); | |
| 294 DCHECK(download_file_manager); | |
| 295 // Transfers ownership to |DownloadFileManager|. | |
| 296 download_file_manager->SetFileFactory(download_file_factory_); | |
| 297 } | |
| 298 | |
| 299 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { | |
| 300 } | |
| 301 | |
| 302 bool TestFileErrorInjectorImpl::InjectError( | |
| 303 int file_index, | |
| 304 content::FileOperationCode operation, | |
| 305 int operation_instance, | |
| 306 net::Error net_error) { | |
| 307 return download_file_factory_->InjectError(file_index, | |
| 308 operation, | |
| 309 operation_instance, | |
| 310 net_error); | |
| 311 } | |
| 312 | |
| 313 size_t TestFileErrorInjectorImpl::CurrentFileCount() const { | |
| 314 return files_.size(); | |
|
cbentzel
2012/02/27 02:18:54
What is the thread-safety here?
ahendrickson
2012/02/28 03:28:56
All operations on files_ now happen on the UI thre
| |
| 315 } | |
| 316 | |
| 317 size_t TestFileErrorInjectorImpl::FileCreationCount() const { | |
| 318 return download_file_factory_->files_created(); | |
| 319 } | |
| 320 | |
| 321 | |
| 322 bool TestFileErrorInjectorImpl::HasFile(int file_index) const { | |
|
cbentzel
2012/02/27 02:18:54
You aren't using this. Would also remove the need
ahendrickson
2012/02/28 03:28:56
Now using it.
| |
| 323 return (files_.find(file_index) != files_.end()); | |
| 324 } | |
| 325 | |
| 326 void TestFileErrorInjectorImpl::DownloadFileCreated( | |
| 327 content::DownloadFileWithErrors* download_file) { | |
| 328 DCHECK(download_file != NULL); | |
| 329 | |
| 330 files_[download_file->index()] = download_file; | |
| 331 } | |
| 332 | |
| 333 void TestFileErrorInjectorImpl::DestroyingDownloadFile( | |
| 334 content::DownloadFileWithErrors* download_file) { | |
| 335 DCHECK(download_file != NULL); | |
| 336 | |
| 337 files_.erase(download_file->index()); | |
| 338 } | |
| OLD | NEW |