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