Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / fileapi / file_system_operation_impl_write_unittest.cc
blob899bb5f94da311389c884c29826cf57b8eceadee
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.
5 #include <vector>
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"
33 using storage::FileSystemOperation;
34 using storage::FileSystemOperationRunner;
35 using storage::FileSystemURL;
36 using content::MockBlobURLRequestContext;
37 using content::ScopedTextBlob;
39 namespace content {
41 namespace {
43 const GURL kOrigin("http://example.com");
44 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
46 void AssertStatusEq(base::File::Error expected,
47 base::File::Error actual) {
48 ASSERT_EQ(expected, actual);
51 } // namespace
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_ =
63 storage::MockFileChangeObserver::CreateList(&change_observer_);
66 virtual void SetUp() {
67 ASSERT_TRUE(dir_.CreateUniqueTempDir());
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"));
77 file_system_context_ = CreateFileSystemContextForTesting(
78 quota_manager_->proxy(), dir_.path());
79 url_request_context_.reset(
80 new MockBlobURLRequestContext(file_system_context_.get()));
82 file_system_context_->operation_runner()->CreateFile(
83 URLForPath(virtual_path_), true /* exclusive */,
84 base::Bind(&AssertStatusEq, base::File::FILE_OK));
86 static_cast<TestFileSystemBackend*>(
87 file_system_context_->GetFileSystemBackend(kFileSystemType))
88 ->AddFileChangeObserver(change_observer());
91 virtual void TearDown() {
92 quota_manager_ = NULL;
93 file_system_context_ = NULL;
94 base::RunLoop().RunUntilIdle();
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;
104 int64 bytes_written() const { return bytes_written_; }
105 bool complete() const { return complete_; }
107 protected:
108 const storage::ChangeObserverList& change_observers() const {
109 return change_observers_;
112 storage::MockFileChangeObserver* change_observer() {
113 return &change_observer_;
116 FileSystemURL URLForPath(const base::FilePath& path) const {
117 return file_system_context_->CreateCrackedFileSystemURL(
118 kOrigin, kFileSystemType, path);
121 // Callback function for recording test results.
122 FileSystemOperation::WriteCallback RecordWriteCallback() {
123 return base::Bind(&FileSystemOperationImplWriteTest::DidWrite,
124 weak_factory_.GetWeakPtr());
127 FileSystemOperation::StatusCallback RecordCancelCallback() {
128 return base::Bind(&FileSystemOperationImplWriteTest::DidCancel,
129 weak_factory_.GetWeakPtr());
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();
147 void DidCancel(base::File::Error status) {
148 cancel_status_ = status;
151 const MockBlobURLRequestContext& url_request_context() const {
152 return *url_request_context_;
155 scoped_refptr<storage::FileSystemContext> file_system_context_;
156 scoped_refptr<MockQuotaManager> quota_manager_;
158 base::MessageLoopForIO loop_;
160 base::ScopedTempDir dir_;
161 base::FilePath virtual_path_;
163 // For post-operation status.
164 base::File::Error status_;
165 base::File::Error cancel_status_;
166 int64 bytes_written_;
167 bool complete_;
169 scoped_ptr<MockBlobURLRequestContext> url_request_context_;
171 storage::MockFileChangeObserver change_observer_;
172 storage::ChangeObserverList change_observers_;
174 base::WeakPtrFactory<FileSystemOperationImplWriteTest> weak_factory_;
176 DISALLOW_COPY_AND_ASSIGN(FileSystemOperationImplWriteTest);
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();
189 EXPECT_EQ(14, bytes_written());
190 EXPECT_EQ(base::File::FILE_OK, status());
191 EXPECT_TRUE(complete());
193 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
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();
203 EXPECT_EQ(0, bytes_written());
204 EXPECT_EQ(base::File::FILE_OK, status());
205 EXPECT_TRUE(complete());
207 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
211 TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) {
212 scoped_ptr<storage::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();
218 EXPECT_EQ(0, bytes_written());
219 EXPECT_EQ(base::File::FILE_ERROR_FAILED, status());
220 EXPECT_TRUE(complete());
222 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count());
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();
234 EXPECT_EQ(0, bytes_written());
235 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
236 EXPECT_TRUE(complete());
238 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
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));
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();
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());
263 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
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();
276 EXPECT_EQ(10, bytes_written());
277 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, status());
278 EXPECT_TRUE(complete());
280 EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
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();
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());
303 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count());
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();
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());
327 EXPECT_EQ(0, change_observer()->get_and_reset_modify_file_count());
330 // TODO(ericu,dmikurube,kinuko): Add more tests for cancel cases.
332 } // namespace content