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

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: Refactored per Chris' comments 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_file_impl.h"
14 #include "content/browser/download/download_file_manager.h"
15 #include "content/browser/renderer_host/resource_dispatcher_host.h"
16
17 namespace {
18
19 class DownloadFileWithErrors;
20 class DownloadFileWithErrorsFactory;
21
22 typedef std::map<int, content::TestFileErrorInjector::FileErrorInfo> ErrorMap;
23
24 DownloadFileManager* GetDownloadFileManager() {
25 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get();
26 DCHECK(rdh != NULL);
27 return rdh->download_file_manager();
28 }
29
30 class TestFileErrorInjectorImpl : public content::TestFileErrorInjector {
31 public:
32 typedef base::Callback<void(int index, bool creating)> DownloadFileCallback;
cbentzel 2012/02/28 14:51:41 Design nit: You typically want this on the Downloa
ahendrickson 2012/03/01 09:17:32 I wanted this class to be the first one declared.
33
34 TestFileErrorInjectorImpl();
35
36 // content::TestFileErrorInjector interface.
37 virtual bool AddError(const FileErrorInfo& error_info) OVERRIDE;
38 virtual bool InjectErrors() OVERRIDE;
39 virtual size_t CurrentFileCount() const OVERRIDE;
40 virtual size_t FileCreationCount() const OVERRIDE;
41 virtual bool HasFile(int file_index) const OVERRIDE;
42
43 // Callbacks from the download file, to record lifetimes.
Randy Smith (Not in Mondays) 2012/02/28 22:06:13 nit: Aren't these callbacks from the factory, not
ahendrickson 2012/03/01 09:17:32 No, the factory passes the callback objects to the
Randy Smith (Not in Mondays) 2012/03/01 20:28:24 Right, got it--sorry for the confusion.
44 virtual void DownloadFileCreated(int file_index);
cbentzel 2012/02/28 14:51:41 These don't need to be virtual. Could also be priv
ahendrickson 2012/03/01 09:17:32 Done.
45 virtual void DestroyingDownloadFile(int file_index);
46
47 private:
48 virtual ~TestFileErrorInjectorImpl();
49
50 void RecordDownloadFileConstructionDestruction(int index, bool creating);
51
52 typedef std::set<int> FileSet;
53
54 // Our injected error list, mapped by file index. One per file.
Randy Smith (Not in Mondays) 2012/02/28 22:06:13 This is the first time I noticed that we could onl
ahendrickson 2012/03/01 09:17:32 I added a comment to AddError().
55 ErrorMap injected_errors_;
56
57 // Keep track of active DownloadFiles.
58 FileSet files_;
59
60 // We have created a factory. Used for validation.
61 bool created_factory_;
62
63 // The number of files we've recorded.
64 int file_counter_;
65
66 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl);
67 };
68
69 // A class that performs file operations and injects errors.
70 class DownloadFileWithErrors: public DownloadFileImpl {
71 public:
72 DownloadFileWithErrors(
73 const DownloadCreateInfo* info,
74 DownloadRequestHandleInterface* request_handle,
75 content::DownloadManager* download_manager,
76 bool calculate_hash,
77 const net::BoundNetLog& bound_net_log,
78 const content::TestFileErrorInjector::FileErrorInfo& error_info,
79 const TestFileErrorInjectorImpl::DownloadFileCallback& callback);
80
81 ~DownloadFileWithErrors();
82
83 // DownloadFile interface.
84 virtual net::Error Initialize() OVERRIDE;
85 virtual net::Error AppendDataToFile(const char* data,
86 size_t data_len) OVERRIDE;
87 virtual net::Error Rename(const FilePath& full_path) OVERRIDE;
88
89 private:
90 // Error generating helper.
91 net::Error ShouldReturnError(
92 content::TestFileErrorInjector::FileOperationCode code,
93 net::Error original_net_error);
94
95 // Our injected error. Only one per file.
96 content::TestFileErrorInjector::FileErrorInfo error_info_;
97
98 // Count per operation. 0-based.
99 std::map<content::TestFileErrorInjector::FileOperationCode, int>
100 operation_counter_;
101
102 // Callback for creation and destruction.
103 TestFileErrorInjectorImpl::DownloadFileCallback callback_;
104 };
105
106 // A factory for constructing DownloadFiles that inject errors.
107 class DownloadFileWithErrorsFactory
108 : public DownloadFileManager::DownloadFileFactory {
109 public:
110
111 DownloadFileWithErrorsFactory(
112 const TestFileErrorInjectorImpl::DownloadFileCallback& callback);
113 virtual ~DownloadFileWithErrorsFactory();
114
115 // DownloadFileFactory interface.
116 virtual content::DownloadFile* CreateFile(
117 DownloadCreateInfo* info,
118 const DownloadRequestHandle& request_handle,
119 content::DownloadManager* download_manager,
120 bool calculate_hash,
121 const net::BoundNetLog& bound_net_log);
122
123 bool AddError(
124 const content::TestFileErrorInjector::FileErrorInfo& error_info);
125
126 size_t files_created() const { return file_counter_; }
127
128 private:
129 // Number of files we've created.
130 size_t file_counter_;
131
132 // Our injected error list, mapped by file index. One per file.
133 ErrorMap injected_errors_;
134
135 // Callback for creation and destruction.
136 TestFileErrorInjectorImpl::DownloadFileCallback callback_;
137 };
138
139 // Implementations.
140
141 DownloadFileWithErrors::DownloadFileWithErrors(
142 const DownloadCreateInfo* info,
143 DownloadRequestHandleInterface* request_handle,
144 content::DownloadManager* download_manager,
145 bool calculate_hash,
146 const net::BoundNetLog& bound_net_log,
147 const content::TestFileErrorInjector::FileErrorInfo& error_info,
148 const TestFileErrorInjectorImpl::DownloadFileCallback& callback)
149 : DownloadFileImpl(info,
150 request_handle,
151 download_manager,
152 calculate_hash,
153 bound_net_log),
154 error_info_(error_info),
155 callback_(callback) {
156 // Record creation.
157 callback_.Run(error_info_.file_index, true);
158 }
159
160 DownloadFileWithErrors::~DownloadFileWithErrors() {
161 // Record destruction.
162 callback_.Run(error_info_.file_index, false);
163 }
164
165
166 net::Error DownloadFileWithErrors::Initialize() {
167 return ShouldReturnError(
168 content::TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
169 DownloadFileImpl::Initialize());
170 }
171
172 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data,
173 size_t data_len) {
174 return ShouldReturnError(
175 content::TestFileErrorInjector::FILE_OPERATION_WRITE,
176 DownloadFileImpl::AppendDataToFile(data, data_len));
177 }
178
179 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) {
180 return ShouldReturnError(
181 content::TestFileErrorInjector::FILE_OPERATION_RENAME,
182 DownloadFileImpl::Rename(full_path));
183 }
184
185 net::Error DownloadFileWithErrors::ShouldReturnError(
186 content::TestFileErrorInjector::FileOperationCode code,
187 net::Error original_net_error) {
188 int counter = operation_counter_[code];
cbentzel 2012/02/28 14:51:41 I'd get rid of the operation_counter_ map here - n
ahendrickson 2012/03/02 21:58:47 We're now using operation instances other than 0.
189 ++operation_counter_[code];
190
191 if (code != error_info_.code)
192 return original_net_error;
193
194 if (counter != error_info_.operation_instance)
195 return original_net_error;
196
197 VLOG(1) << " " << __FUNCTION__ << "()"
198 << " code = " << content::TestFileErrorInjector::DebugString(code)
199 << " (" << code << ")"
200 << " counter = " << counter
201 << " original_error = " << original_net_error
202 << " new error = " << error_info_.net_error;
203
204 return error_info_.net_error;
205 }
206
207 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory(
208 const TestFileErrorInjectorImpl::DownloadFileCallback& callback)
209 : file_counter_(0), callback_(callback) {
210 }
211
212 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() {
213 }
214
215 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile(
216 DownloadCreateInfo* info,
217 const DownloadRequestHandle& request_handle,
218 content::DownloadManager* download_manager,
219 bool calculate_hash,
220 const net::BoundNetLog& bound_net_log) {
221 // Creates entry if it doesn't exist.
222 injected_errors_[file_counter_].file_index = file_counter_; // Set index.
223 return new DownloadFileWithErrors(info,
224 new DownloadRequestHandle(request_handle),
225 download_manager,
226 calculate_hash,
227 bound_net_log,
228 injected_errors_[file_counter_++],
Randy Smith (Not in Mondays) 2012/02/28 22:06:13 What happens if this accesses an uninitialized ent
ahendrickson 2012/03/01 09:17:32 No error is injected.
Randy Smith (Not in Mondays) 2012/03/01 20:28:24 I think Chris did the analysis that I was worried
ahendrickson 2012/03/02 21:58:47 Fixed.
229 callback_);
230 }
231
232 bool DownloadFileWithErrorsFactory::AddError(
233 const content::TestFileErrorInjector::FileErrorInfo& error_info) {
234 DCHECK_LE(0, error_info.file_index);
235 DCHECK_LE(0, error_info.operation_instance);
236
237 // Creates an empty entry if necessary.
238 injected_errors_[error_info.file_index] = error_info;
Randy Smith (Not in Mondays) 2012/02/28 22:06:13 Should this interface allow us to overwrite alread
ahendrickson 2012/03/01 09:17:32 No, although it just replaces the existing value.
239
240 return true;
241 }
242
243 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl()
244 : created_factory_(false), file_counter_(0) {
245 }
246
247 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() {
248 }
249
250 bool TestFileErrorInjectorImpl::AddError(const FileErrorInfo& error_info) {
251 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
252 DCHECK(!created_factory_);
253 DCHECK_LE(0, error_info.file_index);
254 DCHECK_LE(0, error_info.operation_instance);
255
256 // Creates an empty entry if necessary.
257 injected_errors_[error_info.file_index] = error_info;
cbentzel 2012/02/28 14:51:41 Why are you worried about adding support for a map
ahendrickson 2012/03/01 09:17:32 The new tests run multiple downloads, so we need t
258
259 return true;
260 }
261
262 bool TestFileErrorInjectorImpl::InjectErrors() {
263 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
264 DCHECK(!created_factory_);
265
266 DownloadFileWithErrorsFactory* download_file_factory =
267 new DownloadFileWithErrorsFactory(
268 base::Bind(
269 &TestFileErrorInjectorImpl::
270 RecordDownloadFileConstructionDestruction,
271 this));
272
273 for (ErrorMap::const_iterator it = injected_errors_.begin();
274 it != injected_errors_.end();
275 ++it) {
276 download_file_factory->AddError(it->second);
Randy Smith (Not in Mondays) 2012/02/28 22:06:13 nit, suggestion: You could create download_file_fa
ahendrickson 2012/03/01 09:17:32 I did that in an earlier pass, but Chris asked me
Randy Smith (Not in Mondays) 2012/03/01 20:28:24 Given that I think Chris just suggested the same i
277 }
278
279 DownloadFileManager* download_file_manager = GetDownloadFileManager();
280 DCHECK(download_file_manager);
281 // Transfers ownership to |DownloadFileManager|.
cbentzel 2012/02/28 14:51:41 Use scoped_ptr.Pass here instead.
ahendrickson 2012/03/01 09:17:32 Done.
282 download_file_manager->SetFileFactoryForTesting(download_file_factory);
283
284 created_factory_ = true;
285
286 return true;
287 }
288
289 size_t TestFileErrorInjectorImpl::CurrentFileCount() const {
290 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
291 return files_.size();
292 }
293
294 size_t TestFileErrorInjectorImpl::FileCreationCount() const {
295 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
296 return file_counter_;
297 }
298
299
300 bool TestFileErrorInjectorImpl::HasFile(int file_index) const {
301 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
302 return (files_.find(file_index) != files_.end());
303 }
304
305 void TestFileErrorInjectorImpl::DownloadFileCreated(int file_index) {
306 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
307 DCHECK_EQ(file_index, file_counter_);
308
309 file_counter_++;
310 files_.insert(file_index);
311 }
312
313 void TestFileErrorInjectorImpl::DestroyingDownloadFile(int file_index) {
314 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
315
316 files_.erase(file_index);
317 }
318
319 void TestFileErrorInjectorImpl::RecordDownloadFileConstructionDestruction(
320 int index, bool constructing) {
321 content::BrowserThread::PostTask(
322 content::BrowserThread::UI,
323 FROM_HERE,
324 base::Bind(constructing ?
325 &TestFileErrorInjectorImpl::DownloadFileCreated :
326 &TestFileErrorInjectorImpl::DestroyingDownloadFile,
327 this,
328 index));
329 }
330
331 } // namespace
332
333 namespace content {
334
335 // static
336 scoped_refptr<TestFileErrorInjector> TestFileErrorInjector::Create() {
337 return new TestFileErrorInjectorImpl;
338 }
339
340 std::string TestFileErrorInjector::DebugString(FileOperationCode code) {
341
342 #define TO_STRING(code) \
cbentzel 2012/02/28 14:51:41 Although this macro is localized, it provides very
ahendrickson 2012/03/01 09:17:32 Removed the namespace reference. It is now used i
Randy Smith (Not in Mondays) 2012/03/06 23:05:19 FWIW, I agree with Chris; I think writing it direc
343 case content::TestFileErrorInjector::FILE_OPERATION_##code: return #code
344
345 switch (code) {
346 TO_STRING(INITIALIZE);
347 TO_STRING(WRITE);
348 TO_STRING(RENAME);
349 default:
350 break;
351 }
352
353 #undef TO_STRING
354
355 return "Unknown";
356 }
357
358 } // 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