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

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