Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: content/test/test_file_error_injector.cc

Issue 10826311: Move the corresponding cc files from content\test to be alongside their headers in content\public\t… (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/test/test_content_client_initializer.cc ('k') | content/test/test_launcher.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "content/public/test/test_file_error_injector.h"
6
7 #include <vector>
8
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "content/browser/download/download_create_info.h"
12 #include "content/browser/download/download_file_impl.h"
13 #include "content/browser/download/download_file_manager.h"
14 #include "content/browser/download/download_interrupt_reasons_impl.h"
15 #include "content/browser/power_save_blocker.h"
16 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/download_id.h"
19 #include "googleurl/src/gurl.h"
20
21 namespace content {
22 class ByteStreamReader;
23 }
24
25 namespace {
26
27 DownloadFileManager* GetDownloadFileManager() {
28 content::ResourceDispatcherHostImpl* rdh =
29 content::ResourceDispatcherHostImpl::Get();
30 DCHECK(rdh != NULL);
31 return rdh->download_file_manager();
32 }
33
34 // A class that performs file operations and injects errors.
35 class DownloadFileWithErrors: public DownloadFileImpl {
36 public:
37 typedef base::Callback<void(const GURL& url, content::DownloadId id)>
38 ConstructionCallback;
39 typedef base::Callback<void(const GURL& url)> DestructionCallback;
40
41 DownloadFileWithErrors(
42 const DownloadCreateInfo* info,
43 scoped_ptr<content::ByteStreamReader> stream,
44 DownloadRequestHandleInterface* request_handle,
45 content::DownloadManager* download_manager,
46 bool calculate_hash,
47 const net::BoundNetLog& bound_net_log,
48 const content::TestFileErrorInjector::FileErrorInfo& error_info,
49 const ConstructionCallback& ctor_callback,
50 const DestructionCallback& dtor_callback);
51
52 ~DownloadFileWithErrors();
53
54 // DownloadFile interface.
55 virtual content::DownloadInterruptReason Initialize() OVERRIDE;
56 virtual content::DownloadInterruptReason AppendDataToFile(
57 const char* data, size_t data_len) OVERRIDE;
58 virtual void Rename(const FilePath& full_path,
59 bool overwrite_existing_file,
60 const RenameCompletionCallback& callback) OVERRIDE;
61
62 private:
63 // Error generating helper.
64 content::DownloadInterruptReason ShouldReturnError(
65 content::TestFileErrorInjector::FileOperationCode code,
66 content::DownloadInterruptReason original_error);
67
68 // Used in place of original rename callback to intercept with
69 // ShouldReturnError.
70 void RenameErrorCallback(
71 const RenameCompletionCallback& original_callback,
72 content::DownloadInterruptReason original_error,
73 const FilePath& path_result);
74
75 // Source URL for the file being downloaded.
76 GURL source_url_;
77
78 // Our injected error. Only one per file.
79 content::TestFileErrorInjector::FileErrorInfo error_info_;
80
81 // Count per operation. 0-based.
82 std::map<content::TestFileErrorInjector::FileOperationCode, int>
83 operation_counter_;
84
85 // Callback for destruction.
86 DestructionCallback destruction_callback_;
87 };
88
89 DownloadFileWithErrors::DownloadFileWithErrors(
90 const DownloadCreateInfo* info,
91 scoped_ptr<content::ByteStreamReader> stream,
92 DownloadRequestHandleInterface* request_handle,
93 content::DownloadManager* download_manager,
94 bool calculate_hash,
95 const net::BoundNetLog& bound_net_log,
96 const content::TestFileErrorInjector::FileErrorInfo& error_info,
97 const ConstructionCallback& ctor_callback,
98 const DestructionCallback& dtor_callback)
99 : DownloadFileImpl(info,
100 stream.Pass(),
101 request_handle,
102 download_manager,
103 calculate_hash,
104 scoped_ptr<content::PowerSaveBlocker>(NULL).Pass(),
105 bound_net_log),
106 source_url_(info->url()),
107 error_info_(error_info),
108 destruction_callback_(dtor_callback) {
109 ctor_callback.Run(source_url_, info->download_id);
110 }
111
112 DownloadFileWithErrors::~DownloadFileWithErrors() {
113 destruction_callback_.Run(source_url_);
114 }
115
116 content::DownloadInterruptReason DownloadFileWithErrors::Initialize() {
117 return ShouldReturnError(
118 content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
119 DownloadFileImpl::Initialize());
120 }
121
122 content::DownloadInterruptReason DownloadFileWithErrors::AppendDataToFile(
123 const char* data, size_t data_len) {
124 return ShouldReturnError(
125 content::TestFileErrorInjector::FILE_OPERATION_WRITE,
126 DownloadFileImpl::AppendDataToFile(data, data_len));
127 }
128
129 void DownloadFileWithErrors::Rename(
130 const FilePath& full_path,
131 bool overwrite_existing_file,
132 const RenameCompletionCallback& callback) {
133 DownloadFileImpl::Rename(
134 full_path, overwrite_existing_file,
135 base::Bind(&DownloadFileWithErrors::RenameErrorCallback,
136 // Unretained since this'll only be called from
137 // the DownloadFileImpl slice of the same object.
138 base::Unretained(this), callback));
139 }
140
141 content::DownloadInterruptReason DownloadFileWithErrors::ShouldReturnError(
142 content::TestFileErrorInjector::FileOperationCode code,
143 content::DownloadInterruptReason original_error) {
144 int counter = operation_counter_[code];
145 ++operation_counter_[code];
146
147 if (code != error_info_.code)
148 return original_error;
149
150 if (counter != error_info_.operation_instance)
151 return original_error;
152
153 VLOG(1) << " " << __FUNCTION__ << "()"
154 << " url = '" << source_url_.spec() << "'"
155 << " code = " << content::TestFileErrorInjector::DebugString(code)
156 << " (" << code << ")"
157 << " counter = " << counter
158 << " original_error = "
159 << content::InterruptReasonDebugString(original_error)
160 << " (" << original_error << ")"
161 << " new error = "
162 << content::InterruptReasonDebugString(error_info_.error)
163 << " (" << error_info_.error << ")";
164
165 return error_info_.error;
166 }
167
168 void DownloadFileWithErrors::RenameErrorCallback(
169 const RenameCompletionCallback& original_callback,
170 content::DownloadInterruptReason original_error,
171 const FilePath& path_result) {
172 original_callback.Run(ShouldReturnError(
173 content::TestFileErrorInjector::FILE_OPERATION_RENAME,
174 original_error), path_result);
175 }
176
177 } // namespace
178
179 namespace content {
180
181 // A factory for constructing DownloadFiles that inject errors.
182 class DownloadFileWithErrorsFactory
183 : public DownloadFileManager::DownloadFileFactory {
184 public:
185
186 DownloadFileWithErrorsFactory(
187 const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
188 const DownloadFileWithErrors::DestructionCallback& dtor_callback);
189 virtual ~DownloadFileWithErrorsFactory();
190
191 // DownloadFileFactory interface.
192 virtual DownloadFile* CreateFile(
193 DownloadCreateInfo* info,
194 scoped_ptr<content::ByteStreamReader> stream,
195 content::DownloadManager* download_manager,
196 bool calculate_hash,
197 const net::BoundNetLog& bound_net_log);
198
199 bool AddError(
200 const TestFileErrorInjector::FileErrorInfo& error_info);
201
202 void ClearErrors();
203
204 private:
205 // Our injected error list, mapped by URL. One per file.
206 TestFileErrorInjector::ErrorMap injected_errors_;
207
208 // Callback for creation and destruction.
209 DownloadFileWithErrors::ConstructionCallback construction_callback_;
210 DownloadFileWithErrors::DestructionCallback destruction_callback_;
211 };
212
213 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory(
214 const DownloadFileWithErrors::ConstructionCallback& ctor_callback,
215 const DownloadFileWithErrors::DestructionCallback& dtor_callback)
216 : construction_callback_(ctor_callback),
217 destruction_callback_(dtor_callback) {
218 }
219
220 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() {
221 }
222
223 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
224 DownloadCreateInfo* info,
225 scoped_ptr<content::ByteStreamReader> stream,
226 content::DownloadManager* download_manager,
227 bool calculate_hash,
228 const net::BoundNetLog& bound_net_log) {
229 std::string url = info->url().spec();
230
231 if (injected_errors_.find(url) == injected_errors_.end()) {
232 // Have to create entry, because FileErrorInfo is not a POD type.
233 TestFileErrorInjector::FileErrorInfo err_info = {
234 url,
235 TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
236 -1,
237 content::DOWNLOAD_INTERRUPT_REASON_NONE
238 };
239 injected_errors_[url] = err_info;
240 }
241
242 return new DownloadFileWithErrors(
243 info,
244 stream.Pass(),
245 new DownloadRequestHandle(info->request_handle),
246 download_manager,
247 calculate_hash,
248 bound_net_log,
249 injected_errors_[url],
250 construction_callback_,
251 destruction_callback_);
252 }
253
254 bool DownloadFileWithErrorsFactory::AddError(
255 const TestFileErrorInjector::FileErrorInfo& error_info) {
256 // Creates an empty entry if necessary. Duplicate entries overwrite.
257 injected_errors_[error_info.url] = error_info;
258
259 return true;
260 }
261
262 void DownloadFileWithErrorsFactory::ClearErrors() {
263 injected_errors_.clear();
264 }
265
266 TestFileErrorInjector::TestFileErrorInjector()
267 : created_factory_(NULL) {
268 // Record the value of the pointer, for later validation.
269 created_factory_ =
270 new DownloadFileWithErrorsFactory(
271 base::Bind(&TestFileErrorInjector::
272 RecordDownloadFileConstruction,
273 this),
274 base::Bind(&TestFileErrorInjector::
275 RecordDownloadFileDestruction,
276 this));
277
278 // We will transfer ownership of the factory to the download file manager.
279 scoped_ptr<DownloadFileWithErrorsFactory> download_file_factory(
280 created_factory_);
281
282 content::BrowserThread::PostTask(
283 content::BrowserThread::FILE,
284 FROM_HERE,
285 base::Bind(&TestFileErrorInjector::AddFactory,
286 this,
287 base::Passed(&download_file_factory)));
288 }
289
290 TestFileErrorInjector::~TestFileErrorInjector() {
291 }
292
293 void TestFileErrorInjector::AddFactory(
294 scoped_ptr<DownloadFileWithErrorsFactory> factory) {
295 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
296
297 DownloadFileManager* download_file_manager = GetDownloadFileManager();
298 DCHECK(download_file_manager);
299
300 // Convert to base class pointer, for GCC.
301 scoped_ptr<DownloadFileManager::DownloadFileFactory> plain_factory(
302 factory.release());
303
304 download_file_manager->SetFileFactoryForTesting(plain_factory.Pass());
305 }
306
307 bool TestFileErrorInjector::AddError(const FileErrorInfo& error_info) {
308 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
309 DCHECK_LE(0, error_info.operation_instance);
310 DCHECK(injected_errors_.find(error_info.url) == injected_errors_.end());
311
312 // Creates an empty entry if necessary.
313 injected_errors_[error_info.url] = error_info;
314
315 return true;
316 }
317
318 void TestFileErrorInjector::ClearErrors() {
319 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
320 injected_errors_.clear();
321 }
322
323 bool TestFileErrorInjector::InjectErrors() {
324 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
325
326 ClearFoundFiles();
327
328 content::BrowserThread::PostTask(
329 content::BrowserThread::FILE,
330 FROM_HERE,
331 base::Bind(&TestFileErrorInjector::InjectErrorsOnFileThread,
332 this,
333 injected_errors_,
334 created_factory_));
335
336 return true;
337 }
338
339 void TestFileErrorInjector::InjectErrorsOnFileThread(
340 ErrorMap map, DownloadFileWithErrorsFactory* factory) {
341 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
342
343 // Validate that our factory is in use.
344 DownloadFileManager* download_file_manager = GetDownloadFileManager();
345 DCHECK(download_file_manager);
346
347 DownloadFileManager::DownloadFileFactory* file_factory =
348 download_file_manager->GetFileFactoryForTesting();
349
350 // Validate that we still have the same factory.
351 DCHECK_EQ(static_cast<DownloadFileManager::DownloadFileFactory*>(factory),
352 file_factory);
353
354 // We want to replace all existing injection errors.
355 factory->ClearErrors();
356
357 for (ErrorMap::const_iterator it = map.begin(); it != map.end(); ++it)
358 factory->AddError(it->second);
359 }
360
361 size_t TestFileErrorInjector::CurrentFileCount() const {
362 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
363 return files_.size();
364 }
365
366 size_t TestFileErrorInjector::TotalFileCount() const {
367 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
368 return found_files_.size();
369 }
370
371
372 bool TestFileErrorInjector::HadFile(const GURL& url) const {
373 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
374
375 return (found_files_.find(url) != found_files_.end());
376 }
377
378 const content::DownloadId TestFileErrorInjector::GetId(
379 const GURL& url) const {
380 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
381
382 FileMap::const_iterator it = found_files_.find(url);
383 if (it == found_files_.end())
384 return content::DownloadId::Invalid();
385
386 return it->second;
387 }
388
389 void TestFileErrorInjector::ClearFoundFiles() {
390 found_files_.clear();
391 }
392
393 void TestFileErrorInjector::DownloadFileCreated(GURL url,
394 content::DownloadId id) {
395 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
396 DCHECK(files_.find(url) == files_.end());
397
398 files_[url] = id;
399 found_files_[url] = id;
400 }
401
402 void TestFileErrorInjector::DestroyingDownloadFile(GURL url) {
403 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
404 DCHECK(files_.find(url) != files_.end());
405
406 files_.erase(url);
407 }
408
409 void TestFileErrorInjector::RecordDownloadFileConstruction(
410 const GURL& url, content::DownloadId id) {
411 content::BrowserThread::PostTask(
412 content::BrowserThread::UI,
413 FROM_HERE,
414 base::Bind(&TestFileErrorInjector::DownloadFileCreated,
415 this,
416 url,
417 id));
418 }
419
420 void TestFileErrorInjector::RecordDownloadFileDestruction(const GURL& url) {
421 content::BrowserThread::PostTask(
422 content::BrowserThread::UI,
423 FROM_HERE,
424 base::Bind(&TestFileErrorInjector::DestroyingDownloadFile,
425 this,
426 url));
427 }
428
429 // static
430 scoped_refptr<TestFileErrorInjector> TestFileErrorInjector::Create() {
431 static bool visited = false;
432 DCHECK(!visited); // Only allowed to be called once.
433 visited = true;
434
435 scoped_refptr<TestFileErrorInjector> single_injector(
436 new TestFileErrorInjector);
437
438 return single_injector;
439 }
440
441 // static
442 std::string TestFileErrorInjector::DebugString(FileOperationCode code) {
443 switch (code) {
444 case FILE_OPERATION_INITIALIZE:
445 return "INITIALIZE";
446 case FILE_OPERATION_WRITE:
447 return "WRITE";
448 case FILE_OPERATION_RENAME:
449 return "RENAME";
450 default:
451 break;
452 }
453
454 return "Unknown";
455 }
456
457 } // namespace content
OLDNEW
« no previous file with comments | « content/test/test_content_client_initializer.cc ('k') | content/test/test_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698