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 "chrome/browser/sync_file_system/local/canned_syncable_file_system.h" 6 7 #include <iterator> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/file_util.h" 12 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/run_loop.h" 14 #include "base/single_thread_task_runner.h" 15 #include "base/task_runner_util.h" 16 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h" 17 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h" 18 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" 19 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "webkit/browser/blob/mock_blob_url_request_context.h" 22 #include "webkit/browser/fileapi/external_mount_points.h" 23 #include "webkit/browser/fileapi/file_system_backend.h" 24 #include "webkit/browser/fileapi/file_system_context.h" 25 #include "webkit/browser/fileapi/file_system_operation_context.h" 26 #include "webkit/browser/fileapi/file_system_operation_runner.h" 27 #include "webkit/browser/fileapi/mock_file_system_options.h" 28 #include "webkit/browser/fileapi/sandbox_file_system_backend.h" 29 #include "webkit/browser/quota/mock_special_storage_policy.h" 30 #include "webkit/browser/quota/quota_manager.h" 31 #include "webkit/common/blob/shareable_file_reference.h" 32 33 using base::PlatformFileError; 34 using fileapi::FileSystemContext; 35 using fileapi::FileSystemOperationRunner; 36 using fileapi::FileSystemURL; 37 using fileapi::FileSystemURLSet; 38 using quota::QuotaManager; 39 using webkit_blob::MockBlobURLRequestContext; 40 using webkit_blob::ScopedTextBlob; 41 42 namespace sync_file_system { 43 44 namespace { 45 46 void Quit() { base::MessageLoop::current()->Quit(); } 47 48 template <typename R> 49 void AssignAndQuit(base::TaskRunner* original_task_runner, 50 R* result_out, R result) { 51 DCHECK(result_out); 52 *result_out = result; 53 original_task_runner->PostTask(FROM_HERE, base::Bind(&Quit)); 54 } 55 56 template <typename R> 57 R RunOnThread( 58 base::SingleThreadTaskRunner* task_runner, 59 const tracked_objects::Location& location, 60 const base::Callback<void(const base::Callback<void(R)>& callback)>& task) { 61 R result; 62 task_runner->PostTask( 63 location, 64 base::Bind(task, base::Bind(&AssignAndQuit<R>, 65 base::MessageLoopProxy::current(), 66 &result))); 67 base::MessageLoop::current()->Run(); 68 return result; 69 } 70 71 void RunOnThread(base::SingleThreadTaskRunner* task_runner, 72 const tracked_objects::Location& location, 73 const base::Closure& task) { 74 task_runner->PostTaskAndReply( 75 location, task, 76 base::Bind(base::IgnoreResult( 77 base::Bind(&base::MessageLoopProxy::PostTask, 78 base::MessageLoopProxy::current(), 79 FROM_HERE, base::Bind(&Quit))))); 80 base::MessageLoop::current()->Run(); 81 } 82 83 void EnsureRunningOn(base::SingleThreadTaskRunner* runner) { 84 EXPECT_TRUE(runner->RunsTasksOnCurrentThread()); 85 } 86 87 void VerifySameTaskRunner( 88 base::SingleThreadTaskRunner* runner1, 89 base::SingleThreadTaskRunner* runner2) { 90 ASSERT_TRUE(runner1 != NULL); 91 ASSERT_TRUE(runner2 != NULL); 92 runner1->PostTask(FROM_HERE, 93 base::Bind(&EnsureRunningOn, make_scoped_refptr(runner2))); 94 } 95 96 void OnCreateSnapshotFileAndVerifyData( 97 const std::string& expected_data, 98 const CannedSyncableFileSystem::StatusCallback& callback, 99 base::PlatformFileError result, 100 const base::PlatformFileInfo& file_info, 101 const base::FilePath& platform_path, 102 const scoped_refptr<webkit_blob::ShareableFileReference>& /* file_ref */) { 103 if (result != base::PLATFORM_FILE_OK) { 104 callback.Run(result); 105 return; 106 } 107 EXPECT_EQ(expected_data.size(), static_cast<size_t>(file_info.size)); 108 std::string data; 109 const bool read_status = file_util::ReadFileToString(platform_path, &data); 110 EXPECT_TRUE(read_status); 111 EXPECT_EQ(expected_data, data); 112 callback.Run(result); 113 } 114 115 void OnCreateSnapshotFile( 116 base::PlatformFileInfo* file_info_out, 117 base::FilePath* platform_path_out, 118 const CannedSyncableFileSystem::StatusCallback& callback, 119 base::PlatformFileError result, 120 const base::PlatformFileInfo& file_info, 121 const base::FilePath& platform_path, 122 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { 123 DCHECK(!file_ref.get()); 124 DCHECK(file_info_out); 125 DCHECK(platform_path_out); 126 *file_info_out = file_info; 127 *platform_path_out = platform_path; 128 callback.Run(result); 129 } 130 131 void OnReadDirectory( 132 CannedSyncableFileSystem::FileEntryList* entries_out, 133 const CannedSyncableFileSystem::StatusCallback& callback, 134 base::PlatformFileError error, 135 const fileapi::FileSystemOperation::FileEntryList& entries, 136 bool has_more) { 137 DCHECK(entries_out); 138 entries_out->reserve(entries_out->size() + entries.size()); 139 std::copy(entries.begin(), entries.end(), std::back_inserter(*entries_out)); 140 141 if (!has_more) 142 callback.Run(error); 143 } 144 145 class WriteHelper { 146 public: 147 WriteHelper() : bytes_written_(0) {} 148 WriteHelper(MockBlobURLRequestContext* request_context, 149 const GURL& blob_url, 150 const std::string& blob_data) 151 : bytes_written_(0), 152 request_context_(request_context), 153 blob_data_(new ScopedTextBlob(*request_context, blob_url, blob_data)) {} 154 155 ~WriteHelper() { 156 if (request_context_) { 157 base::MessageLoop::current()->DeleteSoon(FROM_HERE, 158 request_context_.release()); 159 } 160 } 161 162 void DidWrite(const base::Callback<void(int64 result)>& completion_callback, 163 PlatformFileError error, int64 bytes, bool complete) { 164 if (error == base::PLATFORM_FILE_OK) { 165 bytes_written_ += bytes; 166 if (!complete) 167 return; 168 } 169 completion_callback.Run(error == base::PLATFORM_FILE_OK 170 ? bytes_written_ : static_cast<int64>(error)); 171 } 172 173 private: 174 int64 bytes_written_; 175 scoped_ptr<MockBlobURLRequestContext> request_context_; 176 scoped_ptr<ScopedTextBlob> blob_data_; 177 178 DISALLOW_COPY_AND_ASSIGN(WriteHelper); 179 }; 180 181 void DidGetUsageAndQuota(const quota::StatusCallback& callback, 182 int64* usage_out, int64* quota_out, 183 quota::QuotaStatusCode status, 184 int64 usage, int64 quota) { 185 *usage_out = usage; 186 *quota_out = quota; 187 callback.Run(status); 188 } 189 190 void EnsureLastTaskRuns(base::SingleThreadTaskRunner* runner) { 191 base::RunLoop run_loop; 192 runner->PostTaskAndReply( 193 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure()); 194 run_loop.Run(); 195 } 196 197 } // namespace 198 199 CannedSyncableFileSystem::CannedSyncableFileSystem( 200 const GURL& origin, 201 base::SingleThreadTaskRunner* io_task_runner, 202 base::SingleThreadTaskRunner* file_task_runner) 203 : origin_(origin), 204 type_(fileapi::kFileSystemTypeSyncable), 205 result_(base::PLATFORM_FILE_OK), 206 sync_status_(sync_file_system::SYNC_STATUS_OK), 207 io_task_runner_(io_task_runner), 208 file_task_runner_(file_task_runner), 209 is_filesystem_set_up_(false), 210 is_filesystem_opened_(false), 211 sync_status_observers_(new ObserverList) { 212 } 213 214 CannedSyncableFileSystem::~CannedSyncableFileSystem() {} 215 216 void CannedSyncableFileSystem::SetUp() { 217 ASSERT_FALSE(is_filesystem_set_up_); 218 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 219 220 scoped_refptr<quota::SpecialStoragePolicy> storage_policy = 221 new quota::MockSpecialStoragePolicy(); 222 223 quota_manager_ = new QuotaManager(false /* is_incognito */, 224 data_dir_.path(), 225 io_task_runner_.get(), 226 base::MessageLoopProxy::current().get(), 227 storage_policy.get()); 228 229 std::vector<std::string> additional_allowed_schemes; 230 additional_allowed_schemes.push_back(origin_.scheme()); 231 fileapi::FileSystemOptions options( 232 fileapi::FileSystemOptions::PROFILE_MODE_NORMAL, 233 additional_allowed_schemes); 234 235 ScopedVector<fileapi::FileSystemBackend> additional_backends; 236 additional_backends.push_back(new SyncFileSystemBackend()); 237 238 file_system_context_ = new FileSystemContext( 239 io_task_runner_.get(), 240 file_task_runner_.get(), 241 fileapi::ExternalMountPoints::CreateRefCounted().get(), 242 storage_policy.get(), 243 quota_manager_->proxy(), 244 additional_backends.Pass(), 245 data_dir_.path(), options); 246 247 is_filesystem_set_up_ = true; 248 } 249 250 void CannedSyncableFileSystem::TearDown() { 251 quota_manager_ = NULL; 252 file_system_context_ = NULL; 253 254 // Make sure we give some more time to finish tasks on other threads. 255 EnsureLastTaskRuns(io_task_runner_.get()); 256 EnsureLastTaskRuns(file_task_runner_.get()); 257 } 258 259 FileSystemURL CannedSyncableFileSystem::URL(const std::string& path) const { 260 EXPECT_TRUE(is_filesystem_set_up_); 261 EXPECT_TRUE(is_filesystem_opened_); 262 263 GURL url(root_url_.spec() + path); 264 return file_system_context_->CrackURL(url); 265 } 266 267 PlatformFileError CannedSyncableFileSystem::OpenFileSystem() { 268 EXPECT_TRUE(is_filesystem_set_up_); 269 EXPECT_FALSE(is_filesystem_opened_); 270 file_system_context_->OpenFileSystem( 271 origin_, type_, 272 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 273 base::Bind(&CannedSyncableFileSystem::DidOpenFileSystem, 274 base::Unretained(this))); 275 base::MessageLoop::current()->Run(); 276 if (backend()->sync_context()) { 277 // Register 'this' as a sync status observer. 278 RunOnThread( 279 io_task_runner_.get(), 280 FROM_HERE, 281 base::Bind(&CannedSyncableFileSystem::InitializeSyncStatusObserver, 282 base::Unretained(this))); 283 } 284 return result_; 285 } 286 287 void CannedSyncableFileSystem::AddSyncStatusObserver( 288 LocalFileSyncStatus::Observer* observer) { 289 sync_status_observers_->AddObserver(observer); 290 } 291 292 void CannedSyncableFileSystem::RemoveSyncStatusObserver( 293 LocalFileSyncStatus::Observer* observer) { 294 sync_status_observers_->RemoveObserver(observer); 295 } 296 297 SyncStatusCode CannedSyncableFileSystem::MaybeInitializeFileSystemContext( 298 LocalFileSyncContext* sync_context) { 299 DCHECK(sync_context); 300 sync_status_ = sync_file_system::SYNC_STATUS_UNKNOWN; 301 VerifySameTaskRunner(io_task_runner_.get(), 302 sync_context->io_task_runner_.get()); 303 sync_context->MaybeInitializeFileSystemContext( 304 origin_, 305 file_system_context_.get(), 306 base::Bind(&CannedSyncableFileSystem::DidInitializeFileSystemContext, 307 base::Unretained(this))); 308 base::MessageLoop::current()->Run(); 309 return sync_status_; 310 } 311 312 PlatformFileError CannedSyncableFileSystem::CreateDirectory( 313 const FileSystemURL& url) { 314 return RunOnThread<PlatformFileError>( 315 io_task_runner_.get(), 316 FROM_HERE, 317 base::Bind(&CannedSyncableFileSystem::DoCreateDirectory, 318 base::Unretained(this), 319 url)); 320 } 321 322 PlatformFileError CannedSyncableFileSystem::CreateFile( 323 const FileSystemURL& url) { 324 return RunOnThread<PlatformFileError>( 325 io_task_runner_.get(), 326 FROM_HERE, 327 base::Bind(&CannedSyncableFileSystem::DoCreateFile, 328 base::Unretained(this), 329 url)); 330 } 331 332 PlatformFileError CannedSyncableFileSystem::Copy( 333 const FileSystemURL& src_url, const FileSystemURL& dest_url) { 334 return RunOnThread<PlatformFileError>( 335 io_task_runner_.get(), 336 FROM_HERE, 337 base::Bind(&CannedSyncableFileSystem::DoCopy, 338 base::Unretained(this), 339 src_url, 340 dest_url)); 341 } 342 343 PlatformFileError CannedSyncableFileSystem::Move( 344 const FileSystemURL& src_url, const FileSystemURL& dest_url) { 345 return RunOnThread<PlatformFileError>( 346 io_task_runner_.get(), 347 FROM_HERE, 348 base::Bind(&CannedSyncableFileSystem::DoMove, 349 base::Unretained(this), 350 src_url, 351 dest_url)); 352 } 353 354 PlatformFileError CannedSyncableFileSystem::TruncateFile( 355 const FileSystemURL& url, int64 size) { 356 return RunOnThread<PlatformFileError>( 357 io_task_runner_.get(), 358 FROM_HERE, 359 base::Bind(&CannedSyncableFileSystem::DoTruncateFile, 360 base::Unretained(this), 361 url, 362 size)); 363 } 364 365 PlatformFileError CannedSyncableFileSystem::TouchFile( 366 const FileSystemURL& url, 367 const base::Time& last_access_time, 368 const base::Time& last_modified_time) { 369 return RunOnThread<PlatformFileError>( 370 io_task_runner_.get(), 371 FROM_HERE, 372 base::Bind(&CannedSyncableFileSystem::DoTouchFile, 373 base::Unretained(this), 374 url, 375 last_access_time, 376 last_modified_time)); 377 } 378 379 PlatformFileError CannedSyncableFileSystem::Remove( 380 const FileSystemURL& url, bool recursive) { 381 return RunOnThread<PlatformFileError>( 382 io_task_runner_.get(), 383 FROM_HERE, 384 base::Bind(&CannedSyncableFileSystem::DoRemove, 385 base::Unretained(this), 386 url, 387 recursive)); 388 } 389 390 PlatformFileError CannedSyncableFileSystem::FileExists( 391 const FileSystemURL& url) { 392 return RunOnThread<PlatformFileError>( 393 io_task_runner_.get(), 394 FROM_HERE, 395 base::Bind(&CannedSyncableFileSystem::DoFileExists, 396 base::Unretained(this), 397 url)); 398 } 399 400 PlatformFileError CannedSyncableFileSystem::DirectoryExists( 401 const FileSystemURL& url) { 402 return RunOnThread<PlatformFileError>( 403 io_task_runner_.get(), 404 FROM_HERE, 405 base::Bind(&CannedSyncableFileSystem::DoDirectoryExists, 406 base::Unretained(this), 407 url)); 408 } 409 410 PlatformFileError CannedSyncableFileSystem::VerifyFile( 411 const FileSystemURL& url, 412 const std::string& expected_data) { 413 return RunOnThread<PlatformFileError>( 414 io_task_runner_.get(), 415 FROM_HERE, 416 base::Bind(&CannedSyncableFileSystem::DoVerifyFile, 417 base::Unretained(this), 418 url, 419 expected_data)); 420 } 421 422 PlatformFileError CannedSyncableFileSystem::GetMetadataAndPlatformPath( 423 const FileSystemURL& url, 424 base::PlatformFileInfo* info, 425 base::FilePath* platform_path) { 426 return RunOnThread<PlatformFileError>( 427 io_task_runner_.get(), 428 FROM_HERE, 429 base::Bind(&CannedSyncableFileSystem::DoGetMetadataAndPlatformPath, 430 base::Unretained(this), 431 url, 432 info, 433 platform_path)); 434 } 435 436 PlatformFileError CannedSyncableFileSystem::ReadDirectory( 437 const fileapi::FileSystemURL& url, 438 FileEntryList* entries) { 439 return RunOnThread<PlatformFileError>( 440 io_task_runner_.get(), 441 FROM_HERE, 442 base::Bind(&CannedSyncableFileSystem::DoReadDirectory, 443 base::Unretained(this), 444 url, 445 entries)); 446 } 447 448 int64 CannedSyncableFileSystem::Write( 449 net::URLRequestContext* url_request_context, 450 const FileSystemURL& url, const GURL& blob_url) { 451 return RunOnThread<int64>(io_task_runner_.get(), 452 FROM_HERE, 453 base::Bind(&CannedSyncableFileSystem::DoWrite, 454 base::Unretained(this), 455 url_request_context, 456 url, 457 blob_url)); 458 } 459 460 int64 CannedSyncableFileSystem::WriteString( 461 const FileSystemURL& url, const std::string& data) { 462 return RunOnThread<int64>(io_task_runner_.get(), 463 FROM_HERE, 464 base::Bind(&CannedSyncableFileSystem::DoWriteString, 465 base::Unretained(this), 466 url, 467 data)); 468 } 469 470 PlatformFileError CannedSyncableFileSystem::DeleteFileSystem() { 471 EXPECT_TRUE(is_filesystem_set_up_); 472 return RunOnThread<PlatformFileError>( 473 io_task_runner_.get(), 474 FROM_HERE, 475 base::Bind(&FileSystemContext::DeleteFileSystem, 476 file_system_context_, 477 origin_, 478 type_)); 479 } 480 481 quota::QuotaStatusCode CannedSyncableFileSystem::GetUsageAndQuota( 482 int64* usage, int64* quota) { 483 return RunOnThread<quota::QuotaStatusCode>( 484 io_task_runner_.get(), 485 FROM_HERE, 486 base::Bind(&CannedSyncableFileSystem::DoGetUsageAndQuota, 487 base::Unretained(this), 488 usage, 489 quota)); 490 } 491 492 void CannedSyncableFileSystem::GetChangedURLsInTracker( 493 FileSystemURLSet* urls) { 494 return RunOnThread( 495 file_task_runner_.get(), 496 FROM_HERE, 497 base::Bind(&LocalFileChangeTracker::GetAllChangedURLs, 498 base::Unretained(backend()->change_tracker()), 499 urls)); 500 } 501 502 void CannedSyncableFileSystem::ClearChangeForURLInTracker( 503 const FileSystemURL& url) { 504 return RunOnThread( 505 file_task_runner_.get(), 506 FROM_HERE, 507 base::Bind(&LocalFileChangeTracker::ClearChangesForURL, 508 base::Unretained(backend()->change_tracker()), 509 url)); 510 } 511 512 SyncFileSystemBackend* CannedSyncableFileSystem::backend() { 513 return SyncFileSystemBackend::GetBackend(file_system_context_); 514 } 515 516 FileSystemOperationRunner* CannedSyncableFileSystem::operation_runner() { 517 return file_system_context_->operation_runner(); 518 } 519 520 void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL& url) { 521 sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled, 522 url); 523 } 524 525 void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL& url) { 526 sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled, 527 url); 528 } 529 530 void CannedSyncableFileSystem::DoCreateDirectory( 531 const FileSystemURL& url, 532 const StatusCallback& callback) { 533 EXPECT_TRUE(is_filesystem_opened_); 534 operation_runner()->CreateDirectory( 535 url, false /* exclusive */, false /* recursive */, callback); 536 } 537 538 void CannedSyncableFileSystem::DoCreateFile( 539 const FileSystemURL& url, 540 const StatusCallback& callback) { 541 EXPECT_TRUE(is_filesystem_opened_); 542 operation_runner()->CreateFile(url, false /* exclusive */, callback); 543 } 544 545 void CannedSyncableFileSystem::DoCopy( 546 const FileSystemURL& src_url, 547 const FileSystemURL& dest_url, 548 const StatusCallback& callback) { 549 EXPECT_TRUE(is_filesystem_opened_); 550 operation_runner()->Copy(src_url, dest_url, callback); 551 } 552 553 void CannedSyncableFileSystem::DoMove( 554 const FileSystemURL& src_url, 555 const FileSystemURL& dest_url, 556 const StatusCallback& callback) { 557 EXPECT_TRUE(is_filesystem_opened_); 558 operation_runner()->Move(src_url, dest_url, callback); 559 } 560 561 void CannedSyncableFileSystem::DoTruncateFile( 562 const FileSystemURL& url, int64 size, 563 const StatusCallback& callback) { 564 EXPECT_TRUE(is_filesystem_opened_); 565 operation_runner()->Truncate(url, size, callback); 566 } 567 568 void CannedSyncableFileSystem::DoTouchFile( 569 const FileSystemURL& url, 570 const base::Time& last_access_time, 571 const base::Time& last_modified_time, 572 const StatusCallback& callback) { 573 EXPECT_TRUE(is_filesystem_opened_); 574 operation_runner()->TouchFile(url, last_access_time, 575 last_modified_time, callback); 576 } 577 578 void CannedSyncableFileSystem::DoRemove( 579 const FileSystemURL& url, bool recursive, 580 const StatusCallback& callback) { 581 EXPECT_TRUE(is_filesystem_opened_); 582 operation_runner()->Remove(url, recursive, callback); 583 } 584 585 void CannedSyncableFileSystem::DoFileExists( 586 const FileSystemURL& url, const StatusCallback& callback) { 587 EXPECT_TRUE(is_filesystem_opened_); 588 operation_runner()->FileExists(url, callback); 589 } 590 591 void CannedSyncableFileSystem::DoDirectoryExists( 592 const FileSystemURL& url, const StatusCallback& callback) { 593 EXPECT_TRUE(is_filesystem_opened_); 594 operation_runner()->DirectoryExists(url, callback); 595 } 596 597 void CannedSyncableFileSystem::DoVerifyFile( 598 const FileSystemURL& url, 599 const std::string& expected_data, 600 const StatusCallback& callback) { 601 EXPECT_TRUE(is_filesystem_opened_); 602 operation_runner()->CreateSnapshotFile( 603 url, 604 base::Bind(&OnCreateSnapshotFileAndVerifyData,expected_data, callback)); 605 } 606 607 void CannedSyncableFileSystem::DoGetMetadataAndPlatformPath( 608 const FileSystemURL& url, 609 base::PlatformFileInfo* info, 610 base::FilePath* platform_path, 611 const StatusCallback& callback) { 612 EXPECT_TRUE(is_filesystem_opened_); 613 operation_runner()->CreateSnapshotFile( 614 url, base::Bind(&OnCreateSnapshotFile, info, platform_path, callback)); 615 } 616 617 void CannedSyncableFileSystem::DoReadDirectory( 618 const FileSystemURL& url, 619 FileEntryList* entries, 620 const StatusCallback& callback) { 621 EXPECT_TRUE(is_filesystem_opened_); 622 operation_runner()->ReadDirectory( 623 url, base::Bind(&OnReadDirectory, entries, callback)); 624 } 625 626 void CannedSyncableFileSystem::DoWrite( 627 net::URLRequestContext* url_request_context, 628 const FileSystemURL& url, const GURL& blob_url, 629 const WriteCallback& callback) { 630 EXPECT_TRUE(is_filesystem_opened_); 631 WriteHelper* helper = new WriteHelper; 632 operation_runner()->Write(url_request_context, url, blob_url, 0, 633 base::Bind(&WriteHelper::DidWrite, 634 base::Owned(helper), callback)); 635 } 636 637 void CannedSyncableFileSystem::DoWriteString( 638 const FileSystemURL& url, 639 const std::string& data, 640 const WriteCallback& callback) { 641 MockBlobURLRequestContext* url_request_context( 642 new MockBlobURLRequestContext(file_system_context_.get())); 643 const GURL blob_url(std::string("blob:") + data); 644 WriteHelper* helper = new WriteHelper(url_request_context, blob_url, data); 645 operation_runner()->Write(url_request_context, url, blob_url, 0, 646 base::Bind(&WriteHelper::DidWrite, 647 base::Owned(helper), callback)); 648 } 649 650 void CannedSyncableFileSystem::DoGetUsageAndQuota( 651 int64* usage, 652 int64* quota, 653 const quota::StatusCallback& callback) { 654 quota_manager_->GetUsageAndQuota( 655 origin_, storage_type(), 656 base::Bind(&DidGetUsageAndQuota, callback, usage, quota)); 657 } 658 659 void CannedSyncableFileSystem::DidOpenFileSystem( 660 PlatformFileError result, const std::string& name, const GURL& root) { 661 result_ = result; 662 root_url_ = root; 663 is_filesystem_opened_ = true; 664 base::MessageLoop::current()->Quit(); 665 } 666 667 void CannedSyncableFileSystem::DidInitializeFileSystemContext( 668 SyncStatusCode status) { 669 sync_status_ = status; 670 base::MessageLoop::current()->Quit(); 671 } 672 673 void CannedSyncableFileSystem::InitializeSyncStatusObserver() { 674 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread()); 675 backend()->sync_context()->sync_status()->AddObserver(this); 676 } 677 678 } // namespace sync_file_system 679