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 TestFileErrorInjectorImpl; | |
17 | |
18 namespace { | |
19 | |
20 // Structure that encapsulates the information needed to inject a file error. | |
21 struct FileErrorInfo { | |
cbentzel
2012/02/27 02:18:54
This is kind of duplicated in the browsertest. Per
ahendrickson
2012/02/28 03:28:56
Done.
| |
22 FileErrorInfo() | |
23 : file_index(-1), | |
24 code(content::FILE_OPERATION_INITIALIZE), | |
25 operation_instance(-1), | |
26 net_error(net::OK) { | |
27 } | |
28 | |
29 int file_index; // 0-based index into created DownloadFile instances. | |
30 content::FileOperationCode code; // Operation to affect. | |
31 int operation_instance; // 0-based count of operation calls. | |
32 net::Error net_error; // Error to inject. | |
33 }; | |
34 | |
35 DownloadFileManager* GetDownloadFileManager() { | |
36 ResourceDispatcherHost* rdh = ResourceDispatcherHost::Get(); | |
37 DCHECK(rdh != NULL); | |
cbentzel
2012/02/27 02:18:54
What cases could it be NULL?
ahendrickson
2012/02/28 03:28:56
There are tests (perhaps just unit tests) where RD
| |
38 return rdh->download_file_manager(); | |
39 } | |
40 | |
41 std::string DebugString(content::FileOperationCode code) { | |
cbentzel
2012/02/27 02:18:54
Is this needed?
ahendrickson
2012/02/28 03:28:56
It's used below. I think it's useful to trace err
| |
42 | |
43 #define TO_STRING(code) case content::FILE_OPERATION_##code: return #code | |
44 | |
45 switch (code) { | |
46 TO_STRING(INITIALIZE); | |
47 TO_STRING(WRITE); | |
48 TO_STRING(RENAME); | |
49 default: | |
50 break; | |
51 } | |
52 | |
53 #undef TO_STRING | |
54 | |
55 return "Unknown"; | |
56 } | |
57 | |
58 } // namespace | |
59 | |
60 namespace content { | |
61 | |
62 // A class that performs file operations and injects errors. | |
63 class DownloadFileWithErrors: public DownloadFileImpl { | |
cbentzel
2012/02/27 02:18:54
Could this be in an anonymous nested namespace in
ahendrickson
2012/02/28 03:28:56
Done.
| |
64 public: | |
65 DownloadFileWithErrors(const DownloadCreateInfo* info, | |
66 DownloadRequestHandleInterface* request_handle, | |
67 content::DownloadManager* download_manager, | |
68 bool calculate_hash, | |
69 const net::BoundNetLog& bound_net_log, | |
70 const FileErrorInfo error_info, | |
71 TestFileErrorInjectorImpl* injector); | |
72 | |
73 ~DownloadFileWithErrors(); | |
74 | |
75 // DownloadFile interface. | |
76 virtual net::Error Initialize() OVERRIDE; | |
77 virtual net::Error AppendDataToFile(const char* data, | |
78 size_t data_len) OVERRIDE; | |
79 virtual net::Error Rename(const FilePath& full_path) OVERRIDE; | |
80 | |
81 // For |TestFileErrorInjectorImpl| to record lifetime. | |
82 int index() const { return error_info_.file_index; } | |
83 | |
84 private: | |
85 // Error generating helper. | |
86 net::Error ShouldReturnError(FileOperationCode code, | |
87 net::Error original_net_error); | |
88 | |
89 // The class that injects errors. | |
90 TestFileErrorInjectorImpl* injector_; // Needed for destructor. | |
91 | |
92 // Our injected error. Only one per file. | |
93 FileErrorInfo error_info_; | |
94 | |
95 // Count per operation. 0-based. | |
96 std::map<FileOperationCode, int> operation_counter_; | |
97 }; | |
98 | |
99 // A factory for constructing DownloadFiles that inject errors. | |
100 class DownloadFileWithErrorsFactory | |
101 : public DownloadFileManager::DownloadFileFactory { | |
102 public: | |
103 | |
104 explicit DownloadFileWithErrorsFactory(TestFileErrorInjectorImpl* injector); | |
105 virtual ~DownloadFileWithErrorsFactory(); | |
106 | |
107 // DownloadFileFactory interface. | |
108 virtual content::DownloadFile* CreateFile( | |
109 DownloadCreateInfo* info, | |
110 const DownloadRequestHandle& request_handle, | |
111 content::DownloadManager* download_manager, | |
112 bool calculate_hash, | |
113 const net::BoundNetLog& bound_net_log); | |
114 | |
115 bool InjectError(int file_index, | |
116 content::FileOperationCode operation, | |
117 int operation_instance, | |
118 net::Error net_error); | |
119 | |
120 size_t files_created() const { return file_counter_; } | |
121 | |
122 private: | |
123 // The number of files we've created. | |
124 int file_counter_; | |
125 | |
126 // We pass this to DownloadFileWithErrors, for lifetime tracking. | |
127 // We own this. | |
128 TestFileErrorInjectorImpl* injector_; | |
cbentzel
2012/02/26 15:01:48
scoped_ptr is much clearer declaration of ownershi
ahendrickson
2012/02/28 03:28:56
Now using RefCountedThreadSafe.
| |
129 | |
130 // Our injected error list, mapped by file index. One per file. | |
131 std::map<int, FileErrorInfo> injected_errors_; | |
132 }; | |
133 | |
134 } // namespace content | |
135 | |
136 class TestFileErrorInjectorImpl : public content::TestFileErrorInjector { | |
137 public: | |
138 TestFileErrorInjectorImpl(); | |
139 virtual ~TestFileErrorInjectorImpl(); | |
140 | |
141 // content::TestFileErrorInjector interface. | |
142 virtual bool InjectError(int file_index, | |
143 content::FileOperationCode operation, | |
144 int operation_instance, | |
145 net::Error net_error) OVERRIDE; | |
146 virtual size_t CurrentFileCount() const OVERRIDE; | |
147 virtual size_t FileCreationCount() const OVERRIDE; | |
148 virtual bool HasFile(int file_index) const OVERRIDE; | |
149 | |
150 // Callbacks from the download file, to record lifetimes. | |
151 virtual void DownloadFileCreated( | |
152 content::DownloadFileWithErrors* download_file); | |
153 virtual void DestroyingDownloadFile( | |
154 content::DownloadFileWithErrors* download_file); | |
155 | |
156 private: | |
157 typedef std::map<int, content::DownloadFileWithErrors*> FileMap; | |
158 | |
159 // Keep track of active DownloadFiles. | |
160 FileMap files_; | |
161 | |
162 content::DownloadFileWithErrorsFactory* download_file_factory_; | |
163 | |
164 DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjectorImpl); | |
165 }; | |
166 | |
167 | |
168 // Implementations. | |
169 namespace content { | |
170 | |
171 DownloadFileWithErrors::DownloadFileWithErrors( | |
172 const DownloadCreateInfo* info, | |
173 DownloadRequestHandleInterface* request_handle, | |
174 content::DownloadManager* download_manager, | |
175 bool calculate_hash, | |
176 const net::BoundNetLog& bound_net_log, | |
177 const FileErrorInfo error_info, | |
178 TestFileErrorInjectorImpl* injector) | |
179 : DownloadFileImpl(info, | |
180 request_handle, | |
181 download_manager, | |
182 calculate_hash, | |
183 bound_net_log), | |
184 injector_(injector), | |
185 error_info_(error_info) { | |
186 // Record creation. | |
187 injector_->DownloadFileCreated(this); | |
cbentzel
2012/02/27 02:18:54
Are you worried at all about thread-safety issues
ahendrickson
2012/02/28 03:28:56
Switched to using RefCountedThreadSafe for the inj
| |
188 } | |
189 | |
190 DownloadFileWithErrors::~DownloadFileWithErrors() { | |
191 // Record destruction. | |
192 injector_->DestroyingDownloadFile(this); | |
193 } | |
194 | |
195 | |
196 net::Error DownloadFileWithErrors::Initialize() { | |
197 return ShouldReturnError(FILE_OPERATION_INITIALIZE, | |
198 DownloadFileImpl::Initialize()); | |
199 } | |
200 | |
201 net::Error DownloadFileWithErrors::AppendDataToFile(const char* data, | |
202 size_t data_len) { | |
203 return ShouldReturnError(FILE_OPERATION_WRITE, | |
204 DownloadFileImpl::AppendDataToFile(data, data_len)); | |
205 } | |
206 | |
207 net::Error DownloadFileWithErrors::Rename(const FilePath& full_path) { | |
208 return ShouldReturnError(FILE_OPERATION_RENAME, | |
209 DownloadFileImpl::Rename(full_path)); | |
210 } | |
211 | |
212 net::Error DownloadFileWithErrors::ShouldReturnError( | |
213 FileOperationCode code, | |
214 net::Error original_net_error) { | |
215 int counter = operation_counter_[code]; | |
cbentzel
2012/02/27 02:18:54
Looks like the operation_instance is always 0 when
ahendrickson
2012/02/28 03:28:56
Would prefer not to, as I have a use for this in m
| |
216 ++operation_counter_[code]; | |
217 | |
218 if (code != error_info_.code) | |
219 return original_net_error; // No error for this operation. | |
cbentzel
2012/02/27 02:18:54
Comments not really needed and a bit unclear actua
ahendrickson
2012/02/28 03:28:56
Removed.
| |
220 | |
221 if (counter != error_info_.operation_instance) | |
222 return original_net_error; // No error for this instance of the operation. | |
223 | |
224 DVLOG(20) << " " << __FUNCTION__ << "()" | |
225 << " code = " << ::DebugString(code) << " (" << code << ")" | |
226 << " counter = " << counter | |
227 << " original_error = " << original_net_error | |
228 << " new error = " << error_info_.net_error; | |
229 | |
230 return error_info_.net_error; // Error! | |
231 } | |
232 | |
233 DownloadFileWithErrorsFactory::DownloadFileWithErrorsFactory( | |
234 TestFileErrorInjectorImpl* injector) | |
cbentzel
2012/02/27 02:18:54
should be passed in via scoped_ptr if the Factory
ahendrickson
2012/02/28 03:28:56
Now using RefCountedThreadSafe for the injector.
| |
235 : file_counter_(0), injector_(injector) { | |
236 } | |
237 | |
238 DownloadFileWithErrorsFactory::~DownloadFileWithErrorsFactory() { | |
239 delete injector_; | |
240 injector_ = NULL; | |
241 } | |
242 | |
243 content::DownloadFile* DownloadFileWithErrorsFactory::CreateFile( | |
244 DownloadCreateInfo* info, | |
245 const DownloadRequestHandle& request_handle, | |
246 content::DownloadManager* download_manager, | |
247 bool calculate_hash, | |
248 const net::BoundNetLog& bound_net_log) { | |
249 // Creates entry if it doesn't exist. | |
250 injected_errors_[file_counter_].file_index = file_counter_; // Set index. | |
251 return new DownloadFileWithErrors(info, | |
252 new DownloadRequestHandle(request_handle), | |
253 download_manager, | |
254 calculate_hash, | |
255 bound_net_log, | |
256 injected_errors_[file_counter_++], | |
257 injector_); | |
258 } | |
259 | |
260 bool DownloadFileWithErrorsFactory::InjectError( | |
261 int file_index, | |
262 content::FileOperationCode operation, | |
263 int operation_instance, | |
264 net::Error net_error) { | |
265 DCHECK_LE(0, file_index); | |
266 DCHECK_LE(0, operation_instance); | |
267 | |
268 // Fill in a new entry. | |
269 FileErrorInfo info; | |
270 info.file_index = file_index; | |
271 info.code = operation; | |
272 info.operation_instance = operation_instance; | |
273 info.net_error = net_error; | |
274 | |
275 // Creates an empty entry if necessary. | |
276 injected_errors_[file_index] = info; | |
277 | |
278 return true; | |
279 } | |
280 | |
281 } // namespace content | |
282 | |
283 | |
284 // static | |
285 content::TestFileErrorInjector* content::TestFileErrorInjector::Create() { | |
286 return new TestFileErrorInjectorImpl; | |
287 } | |
288 | |
289 TestFileErrorInjectorImpl::TestFileErrorInjectorImpl() | |
290 : download_file_factory_(new content::DownloadFileWithErrorsFactory(this)) { | |
291 // |DownloadFileWithErrorsFactory| now owns |TestFileErrorInjectorImpl|. | |
292 DownloadFileManager* download_file_manager = | |
293 GetDownloadFileManager(); | |
294 DCHECK(download_file_manager); | |
295 // Transfers ownership to |DownloadFileManager|. | |
296 download_file_manager->SetFileFactory(download_file_factory_); | |
297 } | |
298 | |
299 TestFileErrorInjectorImpl::~TestFileErrorInjectorImpl() { | |
300 } | |
301 | |
302 bool TestFileErrorInjectorImpl::InjectError( | |
303 int file_index, | |
304 content::FileOperationCode operation, | |
305 int operation_instance, | |
306 net::Error net_error) { | |
307 return download_file_factory_->InjectError(file_index, | |
308 operation, | |
309 operation_instance, | |
310 net_error); | |
311 } | |
312 | |
313 size_t TestFileErrorInjectorImpl::CurrentFileCount() const { | |
314 return files_.size(); | |
cbentzel
2012/02/27 02:18:54
What is the thread-safety here?
ahendrickson
2012/02/28 03:28:56
All operations on files_ now happen on the UI thre
| |
315 } | |
316 | |
317 size_t TestFileErrorInjectorImpl::FileCreationCount() const { | |
318 return download_file_factory_->files_created(); | |
319 } | |
320 | |
321 | |
322 bool TestFileErrorInjectorImpl::HasFile(int file_index) const { | |
cbentzel
2012/02/27 02:18:54
You aren't using this. Would also remove the need
ahendrickson
2012/02/28 03:28:56
Now using it.
| |
323 return (files_.find(file_index) != files_.end()); | |
324 } | |
325 | |
326 void TestFileErrorInjectorImpl::DownloadFileCreated( | |
327 content::DownloadFileWithErrors* download_file) { | |
328 DCHECK(download_file != NULL); | |
329 | |
330 files_[download_file->index()] = download_file; | |
331 } | |
332 | |
333 void TestFileErrorInjectorImpl::DestroyingDownloadFile( | |
334 content::DownloadFileWithErrors* download_file) { | |
335 DCHECK(download_file != NULL); | |
336 | |
337 files_.erase(download_file->index()); | |
338 } | |
OLD | NEW |