canned_syncable_file_system.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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/test_file_system_options.h"
26#include "testing/gtest/include/gtest/gtest.h"
27#include "webkit/browser/fileapi/external_mount_points.h"
28#include "webkit/browser/fileapi/file_system_backend.h"
29#include "webkit/browser/fileapi/file_system_context.h"
30#include "webkit/browser/fileapi/file_system_operation_context.h"
31#include "webkit/browser/fileapi/file_system_operation_runner.h"
32#include "webkit/browser/quota/mock_special_storage_policy.h"
33#include "webkit/browser/quota/quota_manager.h"
34#include "webkit/common/blob/shareable_file_reference.h"
35
36using base::File;
37using fileapi::FileSystemContext;
38using fileapi::FileSystemOperationRunner;
39using fileapi::FileSystemURL;
40using fileapi::FileSystemURLSet;
41using quota::QuotaManager;
42using content::MockBlobURLRequestContext;
43using content::ScopedTextBlob;
44
45namespace sync_file_system {
46
47namespace {
48
49void Quit() { base::MessageLoop::current()->Quit(); }
50
51template <typename R>
52void 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
59template <typename R>
60R 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
74void 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
86void EnsureRunningOn(base::SingleThreadTaskRunner* runner) {
87  EXPECT_TRUE(runner->RunsTasksOnCurrentThread());
88}
89
90void 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
99void 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
118void 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
134void 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
148class 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
188void 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
197void 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
206CannedSyncableFileSystem::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
223CannedSyncableFileSystem::~CannedSyncableFileSystem() {}
224
225void 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 quota::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
263void 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
272FileSystemURL 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
280File::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
303void CannedSyncableFileSystem::AddSyncStatusObserver(
304    LocalFileSyncStatus::Observer* observer) {
305  sync_status_observers_->AddObserver(observer);
306}
307
308void CannedSyncableFileSystem::RemoveSyncStatusObserver(
309    LocalFileSyncStatus::Observer* observer) {
310  sync_status_observers_->RemoveObserver(observer);
311}
312
313SyncStatusCode 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
328File::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
338File::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
347File::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
358File::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
369File::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
380File::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
394File::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
405File::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
415File::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
425File::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
437File::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
451File::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
463int64 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
476int64 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
486File::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
497quota::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
508void 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
518void 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
528void 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
539SyncFileSystemBackend* CannedSyncableFileSystem::backend() {
540  return SyncFileSystemBackend::GetBackend(file_system_context_);
541}
542
543FileSystemOperationRunner* CannedSyncableFileSystem::operation_runner() {
544  return file_system_context_->operation_runner();
545}
546
547void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL& url) {
548  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled,
549                                 url);
550}
551
552void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL& url) {
553  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled,
554                                 url);
555}
556
557void 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
567void 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
576void 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
584void 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
596void 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
606void 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
614void 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
625void 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
633void 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
640void 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
647void 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
658void 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
669void 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
679void 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
693void 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
708void 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
720void 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
744void CannedSyncableFileSystem::DidInitializeFileSystemContext(
745    SyncStatusCode status) {
746  sync_status_ = status;
747  base::MessageLoop::current()->Quit();
748}
749
750void 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