- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / file_system_operation_impl_write_unittest.cc
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 "content/public/test/test_file_system_backend.h"
13 #include "content/public/test/test_file_system_context.h"
14 #include "net/url_request/url_request.h"
15 #include "net/url_request/url_request_context.h"
16 #include "net/url_request/url_request_job.h"
17 #include "net/url_request/url_request_job_factory_impl.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "url/gurl.h"
20 #include "webkit/browser/blob/blob_storage_context.h"
21 #include "webkit/browser/blob/blob_url_request_job.h"
22 #include "webkit/browser/blob/mock_blob_url_request_context.h"
23 #include "webkit/browser/fileapi/file_system_context.h"
24 #include "webkit/browser/fileapi/file_system_file_util.h"
25 #include "webkit/browser/fileapi/file_system_operation_context.h"
26 #include "webkit/browser/fileapi/file_system_operation_runner.h"
27 #include "webkit/browser/fileapi/local_file_util.h"
28 #include "webkit/browser/fileapi/mock_file_change_observer.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