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

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: Simplified injector classes further. Created 8 years, 10 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/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 }
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