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/public/browser/browser_thread.h" | |
| 13 #include "content/browser/download/download_file_impl.h" | |
| 14 #include "content/browser/download/download_file_manager.h" | |
| 15 #include "content/browser/renderer_host/resource_dispatcher_host.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 class DownloadFileWithErrors; | |
| 20 class DownloadFileWithErrorsFactory; | |
| 21 | |
| 22 typedef std::map<int, content::TestFileErrorInjector::FileErrorInfo> ErrorMap; | |
| 23 | |
| 24 DownloadFileManager* GetDownloadFileManager() { | |
| 25 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); | |
| 26 DCHECK(rdh != NULL); | |
| 27 return rdh->download_file_manager(); | |
| 28 } | |
| 29 | |
| 30 class TestFileErrorInjectorImpl : public content::TestFileErrorInjector { | |
| 31 public: | |
| 32 typedef base::Callback<void(int index, bool creating)> DownloadFileCallback; | |
|
cbentzel
2012/02/28 14:51:41
Design nit: You typically want this on the Downloa
ahendrickson
2012/03/01 09:17:32
I wanted this class to be the first one declared.
| |
| 33 | |
| 34 TestFileErrorInjectorImpl(); | |
| 35 | |
| 36 // content::TestFileErrorInjector interface. | |
| 37 virtual bool AddError(const FileErrorInfo& error_info) OVERRIDE; | |
| 38 virtual bool InjectErrors() OVERRIDE; | |
| 39 virtual size_t CurrentFileCount() const OVERRIDE; | |
| 40 virtual size_t FileCreationCount() const OVERRIDE; | |
| 41 virtual bool HasFile(int file_index) const OVERRIDE; | |
| 42 | |
| 43 // Callbacks from the download file, to record lifetimes. | |
|
Randy Smith (Not in Mondays)
2012/02/28 22:06:13
nit: Aren't these callbacks from the factory, not
ahendrickson
2012/03/01 09:17:32
No, the factory passes the callback objects to the
Randy Smith (Not in Mondays)
2012/03/01 20:28:24
Right, got it--sorry for the confusion.
| |
| 44 virtual void DownloadFileCreated(int file_index); | |
|
cbentzel
2012/02/28 14:51:41
These don't need to be virtual. Could also be priv
ahendrickson
2012/03/01 09:17:32
Done.
| |
| 45 virtual void DestroyingDownloadFile(int file_index); | |
| 46 | |
| 47 private: | |
| 48 virtual ~TestFileErrorInjectorImpl(); | |
| 49 | |
| 50 void RecordDownloadFileConstructionDestruction(int index, bool creating); | |
| 51 | |
| 52 typedef std::set<int> FileSet; | |
| 53 | |
| 54 // Our injected error list, mapped by file index. One per file. | |
|
Randy Smith (Not in Mondays)
2012/02/28 22:06:13
This is the first time I noticed that we could onl
ahendrickson
2012/03/01 09:17:32
I added a comment to AddError().
| |
| 55 ErrorMap injected_errors_; | |
| 56 | |
| 57 // Keep track of active DownloadFiles. | |
| 58 FileSet files_; | |
| 59 | |
| 60 // We have created a factory. Used for validation. | |
| 61 bool created_factory_; | |
| 62 | |
| 63 // The number of files we've recorded. | |
| 64 int file_counter_; | |
| 65 | |
| 66 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); | |
| 67 }; | |
| 68 | |
| 69 // A class that performs file operations and injects errors. | |
| 70 class DownloadFileWithErrors: public DownloadFileImpl { | |
| 71 public: | |
| 72 DownloadFileWithErrors( | |
| 73 const DownloadCreateInfo* info, | |
| 74 DownloadRequestHandleInterface* request_handle, | |
| 75 content::DownloadManager* download_manager, | |
| 76 bool calculate_hash, | |
| 77 const net::BoundNetLog& bound_net_log, | |
| 78 const content::TestFileErrorInjector::FileErrorInfo& error_info, | |
| 79 const TestFileErrorInjectorImpl::DownloadFileCallback& callback); | |
| 80 | |
| 81 ~DownloadFileWithErrors(); | |
| 82 | |
| 83 // DownloadFile interface. | |
| 84 virtual net::Error Initialize() OVERRIDE; | |
| 85 virtual net::Error AppendDataToFile(const char* data, | |
| 86 size_t data_len) OVERRIDE; | |
| 87 virtual net::Error Rename(const FilePath& full_path) OVERRIDE; | |
| 88 | |
| 89 private: | |
| 90 // Error generating helper. | |
| 91 net::Error ShouldReturnError( | |
| 92 content::TestFileErrorInjector::FileOperationCode code, | |
| 93 net::Error original_net_error); | |
| 94 | |
| 95 // Our injected error. Only one per file. | |
| 96 content::TestFileErrorInjector::FileErrorInfo error_info_; | |
| 97 | |
| 98 // Count per operation. 0-based. | |
| 99 std::map<content::TestFileErrorInjector::FileOperationCode, int> | |
| 100 operation_counter_; | |
| 101 | |
| 102 // Callback for creation and destruction. | |
| 103 TestFileErrorInjectorImpl::DownloadFileCallback callback_; | |
| 104 }; | |
| 105 | |
| 106 // A factory for constructing DownloadFiles that inject errors. | |
| 107 class DownloadFileWithErrorsFactory | |
| 108 : public DownloadFileManager::DownloadFileFactory { | |
| 109 public: | |
| 110 | |
| 111 DownloadFileWithErrorsFactory( | |
| 112 const TestFileErrorInjectorImpl::DownloadFileCallback& callback); | |
| 113 virtual ~DownloadFileWithErrorsFactory(); | |
| 114 | |
| 115 // DownloadFileFactory interface. | |
| 116 virtual content::DownloadFile* CreateFile( | |
| 117 DownloadCreateInfo* info, | |
| 118 const DownloadRequestHandle& request_handle, | |
| 119 content::DownloadManager* download_manager, | |
| 120 bool calculate_hash, | |
| 121 const net::BoundNetLog& bound_net_log); | |
| 122 | |
| 123 bool AddError( | |
| 124 const content::TestFileErrorInjector::FileErrorInfo& error_info); | |
| 125 | |
| 126 size_t files_created() const { return file_counter_; } | |
| 127 | |
| 128 private: | |
| 129 // Number of files we've created. | |
| 130 size_t file_counter_; | |
| 131 | |
| 132 // Our injected error list, mapped by file index. One per file. | |
| 133 ErrorMap injected_errors_; | |
| 134 | |
| 135 // Callback for creation and destruction. | |
| 136 TestFileErrorInjectorImpl::DownloadFileCallback callback_; | |
| 137 }; | |
| 138 | |
| 139 // Implementations. | |
| 140 | |
| 141 DownloadFileWithErrors::DownloadFileWithErrors( | |
| 142 const DownloadCreateInfo* info, | |
| 143 DownloadRequestHandleInterface* request_handle, | |
| 144 content::DownloadManager* download_manager, | |
| 145 bool calculate_hash, | |
| 146 const net::BoundNetLog& bound_net_log, | |
| 147 const content::TestFileErrorInjector::FileErrorInfo& error_info, | |
| 148 const TestFileErrorInjectorImpl::DownloadFileCallback& callback) | |
| 149 : DownloadFileImpl(info, | |
| 150 request_handle, | |
| 151 download_manager, | |
| 152 calculate_hash, | |
| 153 bound_net_log), | |
| 154 error_info_(error_info), | |
| 155 callback_(callback) { | |
| 156 // Record creation. | |
| 157 callback_.Run(error_info_.file_index, true); | |
| 158 } | |
| 159 | |
| 160 DownloadFileWithErrors::~DownloadFileWithErrors() { | |
| 161 // Record destruction. | |
| 162 callback_.Run(error_info_.file_index, false); | |
| 163 } | |
| 164 | |
| 165 | |
| 166 net::Error DownloadFileWithErrors::Initialize() { | |
| 167 return ShouldReturnError( | |
| 168 content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE, | |
| 169 DownloadFileImpl::Initialize()); | |
| 170 } | |
| 171 | |
| 172 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, | |
| 173 size_t data_len) { | |
| 174 return ShouldReturnError( | |
| 175 content::TestFileErrorInjector::FILE_OPERATION_WRITE, | |
| 176 DownloadFileImpl::AppendDataToFile(data, data_len)); | |
| 177 } | |
| 178 | |
| 179 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { | |
| 180 return ShouldReturnError( | |
| 181 content::TestFileErrorInjector::FILE_OPERATION_RENAME, | |
| 182 DownloadFileImpl::Rename(full_path)); | |
| 183 } | |
| 184 | |
| 185 net::Error DownloadFileWithErrors::ShouldReturnError( | |
| 186 content::TestFileErrorInjector::FileOperationCode code, | |
| 187 net::Error original_net_error) { | |
| 188 int counter = operation_counter_[code]; | |
|
cbentzel
2012/02/28 14:51:41
I'd get rid of the operation_counter_ map here - n
ahendrickson
2012/03/02 21:58:47
We're now using operation instances other than 0.
| |
| 189 ++operation_counter_[code]; | |
| 190 | |
| 191 if (code != error_info_.code) | |
| 192 return original_net_error; | |
| 193 | |
| 194 if (counter != error_info_.operation_instance) | |
| 195 return original_net_error; | |
| 196 | |
| 197 VLOG(1) << " " << __FUNCTION__ << "()" | |
| 198 << " code = " << content::TestFileErrorInjector::DebugString(code) | |
| 199 << " (" << code << ")" | |
| 200 << " counter = " << counter | |
| 201 << " original_error = " << original_net_error | |
| 202 << " new error = " << error_info_.net_error; | |
| 203 | |
| 204 return error_info_.net_error; | |
| 205 } | |
| 206 | |
| 207 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( | |
| 208 const TestFileErrorInjectorImpl::DownloadFileCallback& callback) | |
| 209 : file_counter_(0), callback_(callback) { | |
| 210 } | |
| 211 | |
| 212 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { | |
| 213 } | |
| 214 | |
| 215 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( | |
| 216 DownloadCreateInfo* info, | |
| 217 const DownloadRequestHandle& request_handle, | |
| 218 content::DownloadManager* download_manager, | |
| 219 bool calculate_hash, | |
| 220 const net::BoundNetLog& bound_net_log) { | |
| 221 // Creates entry if it doesn't exist. | |
| 222 injected_errors_[file_counter_].file_index = file_counter_; // Set index. | |
| 223 return new DownloadFileWithErrors(info, | |
| 224 new DownloadRequestHandle(request_handle), | |
| 225 download_manager, | |
| 226 calculate_hash, | |
| 227 bound_net_log, | |
| 228 injected_errors_[file_counter_++], | |
|
Randy Smith (Not in Mondays)
2012/02/28 22:06:13
What happens if this accesses an uninitialized ent
ahendrickson
2012/03/01 09:17:32
No error is injected.
Randy Smith (Not in Mondays)
2012/03/01 20:28:24
I think Chris did the analysis that I was worried
ahendrickson
2012/03/02 21:58:47
Fixed.
| |
| 229 callback_); | |
| 230 } | |
| 231 | |
| 232 bool DownloadFileWithErrorsFactory::AddError( | |
| 233 const content::TestFileErrorInjector::FileErrorInfo& error_info) { | |
| 234 DCHECK_LE(0, error_info.file_index); | |
| 235 DCHECK_LE(0, error_info.operation_instance); | |
| 236 | |
| 237 // Creates an empty entry if necessary. | |
| 238 injected_errors_[error_info.file_index] = error_info; | |
|
Randy Smith (Not in Mondays)
2012/02/28 22:06:13
Should this interface allow us to overwrite alread
ahendrickson
2012/03/01 09:17:32
No, although it just replaces the existing value.
| |
| 239 | |
| 240 return true; | |
| 241 } | |
| 242 | |
| 243 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() | |
| 244 : created_factory_(false), file_counter_(0) { | |
| 245 } | |
| 246 | |
| 247 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { | |
| 248 } | |
| 249 | |
| 250 bool TestFileErrorInjectorImpl::AddError(const FileErrorInfo& error_info) { | |
| 251 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 252 DCHECK(!created_factory_); | |
| 253 DCHECK_LE(0, error_info.file_index); | |
| 254 DCHECK_LE(0, error_info.operation_instance); | |
| 255 | |
| 256 // Creates an empty entry if necessary. | |
| 257 injected_errors_[error_info.file_index] = error_info; | |
|
cbentzel
2012/02/28 14:51:41
Why are you worried about adding support for a map
ahendrickson
2012/03/01 09:17:32
The new tests run multiple downloads, so we need t
| |
| 258 | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 262 bool TestFileErrorInjectorImpl::InjectErrors() { | |
| 263 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 264 DCHECK(!created_factory_); | |
| 265 | |
| 266 DownloadFileWithErrorsFactory* download_file_factory = | |
| 267 new DownloadFileWithErrorsFactory( | |
| 268 base::Bind( | |
| 269 &TestFileErrorInjectorImpl:: | |
| 270 RecordDownloadFileConstructionDestruction, | |
| 271 this)); | |
| 272 | |
| 273 for (ErrorMap::const_iterator it = injected_errors_.begin(); | |
| 274 it != injected_errors_.end(); | |
| 275 ++it) { | |
| 276 download_file_factory->AddError(it->second); | |
|
Randy Smith (Not in Mondays)
2012/02/28 22:06:13
nit, suggestion: You could create download_file_fa
ahendrickson
2012/03/01 09:17:32
I did that in an earlier pass, but Chris asked me
Randy Smith (Not in Mondays)
2012/03/01 20:28:24
Given that I think Chris just suggested the same i
| |
| 277 } | |
| 278 | |
| 279 DownloadFileManager* download_file_manager = GetDownloadFileManager(); | |
| 280 DCHECK(download_file_manager); | |
| 281 // Transfers ownership to |DownloadFileManager|. | |
|
cbentzel
2012/02/28 14:51:41
Use scoped_ptr.Pass here instead.
ahendrickson
2012/03/01 09:17:32
Done.
| |
| 282 download_file_manager->SetFileFactoryForTesting(download_file_factory); | |
| 283 | |
| 284 created_factory_ = true; | |
| 285 | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 size_t TestFileErrorInjectorImpl::CurrentFileCount() const { | |
| 290 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 291 return files_.size(); | |
| 292 } | |
| 293 | |
| 294 size_t TestFileErrorInjectorImpl::FileCreationCount() const { | |
| 295 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 296 return file_counter_; | |
| 297 } | |
| 298 | |
| 299 | |
| 300 bool TestFileErrorInjectorImpl::HasFile(int file_index) const { | |
| 301 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 302 return (files_.find(file_index) != files_.end()); | |
| 303 } | |
| 304 | |
| 305 void TestFileErrorInjectorImpl::DownloadFileCreated(int file_index) { | |
| 306 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 307 DCHECK_EQ(file_index, file_counter_); | |
| 308 | |
| 309 file_counter_++; | |
| 310 files_.insert(file_index); | |
| 311 } | |
| 312 | |
| 313 void TestFileErrorInjectorImpl::DestroyingDownloadFile(int file_index) { | |
| 314 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 315 | |
| 316 files_.erase(file_index); | |
| 317 } | |
| 318 | |
| 319 void TestFileErrorInjectorImpl::RecordDownloadFileConstructionDestruction( | |
| 320 int index, bool constructing) { | |
| 321 content::BrowserThread::PostTask( | |
| 322 content::BrowserThread::UI, | |
| 323 FROM_HERE, | |
| 324 base::Bind(constructing ? | |
| 325 &TestFileErrorInjectorImpl::DownloadFileCreated : | |
| 326 &TestFileErrorInjectorImpl::DestroyingDownloadFile, | |
| 327 this, | |
| 328 index)); | |
| 329 } | |
| 330 | |
| 331 } // namespace | |
| 332 | |
| 333 namespace content { | |
| 334 | |
| 335 // static | |
| 336 scoped_refptr<TestFileErrorInjector> TestFileErrorInjector::Create() { | |
| 337 return new TestFileErrorInjectorImpl; | |
| 338 } | |
| 339 | |
| 340 std::string TestFileErrorInjector::DebugString(FileOperationCode code) { | |
| 341 | |
| 342 #define TO_STRING(code) \ | |
|
cbentzel
2012/02/28 14:51:41
Although this macro is localized, it provides very
ahendrickson
2012/03/01 09:17:32
Removed the namespace reference.
It is now used i
Randy Smith (Not in Mondays)
2012/03/06 23:05:19
FWIW, I agree with Chris; I think writing it direc
| |
| 343 case content::TestFileErrorInjector::FILE_OPERATION_##code: return #code | |
| 344 | |
| 345 switch (code) { | |
| 346 TO_STRING(INITIALIZE); | |
| 347 TO_STRING(WRITE); | |
| 348 TO_STRING(RENAME); | |
| 349 default: | |
| 350 break; | |
| 351 } | |
| 352 | |
| 353 #undef TO_STRING | |
| 354 | |
| 355 return "Unknown"; | |
| 356 } | |
| 357 | |
| 358 } // namespace content | |
| OLD | NEW |