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