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