OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 <vector> | |
6 | |
7 #include "base/files/scoped_temp_dir.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/memory/weak_ptr.h" | |
10 #include "base/message_loop/message_loop_proxy.h" | |
11 #include "base/run_loop.h" | |
12 #include "net/url_request/url_request.h" | |
13 #include "net/url_request/url_request_context.h" | |
14 #include "net/url_request/url_request_job.h" | |
15 #include "net/url_request/url_request_job_factory_impl.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "url/gurl.h" | |
18 #include "webkit/browser/blob/blob_storage_context.h" | |
19 #include "webkit/browser/blob/blob_url_request_job.h" | |
20 #include "webkit/browser/blob/mock_blob_url_request_context.h" | |
21 #include "webkit/browser/fileapi/file_system_context.h" | |
22 #include "webkit/browser/fileapi/file_system_file_util.h" | |
23 #include "webkit/browser/fileapi/file_system_operation_context.h" | |
24 #include "webkit/browser/fileapi/file_system_operation_runner.h" | |
25 #include "webkit/browser/fileapi/local_file_util.h" | |
26 #include "webkit/browser/fileapi/mock_file_change_observer.h" | |
27 #include "webkit/browser/fileapi/mock_file_system_context.h" | |
28 #include "webkit/browser/fileapi/test_file_system_backend.h" | |
29 #include "webkit/browser/quota/mock_quota_manager.h" | |
30 #include "webkit/common/blob/blob_data.h" | |
31 #include "webkit/common/fileapi/file_system_util.h" | |
32 | |
33 using webkit_blob::MockBlobURLRequestContext; | |
34 using webkit_blob::ScopedTextBlob; | |
35 | |
36 namespace fileapi { | |
37 | |
38 namespace { | |
39 | |
40 const GURL kOrigin("http://example.com"); | |
41 const FileSystemType kFileSystemType = kFileSystemTypeTest; | |
42 | |
43 void AssertStatusEq(base::PlatformFileError expected, | |
44 base::PlatformFileError actual) { | |
45 ASSERT_EQ(expected, actual); | |
46 } | |
47 | |
48 } // namespace | |
49 | |
50 class FileSystemOperationImplWriteTest | |
51 : public testing::Test { | |
52 public: | |
53 FileSystemOperationImplWriteTest() | |
54 : status_(base::PLATFORM_FILE_OK), | |
55 cancel_status_(base::PLATFORM_FILE_ERROR_FAILED), | |
56 bytes_written_(0), | |
57 complete_(false), | |
58 weak_factory_(this) { | |
59 change_observers_ = MockFileChangeObserver::CreateList(&change_observer_); | |
60 } | |
61 | |
62 virtual void SetUp() { | |
63 ASSERT_TRUE(dir_.CreateUniqueTempDir()); | |
64 | |
65 quota_manager_ = | |
66 new quota::MockQuotaManager(false /* is_incognito */, | |
67 dir_.path(), | |
68 base::MessageLoopProxy::current().get(), | |
69 base::MessageLoopProxy::current().get(), | |
70 NULL /* special storage policy */); | |
71 virtual_path_ = base::FilePath(FILE_PATH_LITERAL("temporary file")); | |
72 | |
73 file_system_context_ = CreateFileSystemContextForTesting( | |
74 quota_manager_->proxy(), dir_.path()); | |
75 url_request_context_.reset( | |
76 new MockBlobURLRequestContext(file_system_context_.get())); | |
77 | |
78 file_system_context_->operation_runner()->CreateFile( | |
79 URLForPath(virtual_path_), true /* exclusive */, | |
80 base::Bind(&AssertStatusEq, base::PLATFORM_FILE_OK)); | |
81 | |
82 static_cast<TestFileSystemBackend*>( | |
83 file_system_context_->GetFileSystemBackend(kFileSystemType)) | |
84 ->AddFileChangeObserver(change_observer()); | |
85 } | |
86 | |
87 virtual void TearDown() { | |
88 quota_manager_ = NULL; | |
89 file_system_context_ = NULL; | |
90 base::RunLoop().RunUntilIdle(); | |
91 } | |
92 | |
93 base::PlatformFileError status() const { return status_; } | |
94 base::PlatformFileError cancel_status() const { return cancel_status_; } | |
95 void add_bytes_written(int64 bytes, bool complete) { | |
96 bytes_written_ += bytes; | |
97 EXPECT_FALSE(complete_); | |
98 complete_ = complete; | |
99 } | |
100 int64 bytes_written() const { return bytes_written_; } | |
101 bool complete() const { return complete_; } | |
102 | |
103 protected: | |
104 const ChangeObserverList& change_observers() const { | |
105 return change_observers_; | |
106 } | |
107 | |
108 MockFileChangeObserver* change_observer() { | |
109 return &change_observer_; | |
110 } | |
111 | |
112 FileSystemURL URLForPath(const base::FilePath& path) const { | |
113 return file_system_context_->CreateCrackedFileSystemURL( | |
114 kOrigin, kFileSystemType, path); | |
115 } | |
116 | |
117 // Callback function for recording test results. | |
118 FileSystemOperation::WriteCallback RecordWriteCallback() { | |
119 return base::Bind(&FileSystemOperationImplWriteTest::DidWrite, | |
120 weak_factory_.GetWeakPtr()); | |
121 } | |
122 | |
123 FileSystemOperation::StatusCallback RecordCancelCallback() { | |
124 return base::Bind(&FileSystemOperationImplWriteTest::DidCancel, | |
125 weak_factory_.GetWeakPtr()); | |
126 } | |
127 | |
128 void DidWrite(base::PlatformFileError status, int64 bytes, bool complete) { | |
129 if (status == base::PLATFORM_FILE_OK) { | |
130 add_bytes_written(bytes, complete); | |
131 if (complete) | |
132 base::MessageLoop::current()->Quit(); | |
133 } else { | |
134 EXPECT_FALSE(complete_); | |
135 EXPECT_EQ(status_, base::PLATFORM_FILE_OK); | |
136 complete_ = true; | |
137 status_ = status; | |
138 if (base::MessageLoop::current()->is_running()) | |
139 base::MessageLoop::current()->Quit(); | |
140 } | |
141 } | |
142 | |
143 void DidCancel(base::PlatformFileError status) { | |
144 cancel_status_ = status; | |
145 } | |
146 | |
147 const MockBlobURLRequestContext& url_request_context() const { | |
148 return *url_request_context_; | |
149 } | |
150 | |
151 scoped_refptr<FileSystemContext> file_system_context_; | |
152 scoped_refptr<quota::MockQuotaManager> quota_manager_; | |
153 | |
154 base::MessageLoopForIO loop_; | |
155 | |
156 base::ScopedTempDir dir_; | |
157 base::FilePath virtual_path_; | |
158 | |
159 // For post-operation status. | |
160 base::PlatformFileError status_; | |
161 base::PlatformFileError cancel_status_; | |
162 int64 bytes_written_; | |
163 bool complete_; | |
164 | |
165 scoped_ptr<MockBlobURLRequestContext> url_request_context_; | |
166 | |
167 MockFileChangeObserver change_observer_; | |
168 ChangeObserverList change_observers_; | |
169 | |
170 base::WeakPtrFactory<FileSystemOperationImplWriteTest> weak_factory_; | |
171 | |
172 DISALLOW_COPY_AND_ASSIGN(FileSystemOperationImplWriteTest); | |
173 }; | |
174 | |
175 TEST_F(FileSystemOperationImplWriteTest, TestWriteSuccess) { | |
176 ScopedTextBlob blob(url_request_context(), | |
177 "blob-id:success", | |
178 "Hello, world!\n"); | |
179 file_system_context_->operation_runner()->Write( | |
180 &url_request_context(), URLForPath(virtual_path_), | |
181 blob.GetBlobDataHandle(), | |
182 0, RecordWriteCallback()); | |
183 base::MessageLoop::current()->Run(); | |
184 | |
185 EXPECT_EQ(14, bytes_written()); | |
186 EXPECT_EQ(base::PLATFORM_FILE_OK, status()); | |
187 EXPECT_TRUE(complete()); | |
188 | |
189 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | |
190 } | |
191 | |
192 TEST_F(FileSystemOperationImplWriteTest, TestWriteZero) { | |
193 ScopedTextBlob blob(url_request_context(), "blob_id:zero", ""); | |
194 file_system_context_->operation_runner()->Write( | |
195 &url_request_context(), URLForPath(virtual_path_), | |
196 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
197 base::MessageLoop::current()->Run(); | |
198 | |
199 EXPECT_EQ(0, bytes_written()); | |
200 EXPECT_EQ(base::PLATFORM_FILE_OK, status()); | |
201 EXPECT_TRUE(complete()); | |
202 | |
203 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | |
204 } | |
205 | |
206 | |
207 TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) { | |
208 scoped_ptr<webkit_blob::BlobDataHandle> null_handle; | |
209 file_system_context_->operation_runner()->Write( | |
210 &url_request_context(), URLForPath(virtual_path_), | |
211 null_handle.Pass(), 0, RecordWriteCallback()); | |
212 base::MessageLoop::current()->Run(); | |
213 | |
214 EXPECT_EQ(0, bytes_written()); | |
215 EXPECT_EQ(base::PLATFORM_FILE_ERROR_FAILED, status()); | |
216 EXPECT_TRUE(complete()); | |
217 | |
218 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count()); | |
219 } | |
220 | |
221 TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidFile) { | |
222 ScopedTextBlob blob(url_request_context(), "blob_id:writeinvalidfile", | |
223 "It\'ll not be written."); | |
224 file_system_context_->operation_runner()->Write( | |
225 &url_request_context(), | |
226 URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))), | |
227 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
228 base::MessageLoop::current()->Run(); | |
229 | |
230 EXPECT_EQ(0, bytes_written()); | |
231 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); | |
232 EXPECT_TRUE(complete()); | |
233 | |
234 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | |
235 } | |
236 | |
237 TEST_F(FileSystemOperationImplWriteTest, TestWriteDir) { | |
238 base::FilePath virtual_dir_path(FILE_PATH_LITERAL("d")); | |
239 file_system_context_->operation_runner()->CreateDirectory( | |
240 URLForPath(virtual_dir_path), | |
241 true /* exclusive */, false /* recursive */, | |
242 base::Bind(&AssertStatusEq, base::PLATFORM_FILE_OK)); | |
243 | |
244 ScopedTextBlob blob(url_request_context(), "blob:writedir", | |
245 "It\'ll not be written, too."); | |
246 file_system_context_->operation_runner()->Write( | |
247 &url_request_context(), URLForPath(virtual_dir_path), | |
248 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
249 base::MessageLoop::current()->Run(); | |
250 | |
251 EXPECT_EQ(0, bytes_written()); | |
252 // TODO(kinuko): This error code is platform- or fileutil- dependent | |
253 // right now. Make it return PLATFORM_FILE_ERROR_NOT_A_FILE in every case. | |
254 EXPECT_TRUE(status() == base::PLATFORM_FILE_ERROR_NOT_A_FILE || | |
255 status() == base::PLATFORM_FILE_ERROR_ACCESS_DENIED || | |
256 status() == base::PLATFORM_FILE_ERROR_FAILED); | |
257 EXPECT_TRUE(complete()); | |
258 | |
259 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | |
260 } | |
261 | |
262 TEST_F(FileSystemOperationImplWriteTest, TestWriteFailureByQuota) { | |
263 ScopedTextBlob blob(url_request_context(), "blob:success", | |
264 "Hello, world!\n"); | |
265 quota_manager_->SetQuota( | |
266 kOrigin, FileSystemTypeToQuotaStorageType(kFileSystemType), 10); | |
267 file_system_context_->operation_runner()->Write( | |
268 &url_request_context(), URLForPath(virtual_path_), | |
269 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
270 base::MessageLoop::current()->Run(); | |
271 | |
272 EXPECT_EQ(10, bytes_written()); | |
273 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status()); | |
274 EXPECT_TRUE(complete()); | |
275 | |
276 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | |
277 } | |
278 | |
279 TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelSuccessfulWrite) { | |
280 ScopedTextBlob blob(url_request_context(), "blob:success", | |
281 "Hello, world!\n"); | |
282 FileSystemOperationRunner::OperationID id = | |
283 file_system_context_->operation_runner()->Write( | |
284 &url_request_context(), URLForPath(virtual_path_), | |
285 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
286 file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback()); | |
287 // We use RunAllPendings() instead of Run() here, because we won't dispatch | |
288 // callbacks after Cancel() is issued (so no chance to Quit) nor do we need | |
289 // to run another write cycle. | |
290 base::RunLoop().RunUntilIdle(); | |
291 | |
292 // Issued Cancel() before receiving any response from Write(), | |
293 // so nothing should have happen. | |
294 EXPECT_EQ(0, bytes_written()); | |
295 EXPECT_EQ(base::PLATFORM_FILE_ERROR_ABORT, status()); | |
296 EXPECT_EQ(base::PLATFORM_FILE_OK, cancel_status()); | |
297 EXPECT_TRUE(complete()); | |
298 | |
299 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count()); | |
300 } | |
301 | |
302 TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelFailingWrite) { | |
303 ScopedTextBlob blob(url_request_context(), "blob:writeinvalidfile", | |
304 "It\'ll not be written."); | |
305 FileSystemOperationRunner::OperationID id = | |
306 file_system_context_->operation_runner()->Write( | |
307 &url_request_context(), | |
308 URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))), | |
309 blob.GetBlobDataHandle(), 0, RecordWriteCallback()); | |
310 file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback()); | |
311 // We use RunAllPendings() instead of Run() here, because we won't dispatch | |
312 // callbacks after Cancel() is issued (so no chance to Quit) nor do we need | |
313 // to run another write cycle. | |
314 base::RunLoop().RunUntilIdle(); | |
315 | |
316 // Issued Cancel() before receiving any response from Write(), | |
317 // so nothing should have happen. | |
318 EXPECT_EQ(0, bytes_written()); | |
319 EXPECT_EQ(base::PLATFORM_FILE_ERROR_ABORT, status()); | |
320 EXPECT_EQ(base::PLATFORM_FILE_OK, cancel_status()); | |
321 EXPECT_TRUE(complete()); | |
322 | |
323 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count()); | |
324 } | |
325 | |
326 // TODO(ericu,dmikurube,kinuko): Add more tests for cancel cases. | |
327 | |
328 } // namespace fileapi | |
OLD | NEW |