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