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

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

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

Powered by Google App Engine
This is Rietveld 408576698