Fix Win8 metro startup crash from window switcher button
[chromium-blink-merge.git] / webkit / fileapi / syncable / canned_syncable_file_system.cc
blob59dbbfa64b7ac79ea974261e47e305d0556f1e17
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"
7 #include "base/bind.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 {
41 namespace {
43 void Quit() { base::MessageLoop::current()->Quit(); }
45 template <typename R>
46 void AssignAndQuit(base::TaskRunner* original_task_runner,
47 R* result_out, R result) {
48 DCHECK(result_out);
49 *result_out = result;
50 original_task_runner->PostTask(FROM_HERE, base::Bind(&Quit));
53 template <typename R>
54 R RunOnThread(
55 base::SingleThreadTaskRunner* task_runner,
56 const tracked_objects::Location& location,
57 const base::Callback<void(const base::Callback<void(R)>& callback)>& task) {
58 R result;
59 task_runner->PostTask(
60 location,
61 base::Bind(task, base::Bind(&AssignAndQuit<R>,
62 base::MessageLoopProxy::current(),
63 &result)));
64 base::MessageLoop::current()->Run();
65 return result;
68 void RunOnThread(base::SingleThreadTaskRunner* task_runner,
69 const tracked_objects::Location& location,
70 const base::Closure& task) {
71 task_runner->PostTaskAndReply(
72 location, task,
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);
101 return;
103 EXPECT_EQ(expected_data.size(), static_cast<size_t>(file_info.size));
104 std::string data;
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);
111 void OnGetMetadata(
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);
125 class WriteHelper {
126 public:
127 WriteHelper() : bytes_written_(0) {}
128 WriteHelper(MockBlobURLRequestContext* request_context,
129 const GURL& blob_url,
130 const std::string& blob_data)
131 : bytes_written_(0),
132 request_context_(request_context),
133 blob_data_(new ScopedTextBlob(*request_context, blob_url, blob_data)) {}
135 ~WriteHelper() {
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;
146 if (!complete)
147 return;
149 completion_callback.Run(error == base::PLATFORM_FILE_OK
150 ? bytes_written_ : static_cast<int64>(error));
153 private:
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) {
165 *usage_out = usage;
166 *quota_out = 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());
174 run_loop.Run();
177 } // namespace
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),
184 origin_(origin),
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 */,
206 data_dir_.path(),
207 io_task_runner_,
208 base::MessageLoopProxy::current(),
209 storage_policy);
211 file_system_context_ = new FileSystemContext(
212 make_scoped_ptr(new fileapi::FileSystemTaskRunners(
213 io_task_runner_,
214 file_task_runner_,
215 file_task_runner_)),
216 fileapi::ExternalMountPoints::CreateRefCounted().get(),
217 storage_policy,
218 quota_manager_->proxy(),
219 ScopedVector<fileapi::FileSystemMountPointProvider>(),
220 data_dir_.path(),
221 fileapi::CreateAllowFileAccessOptions());
223 // In testing we override this setting to support directory operations
224 // by default.
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_,
259 FROM_HERE,
260 base::Bind(
261 &CannedSyncableFileSystem::InitializeSyncStatusObserver,
262 base::Unretained(this)));
264 return result_;
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();
287 return sync_status_;
290 PlatformFileError CannedSyncableFileSystem::CreateDirectory(
291 const FileSystemURL& url) {
292 return RunOnThread<PlatformFileError>(
293 io_task_runner_,
294 FROM_HERE,
295 base::Bind(&CannedSyncableFileSystem::DoCreateDirectory,
296 base::Unretained(this), url));
299 PlatformFileError CannedSyncableFileSystem::CreateFile(
300 const FileSystemURL& url) {
301 return RunOnThread<PlatformFileError>(
302 io_task_runner_,
303 FROM_HERE,
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>(
311 io_task_runner_,
312 FROM_HERE,
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>(
320 io_task_runner_,
321 FROM_HERE,
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>(
329 io_task_runner_,
330 FROM_HERE,
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>(
340 io_task_runner_,
341 FROM_HERE,
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>(
350 io_task_runner_,
351 FROM_HERE,
352 base::Bind(&CannedSyncableFileSystem::DoRemove,
353 base::Unretained(this), url, recursive));
356 PlatformFileError CannedSyncableFileSystem::FileExists(
357 const FileSystemURL& url) {
358 return RunOnThread<PlatformFileError>(
359 io_task_runner_,
360 FROM_HERE,
361 base::Bind(&CannedSyncableFileSystem::DoFileExists,
362 base::Unretained(this), url));
365 PlatformFileError CannedSyncableFileSystem::DirectoryExists(
366 const FileSystemURL& url) {
367 return RunOnThread<PlatformFileError>(
368 io_task_runner_,
369 FROM_HERE,
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>(
378 io_task_runner_,
379 FROM_HERE,
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>(
389 io_task_runner_,
390 FROM_HERE,
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>(
399 io_task_runner_,
400 FROM_HERE,
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>(
408 io_task_runner_,
409 FROM_HERE,
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>(
417 io_task_runner_,
418 FROM_HERE,
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>(
426 io_task_runner_,
427 FROM_HERE,
428 base::Bind(&CannedSyncableFileSystem::DoGetUsageAndQuota,
429 base::Unretained(this), usage, quota));
432 void CannedSyncableFileSystem::GetChangedURLsInTracker(
433 FileSystemURLSet* urls) {
434 return RunOnThread(
435 file_task_runner_,
436 FROM_HERE,
437 base::Bind(&LocalFileChangeTracker::GetAllChangedURLs,
438 base::Unretained(file_system_context_->change_tracker()),
439 urls));
442 void CannedSyncableFileSystem::ClearChangeForURLInTracker(
443 const FileSystemURL& url) {
444 return RunOnThread(
445 file_task_runner_,
446 FROM_HERE,
447 base::Bind(&LocalFileChangeTracker::ClearChangesForURL,
448 base::Unretained(file_system_context_->change_tracker()),
449 url));
452 FileSystemOperation* CannedSyncableFileSystem::NewOperation() {
453 return file_system_context_->CreateFileSystemOperation(URL(std::string()),
454 NULL);
457 void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL& url) {
458 sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled,
459 url);
462 void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL& url) {
463 sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled,
464 url);
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(
579 int64* usage,
580 int64* quota,
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) {
589 result_ = result;
590 root_url_ = 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