1 // Copyright (c) 2012 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 "webkit/fileapi/syncable/canned_syncable_file_system.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/message_loop_proxy.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/task_runner_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "webkit/blob/mock_blob_url_request_context.h"
16 #include "webkit/browser/fileapi/external_mount_points.h"
17 #include "webkit/browser/fileapi/file_system_mount_point_provider.h"
18 #include "webkit/browser/fileapi/file_system_task_runners.h"
19 #include "webkit/browser/fileapi/local_file_system_operation.h"
20 #include "webkit/browser/fileapi/mock_file_system_options.h"
21 #include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
22 #include "webkit/fileapi/file_system_context.h"
23 #include "webkit/fileapi/file_system_operation_context.h"
24 #include "webkit/fileapi/syncable/local_file_change_tracker.h"
25 #include "webkit/fileapi/syncable/local_file_sync_context.h"
26 #include "webkit/fileapi/syncable/syncable_file_system_util.h"
27 #include "webkit/quota/mock_special_storage_policy.h"
28 #include "webkit/quota/quota_manager.h"
30 using base::PlatformFileError
;
31 using fileapi::FileSystemContext
;
32 using fileapi::FileSystemOperation
;
33 using fileapi::FileSystemURL
;
34 using fileapi::FileSystemURLSet
;
35 using quota::QuotaManager
;
36 using webkit_blob::MockBlobURLRequestContext
;
37 using webkit_blob::ScopedTextBlob
;
39 namespace sync_file_system
{
43 void Quit() { base::MessageLoop::current()->Quit(); }
46 void AssignAndQuit(base::TaskRunner
* original_task_runner
,
47 R
* result_out
, R result
) {
50 original_task_runner
->PostTask(FROM_HERE
, base::Bind(&Quit
));
55 base::SingleThreadTaskRunner
* task_runner
,
56 const tracked_objects::Location
& location
,
57 const base::Callback
<void(const base::Callback
<void(R
)>& callback
)>& task
) {
59 task_runner
->PostTask(
61 base::Bind(task
, base::Bind(&AssignAndQuit
<R
>,
62 base::MessageLoopProxy::current(),
64 base::MessageLoop::current()->Run();
68 void RunOnThread(base::SingleThreadTaskRunner
* task_runner
,
69 const tracked_objects::Location
& location
,
70 const base::Closure
& task
) {
71 task_runner
->PostTaskAndReply(
73 base::Bind(base::IgnoreResult(
74 base::Bind(&base::MessageLoopProxy::PostTask
,
75 base::MessageLoopProxy::current(),
76 FROM_HERE
, base::Bind(&Quit
)))));
77 base::MessageLoop::current()->Run();
80 void EnsureRunningOn(base::SingleThreadTaskRunner
* runner
) {
81 EXPECT_TRUE(runner
->RunsTasksOnCurrentThread());
84 void VerifySameTaskRunner(
85 base::SingleThreadTaskRunner
* runner1
,
86 base::SingleThreadTaskRunner
* runner2
) {
87 ASSERT_TRUE(runner1
!= NULL
);
88 ASSERT_TRUE(runner2
!= NULL
);
89 runner1
->PostTask(FROM_HERE
,
90 base::Bind(&EnsureRunningOn
, make_scoped_refptr(runner2
)));
93 void OnGetMetadataAndVerifyData(
94 const std::string
& expected_data
,
95 const CannedSyncableFileSystem::StatusCallback
& callback
,
96 base::PlatformFileError result
,
97 const base::PlatformFileInfo
& file_info
,
98 const base::FilePath
& platform_path
) {
99 if (result
!= base::PLATFORM_FILE_OK
) {
100 callback
.Run(result
);
103 EXPECT_EQ(expected_data
.size(), static_cast<size_t>(file_info
.size
));
105 const bool read_status
= file_util::ReadFileToString(platform_path
, &data
);
106 EXPECT_TRUE(read_status
);
107 EXPECT_EQ(expected_data
, data
);
108 callback
.Run(result
);
112 base::PlatformFileInfo
* file_info_out
,
113 base::FilePath
* platform_path_out
,
114 const CannedSyncableFileSystem::StatusCallback
& callback
,
115 base::PlatformFileError result
,
116 const base::PlatformFileInfo
& file_info
,
117 const base::FilePath
& platform_path
) {
118 DCHECK(file_info_out
);
119 DCHECK(platform_path_out
);
120 *file_info_out
= file_info
;
121 *platform_path_out
= platform_path
;
122 callback
.Run(result
);
127 WriteHelper() : bytes_written_(0) {}
128 WriteHelper(MockBlobURLRequestContext
* request_context
,
129 const GURL
& blob_url
,
130 const std::string
& blob_data
)
132 request_context_(request_context
),
133 blob_data_(new ScopedTextBlob(*request_context
, blob_url
, blob_data
)) {}
136 if (request_context_
) {
137 base::MessageLoop::current()->DeleteSoon(FROM_HERE
,
138 request_context_
.release());
142 void DidWrite(const base::Callback
<void(int64 result
)>& completion_callback
,
143 PlatformFileError error
, int64 bytes
, bool complete
) {
144 if (error
== base::PLATFORM_FILE_OK
) {
145 bytes_written_
+= bytes
;
149 completion_callback
.Run(error
== base::PLATFORM_FILE_OK
150 ? bytes_written_
: static_cast<int64
>(error
));
154 int64 bytes_written_
;
155 scoped_ptr
<MockBlobURLRequestContext
> request_context_
;
156 scoped_ptr
<ScopedTextBlob
> blob_data_
;
158 DISALLOW_COPY_AND_ASSIGN(WriteHelper
);
161 void DidGetUsageAndQuota(const quota::StatusCallback
& callback
,
162 int64
* usage_out
, int64
* quota_out
,
163 quota::QuotaStatusCode status
,
164 int64 usage
, int64 quota
) {
167 callback
.Run(status
);
170 void EnsureLastTaskRuns(base::SingleThreadTaskRunner
* runner
) {
171 base::RunLoop run_loop
;
172 runner
->PostTaskAndReply(
173 FROM_HERE
, base::Bind(&base::DoNothing
), run_loop
.QuitClosure());
179 CannedSyncableFileSystem::CannedSyncableFileSystem(
180 const GURL
& origin
, const std::string
& service
,
181 base::SingleThreadTaskRunner
* io_task_runner
,
182 base::SingleThreadTaskRunner
* file_task_runner
)
183 : service_name_(service
),
185 type_(fileapi::kFileSystemTypeSyncable
),
186 result_(base::PLATFORM_FILE_OK
),
187 sync_status_(sync_file_system::SYNC_STATUS_OK
),
188 io_task_runner_(io_task_runner
),
189 file_task_runner_(file_task_runner
),
190 is_filesystem_set_up_(false),
191 is_filesystem_opened_(false),
192 sync_status_observers_(new ObserverList
) {
195 CannedSyncableFileSystem::~CannedSyncableFileSystem() {}
197 void CannedSyncableFileSystem::SetUp() {
198 ASSERT_FALSE(is_filesystem_set_up_
);
199 ASSERT_TRUE(data_dir_
.CreateUniqueTempDir());
201 scoped_refptr
<quota::SpecialStoragePolicy
> storage_policy
=
202 new quota::MockSpecialStoragePolicy();
204 quota_manager_
= new QuotaManager(
205 false /* is_incognito */,
208 base::MessageLoopProxy::current(),
211 file_system_context_
= new FileSystemContext(
212 make_scoped_ptr(new fileapi::FileSystemTaskRunners(
216 fileapi::ExternalMountPoints::CreateRefCounted().get(),
218 quota_manager_
->proxy(),
219 ScopedVector
<fileapi::FileSystemMountPointProvider
>(),
221 fileapi::CreateAllowFileAccessOptions());
223 // In testing we override this setting to support directory operations
225 SetEnableSyncFSDirectoryOperation(true);
227 is_filesystem_set_up_
= true;
230 void CannedSyncableFileSystem::TearDown() {
231 quota_manager_
= NULL
;
232 file_system_context_
= NULL
;
233 SetEnableSyncFSDirectoryOperation(false);
235 // Make sure we give some more time to finish tasks on other threads.
236 EnsureLastTaskRuns(io_task_runner_
);
237 EnsureLastTaskRuns(file_task_runner_
);
240 FileSystemURL
CannedSyncableFileSystem::URL(const std::string
& path
) const {
241 EXPECT_TRUE(is_filesystem_set_up_
);
242 EXPECT_TRUE(is_filesystem_opened_
);
244 GURL
url(root_url_
.spec() + path
);
245 return file_system_context_
->CrackURL(url
);
248 PlatformFileError
CannedSyncableFileSystem::OpenFileSystem() {
249 EXPECT_TRUE(is_filesystem_set_up_
);
250 EXPECT_FALSE(is_filesystem_opened_
);
251 file_system_context_
->OpenSyncableFileSystem(
252 service_name_
, origin_
, type_
, true /* create */,
253 base::Bind(&CannedSyncableFileSystem::DidOpenFileSystem
,
254 base::Unretained(this)));
255 base::MessageLoop::current()->Run();
256 if (file_system_context_
->sync_context()) {
257 // Register 'this' as a sync status observer.
258 RunOnThread(io_task_runner_
,
261 &CannedSyncableFileSystem::InitializeSyncStatusObserver
,
262 base::Unretained(this)));
267 void CannedSyncableFileSystem::AddSyncStatusObserver(
268 LocalFileSyncStatus::Observer
* observer
) {
269 sync_status_observers_
->AddObserver(observer
);
272 void CannedSyncableFileSystem::RemoveSyncStatusObserver(
273 LocalFileSyncStatus::Observer
* observer
) {
274 sync_status_observers_
->RemoveObserver(observer
);
277 SyncStatusCode
CannedSyncableFileSystem::MaybeInitializeFileSystemContext(
278 LocalFileSyncContext
* sync_context
) {
279 DCHECK(sync_context
);
280 sync_status_
= sync_file_system::SYNC_STATUS_UNKNOWN
;
281 VerifySameTaskRunner(io_task_runner_
, sync_context
->io_task_runner_
);
282 sync_context
->MaybeInitializeFileSystemContext(
283 origin_
, service_name_
, file_system_context_
,
284 base::Bind(&CannedSyncableFileSystem::DidInitializeFileSystemContext
,
285 base::Unretained(this)));
286 base::MessageLoop::current()->Run();
290 PlatformFileError
CannedSyncableFileSystem::CreateDirectory(
291 const FileSystemURL
& url
) {
292 return RunOnThread
<PlatformFileError
>(
295 base::Bind(&CannedSyncableFileSystem::DoCreateDirectory
,
296 base::Unretained(this), url
));
299 PlatformFileError
CannedSyncableFileSystem::CreateFile(
300 const FileSystemURL
& url
) {
301 return RunOnThread
<PlatformFileError
>(
304 base::Bind(&CannedSyncableFileSystem::DoCreateFile
,
305 base::Unretained(this), url
));
308 PlatformFileError
CannedSyncableFileSystem::Copy(
309 const FileSystemURL
& src_url
, const FileSystemURL
& dest_url
) {
310 return RunOnThread
<PlatformFileError
>(
313 base::Bind(&CannedSyncableFileSystem::DoCopy
,
314 base::Unretained(this), src_url
, dest_url
));
317 PlatformFileError
CannedSyncableFileSystem::Move(
318 const FileSystemURL
& src_url
, const FileSystemURL
& dest_url
) {
319 return RunOnThread
<PlatformFileError
>(
322 base::Bind(&CannedSyncableFileSystem::DoMove
,
323 base::Unretained(this), src_url
, dest_url
));
326 PlatformFileError
CannedSyncableFileSystem::TruncateFile(
327 const FileSystemURL
& url
, int64 size
) {
328 return RunOnThread
<PlatformFileError
>(
331 base::Bind(&CannedSyncableFileSystem::DoTruncateFile
,
332 base::Unretained(this), url
, size
));
335 PlatformFileError
CannedSyncableFileSystem::TouchFile(
336 const FileSystemURL
& url
,
337 const base::Time
& last_access_time
,
338 const base::Time
& last_modified_time
) {
339 return RunOnThread
<PlatformFileError
>(
342 base::Bind(&CannedSyncableFileSystem::DoTouchFile
,
343 base::Unretained(this), url
,
344 last_access_time
, last_modified_time
));
347 PlatformFileError
CannedSyncableFileSystem::Remove(
348 const FileSystemURL
& url
, bool recursive
) {
349 return RunOnThread
<PlatformFileError
>(
352 base::Bind(&CannedSyncableFileSystem::DoRemove
,
353 base::Unretained(this), url
, recursive
));
356 PlatformFileError
CannedSyncableFileSystem::FileExists(
357 const FileSystemURL
& url
) {
358 return RunOnThread
<PlatformFileError
>(
361 base::Bind(&CannedSyncableFileSystem::DoFileExists
,
362 base::Unretained(this), url
));
365 PlatformFileError
CannedSyncableFileSystem::DirectoryExists(
366 const FileSystemURL
& url
) {
367 return RunOnThread
<PlatformFileError
>(
370 base::Bind(&CannedSyncableFileSystem::DoDirectoryExists
,
371 base::Unretained(this), url
));
374 PlatformFileError
CannedSyncableFileSystem::VerifyFile(
375 const FileSystemURL
& url
,
376 const std::string
& expected_data
) {
377 return RunOnThread
<PlatformFileError
>(
380 base::Bind(&CannedSyncableFileSystem::DoVerifyFile
,
381 base::Unretained(this), url
, expected_data
));
384 PlatformFileError
CannedSyncableFileSystem::GetMetadata(
385 const FileSystemURL
& url
,
386 base::PlatformFileInfo
* info
,
387 base::FilePath
* platform_path
) {
388 return RunOnThread
<PlatformFileError
>(
391 base::Bind(&CannedSyncableFileSystem::DoGetMetadata
,
392 base::Unretained(this), url
, info
, platform_path
));
395 int64
CannedSyncableFileSystem::Write(
396 net::URLRequestContext
* url_request_context
,
397 const FileSystemURL
& url
, const GURL
& blob_url
) {
398 return RunOnThread
<int64
>(
401 base::Bind(&CannedSyncableFileSystem::DoWrite
,
402 base::Unretained(this), url_request_context
, url
, blob_url
));
405 int64
CannedSyncableFileSystem::WriteString(
406 const FileSystemURL
& url
, const std::string
& data
) {
407 return RunOnThread
<int64
>(
410 base::Bind(&CannedSyncableFileSystem::DoWriteString
,
411 base::Unretained(this), url
, data
));
414 PlatformFileError
CannedSyncableFileSystem::DeleteFileSystem() {
415 EXPECT_TRUE(is_filesystem_set_up_
);
416 return RunOnThread
<PlatformFileError
>(
419 base::Bind(&FileSystemContext::DeleteFileSystem
,
420 file_system_context_
, origin_
, type_
));
423 quota::QuotaStatusCode
CannedSyncableFileSystem::GetUsageAndQuota(
424 int64
* usage
, int64
* quota
) {
425 return RunOnThread
<quota::QuotaStatusCode
>(
428 base::Bind(&CannedSyncableFileSystem::DoGetUsageAndQuota
,
429 base::Unretained(this), usage
, quota
));
432 void CannedSyncableFileSystem::GetChangedURLsInTracker(
433 FileSystemURLSet
* urls
) {
437 base::Bind(&LocalFileChangeTracker::GetAllChangedURLs
,
438 base::Unretained(file_system_context_
->change_tracker()),
442 void CannedSyncableFileSystem::ClearChangeForURLInTracker(
443 const FileSystemURL
& url
) {
447 base::Bind(&LocalFileChangeTracker::ClearChangesForURL
,
448 base::Unretained(file_system_context_
->change_tracker()),
452 FileSystemOperation
* CannedSyncableFileSystem::NewOperation() {
453 return file_system_context_
->CreateFileSystemOperation(URL(std::string()),
457 void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL
& url
) {
458 sync_status_observers_
->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled
,
462 void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL
& url
) {
463 sync_status_observers_
->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled
,
467 void CannedSyncableFileSystem::DoCreateDirectory(
468 const FileSystemURL
& url
,
469 const StatusCallback
& callback
) {
470 EXPECT_TRUE(is_filesystem_opened_
);
471 NewOperation()->CreateDirectory(
472 url
, false /* exclusive */, false /* recursive */, callback
);
475 void CannedSyncableFileSystem::DoCreateFile(
476 const FileSystemURL
& url
,
477 const StatusCallback
& callback
) {
478 EXPECT_TRUE(is_filesystem_opened_
);
479 NewOperation()->CreateFile(url
, false /* exclusive */, callback
);
482 void CannedSyncableFileSystem::DoCopy(
483 const FileSystemURL
& src_url
,
484 const FileSystemURL
& dest_url
,
485 const StatusCallback
& callback
) {
486 EXPECT_TRUE(is_filesystem_opened_
);
487 NewOperation()->Copy(src_url
, dest_url
, callback
);
490 void CannedSyncableFileSystem::DoMove(
491 const FileSystemURL
& src_url
,
492 const FileSystemURL
& dest_url
,
493 const StatusCallback
& callback
) {
494 EXPECT_TRUE(is_filesystem_opened_
);
495 NewOperation()->Move(src_url
, dest_url
, callback
);
498 void CannedSyncableFileSystem::DoTruncateFile(
499 const FileSystemURL
& url
, int64 size
,
500 const StatusCallback
& callback
) {
501 EXPECT_TRUE(is_filesystem_opened_
);
502 NewOperation()->Truncate(url
, size
, callback
);
505 void CannedSyncableFileSystem::DoTouchFile(
506 const FileSystemURL
& url
,
507 const base::Time
& last_access_time
,
508 const base::Time
& last_modified_time
,
509 const StatusCallback
& callback
) {
510 EXPECT_TRUE(is_filesystem_opened_
);
511 NewOperation()->TouchFile(url
, last_access_time
,
512 last_modified_time
, callback
);
515 void CannedSyncableFileSystem::DoRemove(
516 const FileSystemURL
& url
, bool recursive
,
517 const StatusCallback
& callback
) {
518 EXPECT_TRUE(is_filesystem_opened_
);
519 NewOperation()->Remove(url
, recursive
, callback
);
522 void CannedSyncableFileSystem::DoFileExists(
523 const FileSystemURL
& url
, const StatusCallback
& callback
) {
524 EXPECT_TRUE(is_filesystem_opened_
);
525 NewOperation()->FileExists(url
, callback
);
528 void CannedSyncableFileSystem::DoDirectoryExists(
529 const FileSystemURL
& url
, const StatusCallback
& callback
) {
530 EXPECT_TRUE(is_filesystem_opened_
);
531 NewOperation()->DirectoryExists(url
, callback
);
534 void CannedSyncableFileSystem::DoVerifyFile(
535 const FileSystemURL
& url
,
536 const std::string
& expected_data
,
537 const StatusCallback
& callback
) {
538 EXPECT_TRUE(is_filesystem_opened_
);
539 NewOperation()->GetMetadata(
540 url
, base::Bind(&OnGetMetadataAndVerifyData
,
541 expected_data
, callback
));
544 void CannedSyncableFileSystem::DoGetMetadata(
545 const FileSystemURL
& url
,
546 base::PlatformFileInfo
* info
,
547 base::FilePath
* platform_path
,
548 const StatusCallback
& callback
) {
549 EXPECT_TRUE(is_filesystem_opened_
);
550 NewOperation()->GetMetadata(
551 url
, base::Bind(&OnGetMetadata
, info
, platform_path
, callback
));
554 void CannedSyncableFileSystem::DoWrite(
555 net::URLRequestContext
* url_request_context
,
556 const FileSystemURL
& url
, const GURL
& blob_url
,
557 const WriteCallback
& callback
) {
558 EXPECT_TRUE(is_filesystem_opened_
);
559 WriteHelper
* helper
= new WriteHelper
;
560 NewOperation()->Write(url_request_context
, url
, blob_url
, 0,
561 base::Bind(&WriteHelper::DidWrite
,
562 base::Owned(helper
), callback
));
565 void CannedSyncableFileSystem::DoWriteString(
566 const FileSystemURL
& url
,
567 const std::string
& data
,
568 const WriteCallback
& callback
) {
569 MockBlobURLRequestContext
* url_request_context(
570 new MockBlobURLRequestContext(file_system_context_
));
571 const GURL
blob_url(std::string("blob:") + data
);
572 WriteHelper
* helper
= new WriteHelper(url_request_context
, blob_url
, data
);
573 NewOperation()->Write(url_request_context
, url
, blob_url
, 0,
574 base::Bind(&WriteHelper::DidWrite
,
575 base::Owned(helper
), callback
));
578 void CannedSyncableFileSystem::DoGetUsageAndQuota(
581 const quota::StatusCallback
& callback
) {
582 quota_manager_
->GetUsageAndQuota(
583 origin_
, storage_type(),
584 base::Bind(&DidGetUsageAndQuota
, callback
, usage
, quota
));
587 void CannedSyncableFileSystem::DidOpenFileSystem(
588 PlatformFileError result
, const std::string
& name
, const GURL
& root
) {
591 is_filesystem_opened_
= true;
592 base::MessageLoop::current()->Quit();
595 void CannedSyncableFileSystem::DidInitializeFileSystemContext(
596 SyncStatusCode status
) {
597 sync_status_
= status
;
598 base::MessageLoop::current()->Quit();
601 void CannedSyncableFileSystem::InitializeSyncStatusObserver() {
602 ASSERT_TRUE(io_task_runner_
->RunsTasksOnCurrentThread());
603 file_system_context_
->sync_context()->sync_status()->AddObserver(this);
606 } // namespace sync_file_system