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