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

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