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/browser/download/download_file_impl.h" | |
13 #include "content/browser/download/download_file_manager.h" | |
14 #include "content/browser/renderer_host/resource_dispatcher_host.h" | |
15 | |
16 class DownloadFileWithErrors; | |
17 | |
18 namespace { | |
19 | |
20 // Structure that encapsulates the information needed to inject a file error. | |
21 struct FileErrorInfo { | |
22 FileErrorInfo() | |
23 : file_index(-1), | |
24 code(FILE_OPERATION_INITIALIZE), | |
25 operation_instance(-1), | |
26 net_error(net::OK) { | |
27 } | |
28 | |
29 int file_index; // 0-based. | |
30 FileOperationCode code; | |
31 int operation_instance; // 0-based. | |
32 net::Error net_error; | |
33 }; | |
34 | |
35 // List of errors. | |
36 typedef std::vector<FileErrorInfo> ErrorList; | |
37 | |
38 // Structure that associates a file with a set of errors. | |
39 struct FileErrors { | |
40 FileErrors() : file(NULL) {} | |
41 | |
42 DownloadFileWithErrors* file; | |
43 ErrorList error_list; | |
44 }; | |
45 | |
46 DownloadFileManager* GetDownloadFileManager() { | |
47 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); | |
48 DCHECK(rdh != NULL); | |
49 return rdh->download_file_manager(); | |
50 } | |
51 | |
52 std::string DebugString(FileOperationCode code) { | |
53 | |
54 #define TO_STRING(code) case FILE_OPERATION_##code: return #code | |
55 | |
56 switch (code) { | |
57 TO_STRING(INITIALIZE); | |
58 TO_STRING(WRITE); | |
59 TO_STRING(RENAME); | |
60 default: | |
61 break; | |
62 } | |
63 | |
64 #undef TO_STRING | |
65 | |
66 return "Unknown"; | |
67 } | |
68 | |
69 } // namespace | |
70 | |
71 class TestFileErrorInjectorImpl : public TestFileErrorInjector { | |
72 public: | |
73 TestFileErrorInjectorImpl(); | |
74 | |
75 // TestFileErrorInjector interface. | |
76 virtual bool InjectError(int file_index, | |
77 FileOperationCode operation, | |
78 int operation_instance, | |
79 net::Error net_error) OVERRIDE; | |
80 virtual size_t CurrentFileCount() const OVERRIDE; | |
81 virtual size_t FileCreationCount() const OVERRIDE { return file_counter_; } | |
82 | |
83 // Callbacks from the download file. | |
84 virtual int DownloadFileCreated(DownloadFileWithErrors* download_file); | |
85 virtual void DestroyingDownloadFile(DownloadFileWithErrors* download_file); | |
86 | |
87 private: | |
88 virtual ~TestFileErrorInjectorImpl(); | |
89 | |
90 // The number of files we've created. | |
91 int file_counter_; | |
92 | |
93 // Our injected error list, mapped by file index. | |
94 std::map<int, FileErrors> injected_errors_; | |
95 | |
96 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); | |
97 }; | |
98 | |
99 // A class that performs file operations and injects errors. | |
100 class DownloadFileWithErrors: public DownloadFileImpl { | |
101 public: | |
102 DownloadFileWithErrors(const DownloadCreateInfo* info, | |
103 DownloadRequestHandleInterface* request_handle, | |
104 content::DownloadManager* download_manager, | |
105 bool calculate_hash, | |
106 const net::BoundNetLog& bound_net_log, | |
107 scoped_refptr<TestFileErrorInjectorImpl> injector); | |
108 | |
109 ~DownloadFileWithErrors(); | |
110 | |
111 // DownloadFile interface. | |
112 virtual net::Error Initialize() OVERRIDE; | |
113 virtual net::Error AppendDataToFile(const char* data, | |
114 size_t data_len) OVERRIDE; | |
115 virtual net::Error Rename(const FilePath& full_path) OVERRIDE; | |
116 | |
117 // Error generating helpers. | |
118 net::Error ShouldReturnError(FileOperationCode code, | |
119 net::Error original_net_error); | |
120 | |
121 void AddError(const FileErrorInfo& info); | |
122 void SetErrorList(int index, | |
123 const ErrorList& error_list); | |
124 int index() const { return index_; } | |
125 | |
126 private: | |
127 // Map from instance number to file error information. | |
128 typedef std::map<int, FileErrorInfo> InstanceMap; | |
129 | |
130 // Map of errors by operation code | |
131 typedef std::map<FileOperationCode, | |
132 InstanceMap> ErrorMap; | |
133 | |
134 // The class that manages errors. | |
135 scoped_refptr<TestFileErrorInjectorImpl> injector_; | |
136 | |
137 // Our file index. | |
138 int index_; | |
139 | |
140 // Our injected error list. | |
141 ErrorMap error_map_; | |
142 | |
143 // Count per operation. 0-based. | |
144 std::map<FileOperationCode, int> operation_counter_; | |
145 }; | |
146 | |
147 // A factory for constructing DownloadFiles that inject errors. | |
148 class DownloadFileWithErrorsFactory | |
149 : public DownloadFileManager::DownloadFileFactory { | |
150 public: | |
151 | |
152 explicit DownloadFileWithErrorsFactory( | |
153 scoped_refptr<TestFileErrorInjectorImpl> injector); | |
154 | |
155 virtual ~DownloadFileWithErrorsFactory(); | |
156 | |
157 virtual content::DownloadFile* CreateFile( | |
158 DownloadCreateInfo* info, | |
159 const DownloadRequestHandle& request_handle, | |
160 content::DownloadManager* download_manager, | |
161 bool calculate_hash, | |
162 const net::BoundNetLog& bound_net_log); | |
163 | |
164 private: | |
165 | |
166 scoped_refptr<TestFileErrorInjectorImpl> injector_; | |
167 }; | |
168 | |
169 | |
170 // Implementations. | |
171 | |
172 // static | |
173 TestFileErrorInjector* TestFileErrorInjector::Create() { | |
174 return new TestFileErrorInjectorImpl; | |
175 } | |
176 | |
177 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() : file_counter_(0) { | |
178 DownloadFileWithErrorsFactory* download_file_factory = | |
179 new DownloadFileWithErrorsFactory(this); | |
180 DownloadFileManager* download_file_manager = GetDownloadFileManager(); | |
181 DCHECK(download_file_manager); | |
182 // Transfers ownership. | |
183 download_file_manager->SetFileFactory(download_file_factory); | |
184 } | |
185 | |
186 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { | |
187 } | |
188 | |
189 bool TestFileErrorInjectorImpl::InjectError(int file_index, | |
190 FileOperationCode operation, | |
191 int operation_instance, | |
192 net::Error net_error) { | |
193 DCHECK_LE(0, file_index); | |
194 DCHECK_LE(0, operation_instance); | |
195 | |
196 // Fill in a new entry. | |
197 FileErrorInfo info; | |
198 info.file_index = file_index; | |
199 info.code = operation; | |
200 info.operation_instance = operation_instance; | |
201 info.net_error = net_error; | |
202 | |
203 // Creates an empty entry if necessary. | |
204 FileErrors& file_errors = injected_errors_[file_index]; | |
205 file_errors.error_list.push_back(info); | |
206 | |
207 // If the file already exists, simply add this entry to the error list. | |
cbentzel
2012/02/24 02:25:12
Do you need to handle this case?
ahendrickson
2012/02/24 22:48:39
Removed.
| |
208 if (file_errors.file != NULL) | |
209 file_errors.file->AddError(info); | |
210 | |
211 return true; | |
212 } | |
213 | |
214 size_t TestFileErrorInjectorImpl::CurrentFileCount() const { | |
215 size_t count = 0; | |
216 | |
217 // Count the map entries with a non-NULL file pointer. | |
218 for (std::map<int, FileErrors>::const_iterator it = injected_errors_.begin(); | |
219 it != injected_errors_.end(); | |
220 ++it) { | |
221 if (it->second.file != NULL) | |
222 count++; | |
223 } | |
224 | |
225 return count; | |
226 } | |
227 | |
228 int TestFileErrorInjectorImpl::DownloadFileCreated( | |
229 DownloadFileWithErrors* download_file) { | |
230 DCHECK(download_file != NULL); | |
231 | |
232 // Creates an empty instance if necessary. | |
233 FileErrors& file_errors = injected_errors_[file_counter_]; | |
234 DCHECK(file_errors.file == NULL); | |
235 file_errors.file = download_file; // Set the file. | |
236 | |
237 download_file->SetErrorList(file_counter_, file_errors.error_list); | |
238 | |
239 return file_counter_++; | |
240 } | |
241 | |
242 void TestFileErrorInjectorImpl::DestroyingDownloadFile( | |
243 DownloadFileWithErrors* download_file) { | |
244 DCHECK(download_file != NULL); | |
245 | |
246 // Mark as gone by making the file NULL. | |
247 injected_errors_[download_file->index()].file = NULL; | |
248 } | |
249 | |
250 DownloadFileWithErrors::DownloadFileWithErrors( | |
251 const DownloadCreateInfo* info, | |
252 DownloadRequestHandleInterface* request_handle, | |
253 content::DownloadManager* download_manager, | |
254 bool calculate_hash, | |
255 const net::BoundNetLog& bound_net_log, | |
256 scoped_refptr<TestFileErrorInjectorImpl> injector) | |
257 : DownloadFileImpl(info, | |
258 request_handle, | |
259 download_manager, | |
260 calculate_hash, | |
261 bound_net_log), | |
262 injector_(injector), | |
263 index_(-1) { | |
264 if (injector_) | |
265 injector_->DownloadFileCreated(this); | |
266 } | |
267 | |
268 DownloadFileWithErrors::~DownloadFileWithErrors() { | |
269 if (injector_) | |
270 injector_->DestroyingDownloadFile(this); | |
271 } | |
272 | |
273 | |
274 net::Error DownloadFileWithErrors::Initialize() { | |
275 return ShouldReturnError(FILE_OPERATION_INITIALIZE, | |
276 DownloadFileImpl::Initialize()); | |
277 } | |
278 | |
279 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, | |
280 size_t data_len) { | |
281 return ShouldReturnError(FILE_OPERATION_WRITE, | |
282 DownloadFileImpl::AppendDataToFile(data, data_len)); | |
283 } | |
284 | |
285 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { | |
286 return ShouldReturnError(FILE_OPERATION_RENAME, | |
287 DownloadFileImpl::Rename(full_path)); | |
288 } | |
289 | |
290 net::Error DownloadFileWithErrors::ShouldReturnError( | |
291 FileOperationCode code, | |
292 net::Error original_net_error) { | |
293 int counter = operation_counter_[code]; | |
294 ++operation_counter_[code]; | |
295 | |
296 if (error_map_.find(code) == error_map_.end()) | |
297 return original_net_error; // No errors for this operation. | |
298 | |
299 InstanceMap& instance_map = error_map_[code]; | |
300 | |
301 if (instance_map.find(counter) == instance_map.end()) | |
302 return original_net_error; // No error for this instance of the operation. | |
303 | |
304 DVLOG(20) << " " << __FUNCTION__ << "()" | |
305 << " code = " << ::DebugString(code) << " (" << code << ")" | |
306 << " counter = " << counter | |
307 << " original_error = " << original_net_error | |
308 << " new error = " << instance_map[counter].net_error; | |
309 | |
310 return instance_map[counter].net_error; // Error! | |
311 } | |
312 | |
313 void DownloadFileWithErrors::AddError( | |
314 const FileErrorInfo& info) { | |
315 // Get the instance map for the operation code. | |
316 InstanceMap& instance_map = error_map_[info.code]; | |
317 | |
318 // Duplicate entries are an error. | |
319 DCHECK(instance_map.end() == instance_map.find(info.operation_instance)); | |
320 | |
321 // Set the error information in the map. | |
322 instance_map[info.operation_instance] = info; | |
323 } | |
324 | |
325 void DownloadFileWithErrors::SetErrorList( | |
326 int index, const ErrorList& error_list) { | |
327 DCHECK_EQ(-1, index_); | |
328 DCHECK_LE(0, index); | |
329 index_ = index; | |
330 | |
331 // Parcel out the error list by operation code and instance. | |
332 for (size_t i = 0; i < error_list.size(); ++i) | |
333 AddError(error_list[i]); | |
334 } | |
335 | |
336 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( | |
337 scoped_refptr<TestFileErrorInjectorImpl> injector) : injector_(injector) { | |
338 } | |
339 | |
340 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { | |
341 } | |
342 | |
343 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( | |
344 DownloadCreateInfo* info, | |
345 const DownloadRequestHandle& request_handle, | |
346 content::DownloadManager* download_manager, | |
347 bool calculate_hash, | |
348 const net::BoundNetLog& bound_net_log) { | |
349 return new DownloadFileWithErrors(info, | |
350 new DownloadRequestHandle(request_handle), | |
351 download_manager, | |
352 calculate_hash, | |
353 bound_net_log, | |
354 injector_); | |
355 } | |
OLD | NEW |