OLD | NEW |
---|---|
(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 | |
OLD | NEW |