Removing uses of X11 native key events.
[chromium-blink-merge.git] / content / public / test / test_file_error_injector.cc
blob440156286b0bb90fb85290fafcdcee7fbd7b7c61
1 // Copyright (c) 2012 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.
5 #include "content/public/test/test_file_error_injector.h"
7 #include <vector>
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "content/browser/download/download_file_factory.h"
12 #include "content/browser/download/download_file_impl.h"
13 #include "content/browser/download/download_interrupt_reasons_impl.h"
14 #include "content/browser/download/download_manager_impl.h"
15 #include "content/browser/loader/resource_dispatcher_host_impl.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "url/gurl.h"
19 namespace content {
20 class ByteStreamReader;
22 namespace {
24 // A class that performs file operations and injects errors.
25 class DownloadFileWithErrors: public DownloadFileImpl {
26 public:
27 typedef base::Callback<void(const GURL& url)> ConstructionCallback;
28 typedef base::Callback<void(const GURL& url)> DestructionCallback;
30 DownloadFileWithErrors(
31 scoped_ptr<DownloadSaveInfo> save_info,
32 const base::FilePath& default_download_directory,
33 const GURL& url,
34 const GURL& referrer_url,
35 bool calculate_hash,
36 scoped_ptr<ByteStreamReader> stream,
37 const net::BoundNetLog& bound_net_log,
38 base::WeakPtr<DownloadDestinationObserver> observer,
39 const TestFileErrorInjector::FileErrorInfo& error_info,
40 const ConstructionCallback& ctor_callback,
41 const DestructionCallback& dtor_callback);
43 virtual ~DownloadFileWithErrors();
45 virtual void Initialize(const InitializeCallback& callback) OVERRIDE;
47 // DownloadFile interface.
48 virtual DownloadInterruptReason AppendDataToFile(
49 const char* data, size_t data_len) OVERRIDE;
50 virtual void RenameAndUniquify(
51 const base::FilePath& full_path,
52 const RenameCompletionCallback& callback) OVERRIDE;
53 virtual void RenameAndAnnotate(
54 const base::FilePath& full_path,
55 const RenameCompletionCallback& callback) OVERRIDE;
57 private:
58 // Error generating helper.
59 DownloadInterruptReason ShouldReturnError(
60 TestFileErrorInjector::FileOperationCode code,
61 DownloadInterruptReason original_error);
63 // Determine whether to overwrite an operation with the given code
64 // with a substitute error; if returns true, |*original_error| is
65 // written with the error to use for overwriting.
66 // NOTE: This routine changes state; specifically, it increases the
67 // operations counts for the specified code. It should only be called
68 // once per operation.
69 bool OverwriteError(
70 TestFileErrorInjector::FileOperationCode code,
71 DownloadInterruptReason* output_error);
73 // Source URL for the file being downloaded.
74 GURL source_url_;
76 // Our injected error. Only one per file.
77 TestFileErrorInjector::FileErrorInfo error_info_;
79 // Count per operation. 0-based.
80 std::map<TestFileErrorInjector::FileOperationCode, int> operation_counter_;
82 // Callback for destruction.
83 DestructionCallback destruction_callback_;
86 static void InitializeErrorCallback(
87 const DownloadFile::InitializeCallback original_callback,
88 DownloadInterruptReason overwrite_error,
89 DownloadInterruptReason original_error) {
90 original_callback.Run(overwrite_error);
93 static void RenameErrorCallback(
94 const DownloadFile::RenameCompletionCallback original_callback,
95 DownloadInterruptReason overwrite_error,
96 DownloadInterruptReason original_error,
97 const base::FilePath& path_result) {
98 original_callback.Run(
99 overwrite_error,
100 overwrite_error == DOWNLOAD_INTERRUPT_REASON_NONE ?
101 path_result : base::FilePath());
104 DownloadFileWithErrors::DownloadFileWithErrors(
105 scoped_ptr<DownloadSaveInfo> save_info,
106 const base::FilePath& default_download_directory,
107 const GURL& url,
108 const GURL& referrer_url,
109 bool calculate_hash,
110 scoped_ptr<ByteStreamReader> stream,
111 const net::BoundNetLog& bound_net_log,
112 base::WeakPtr<DownloadDestinationObserver> observer,
113 const TestFileErrorInjector::FileErrorInfo& error_info,
114 const ConstructionCallback& ctor_callback,
115 const DestructionCallback& dtor_callback)
116 : DownloadFileImpl(
117 save_info.Pass(), default_download_directory, url, referrer_url,
118 calculate_hash, stream.Pass(), bound_net_log, observer),
119 source_url_(url),
120 error_info_(error_info),
121 destruction_callback_(dtor_callback) {
122 // DownloadFiles are created on the UI thread and are destroyed on the FILE
123 // thread. Schedule the ConstructionCallback on the FILE thread so that if a
124 // DownloadItem schedules a DownloadFile to be destroyed and creates another
125 // one (as happens during download resumption), then the DestructionCallback
126 // for the old DownloadFile is run before the ConstructionCallback for the
127 // next DownloadFile.
128 BrowserThread::PostTask(
129 BrowserThread::FILE,
130 FROM_HERE,
131 base::Bind(ctor_callback, source_url_));
134 DownloadFileWithErrors::~DownloadFileWithErrors() {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
136 destruction_callback_.Run(source_url_);
139 void DownloadFileWithErrors::Initialize(
140 const InitializeCallback& callback) {
141 DownloadInterruptReason error_to_return = DOWNLOAD_INTERRUPT_REASON_NONE;
142 InitializeCallback callback_to_use = callback;
144 // Replace callback if the error needs to be overwritten.
145 if (OverwriteError(
146 TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
147 &error_to_return)) {
148 if (DOWNLOAD_INTERRUPT_REASON_NONE != error_to_return) {
149 // Don't execute a, probably successful, Initialize; just
150 // return the error.
151 BrowserThread::PostTask(
152 BrowserThread::UI, FROM_HERE, base::Bind(
153 callback, error_to_return));
154 return;
157 // Otherwise, just wrap the return.
158 callback_to_use = base::Bind(&InitializeErrorCallback, callback,
159 error_to_return);
162 DownloadFileImpl::Initialize(callback_to_use);
165 DownloadInterruptReason DownloadFileWithErrors::AppendDataToFile(
166 const char* data, size_t data_len) {
167 return ShouldReturnError(
168 TestFileErrorInjector::FILE_OPERATION_WRITE,
169 DownloadFileImpl::AppendDataToFile(data, data_len));
172 void DownloadFileWithErrors::RenameAndUniquify(
173 const base::FilePath& full_path,
174 const RenameCompletionCallback& callback) {
175 DownloadInterruptReason error_to_return = DOWNLOAD_INTERRUPT_REASON_NONE;
176 RenameCompletionCallback callback_to_use = callback;
178 // Replace callback if the error needs to be overwritten.
179 if (OverwriteError(
180 TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY,
181 &error_to_return)) {
182 if (DOWNLOAD_INTERRUPT_REASON_NONE != error_to_return) {
183 // Don't execute a, probably successful, RenameAndUniquify; just
184 // return the error.
185 BrowserThread::PostTask(
186 BrowserThread::UI, FROM_HERE, base::Bind(
187 callback, error_to_return, base::FilePath()));
188 return;
191 // Otherwise, just wrap the return.
192 callback_to_use = base::Bind(&RenameErrorCallback, callback,
193 error_to_return);
196 DownloadFileImpl::RenameAndUniquify(full_path, callback_to_use);
199 void DownloadFileWithErrors::RenameAndAnnotate(
200 const base::FilePath& full_path,
201 const RenameCompletionCallback& callback) {
202 DownloadInterruptReason error_to_return = DOWNLOAD_INTERRUPT_REASON_NONE;
203 RenameCompletionCallback callback_to_use = callback;
205 // Replace callback if the error needs to be overwritten.
206 if (OverwriteError(
207 TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE,
208 &error_to_return)) {
209 if (DOWNLOAD_INTERRUPT_REASON_NONE != error_to_return) {
210 // Don't execute a, probably successful, RenameAndAnnotate; just
211 // return the error.
212 BrowserThread::PostTask(
213 BrowserThread::UI, FROM_HERE, base::Bind(
214 callback, error_to_return, base::FilePath()));
215 return;
218 // Otherwise, just wrap the return.
219 callback_to_use = base::Bind(&RenameErrorCallback, callback,
220 error_to_return);
223 DownloadFileImpl::RenameAndAnnotate(full_path, callback_to_use);
226 bool DownloadFileWithErrors::OverwriteError(
227 TestFileErrorInjector::FileOperationCode code,
228 DownloadInterruptReason* output_error) {
229 int counter = operation_counter_[code]++;
231 if (code != error_info_.code)
232 return false;
234 if (counter != error_info_.operation_instance)
235 return false;
237 *output_error = error_info_.error;
238 return true;
241 DownloadInterruptReason DownloadFileWithErrors::ShouldReturnError(
242 TestFileErrorInjector::FileOperationCode code,
243 DownloadInterruptReason original_error) {
244 DownloadInterruptReason output_error = original_error;
245 OverwriteError(code, &output_error);
246 return output_error;
249 } // namespace
251 // A factory for constructing DownloadFiles that inject errors.
252 class DownloadFileWithErrorsFactory : public DownloadFileFactory {
253 public:
254 DownloadFileWithErrorsFactory(
255 const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
256 const DownloadFileWithErrors::DestructionCallback& dtor_callback);
257 virtual ~DownloadFileWithErrorsFactory();
259 // DownloadFileFactory interface.
260 virtual DownloadFile* CreateFile(
261 scoped_ptr<DownloadSaveInfo> save_info,
262 const base::FilePath& default_download_directory,
263 const GURL& url,
264 const GURL& referrer_url,
265 bool calculate_hash,
266 scoped_ptr<ByteStreamReader> stream,
267 const net::BoundNetLog& bound_net_log,
268 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE;
270 bool AddError(
271 const TestFileErrorInjector::FileErrorInfo& error_info);
273 void ClearErrors();
275 private:
276 // Our injected error list, mapped by URL. One per file.
277 TestFileErrorInjector::ErrorMap injected_errors_;
279 // Callback for creation and destruction.
280 DownloadFileWithErrors::ConstructionCallback construction_callback_;
281 DownloadFileWithErrors::DestructionCallback destruction_callback_;
284 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory(
285 const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
286 const DownloadFileWithErrors::DestructionCallback& dtor_callback)
287 : construction_callback_(ctor_callback),
288 destruction_callback_(dtor_callback) {
291 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() {
294 DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
295 scoped_ptr<DownloadSaveInfo> save_info,
296 const base::FilePath& default_download_directory,
297 const GURL& url,
298 const GURL& referrer_url,
299 bool calculate_hash,
300 scoped_ptr<ByteStreamReader> stream,
301 const net::BoundNetLog& bound_net_log,
302 base::WeakPtr<DownloadDestinationObserver> observer) {
303 if (injected_errors_.find(url.spec()) == injected_errors_.end()) {
304 // Have to create entry, because FileErrorInfo is not a POD type.
305 TestFileErrorInjector::FileErrorInfo err_info = {
306 url.spec(),
307 TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
309 DOWNLOAD_INTERRUPT_REASON_NONE
311 injected_errors_[url.spec()] = err_info;
314 return new DownloadFileWithErrors(
315 save_info.Pass(),
316 default_download_directory,
317 url,
318 referrer_url,
319 calculate_hash,
320 stream.Pass(),
321 bound_net_log,
322 observer,
323 injected_errors_[url.spec()],
324 construction_callback_,
325 destruction_callback_);
328 bool DownloadFileWithErrorsFactory::AddError(
329 const TestFileErrorInjector::FileErrorInfo& error_info) {
330 // Creates an empty entry if necessary. Duplicate entries overwrite.
331 injected_errors_[error_info.url] = error_info;
333 return true;
336 void DownloadFileWithErrorsFactory::ClearErrors() {
337 injected_errors_.clear();
340 TestFileErrorInjector::TestFileErrorInjector(
341 DownloadManager* download_manager)
342 : created_factory_(NULL),
343 // This code is only used for browser_tests, so a
344 // DownloadManager is always a DownloadManagerImpl.
345 download_manager_(static_cast<DownloadManagerImpl*>(download_manager)) {
346 // Record the value of the pointer, for later validation.
347 created_factory_ =
348 new DownloadFileWithErrorsFactory(
349 base::Bind(&TestFileErrorInjector::RecordDownloadFileConstruction,
350 this),
351 base::Bind(&TestFileErrorInjector::RecordDownloadFileDestruction,
352 this));
354 // We will transfer ownership of the factory to the download manager.
355 scoped_ptr<DownloadFileFactory> download_file_factory(
356 created_factory_);
358 download_manager_->SetDownloadFileFactoryForTesting(
359 download_file_factory.Pass());
362 TestFileErrorInjector::~TestFileErrorInjector() {
365 bool TestFileErrorInjector::AddError(const FileErrorInfo& error_info) {
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
367 DCHECK_LE(0, error_info.operation_instance);
368 DCHECK(injected_errors_.find(error_info.url) == injected_errors_.end());
370 // Creates an empty entry if necessary.
371 injected_errors_[error_info.url] = error_info;
373 return true;
376 void TestFileErrorInjector::ClearErrors() {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 injected_errors_.clear();
381 bool TestFileErrorInjector::InjectErrors() {
382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
384 ClearFoundFiles();
386 DCHECK_EQ(static_cast<DownloadFileFactory*>(created_factory_),
387 download_manager_->GetDownloadFileFactoryForTesting());
389 created_factory_->ClearErrors();
391 for (ErrorMap::const_iterator it = injected_errors_.begin();
392 it != injected_errors_.end(); ++it)
393 created_factory_->AddError(it->second);
395 return true;
398 size_t TestFileErrorInjector::CurrentFileCount() const {
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400 return files_.size();
403 size_t TestFileErrorInjector::TotalFileCount() const {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405 return found_files_.size();
409 bool TestFileErrorInjector::HadFile(const GURL& url) const {
410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
412 return (found_files_.find(url) != found_files_.end());
415 void TestFileErrorInjector::ClearFoundFiles() {
416 found_files_.clear();
419 void TestFileErrorInjector::DownloadFileCreated(GURL url) {
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 DCHECK(files_.find(url) == files_.end());
423 files_.insert(url);
424 found_files_.insert(url);
427 void TestFileErrorInjector::DestroyingDownloadFile(GURL url) {
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429 DCHECK(files_.find(url) != files_.end());
431 files_.erase(url);
434 void TestFileErrorInjector::RecordDownloadFileConstruction(const GURL& url) {
435 BrowserThread::PostTask(
436 BrowserThread::UI,
437 FROM_HERE,
438 base::Bind(&TestFileErrorInjector::DownloadFileCreated, this, url));
441 void TestFileErrorInjector::RecordDownloadFileDestruction(const GURL& url) {
442 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
443 base::Bind(&TestFileErrorInjector::DestroyingDownloadFile, this, url));
446 // static
447 scoped_refptr<TestFileErrorInjector> TestFileErrorInjector::Create(
448 DownloadManager* download_manager) {
449 static bool visited = false;
450 DCHECK(!visited); // Only allowed to be called once.
451 visited = true;
453 scoped_refptr<TestFileErrorInjector> single_injector(
454 new TestFileErrorInjector(download_manager));
456 return single_injector;
459 // static
460 std::string TestFileErrorInjector::DebugString(FileOperationCode code) {
461 switch (code) {
462 case FILE_OPERATION_INITIALIZE:
463 return "INITIALIZE";
464 case FILE_OPERATION_WRITE:
465 return "WRITE";
466 case FILE_OPERATION_RENAME_UNIQUIFY:
467 return "RENAME_UNIQUIFY";
468 case FILE_OPERATION_RENAME_ANNOTATE:
469 return "RENAME_ANNOTATE";
470 default:
471 break;
474 return "Unknown";
477 } // namespace content