canned_syncable_file_system.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/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 "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
36using base::File;
37using storage::FileSystemContext;
38using storage::FileSystemOperationRunner;
39using storage::FileSystemURL;
40using storage::FileSystemURLSet;
41using storage::QuotaManager;
42using content::MockBlobURLRequestContext;
43using content::ScopedTextBlob;
44
45namespace sync_file_system {
46
47namespace {
48
49template <typename R>
50void 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
58template <typename R>
59R 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
75void 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
88void EnsureRunningOn(base::SingleThreadTaskRunner* runner) {
89  EXPECT_TRUE(runner->RunsTasksOnCurrentThread());
90}
91
92void 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
101void 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
120void 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
136void 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
149class 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
189void 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
200void 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
209CannedSyncableFileSystem::CannedSyncableFileSystem(
210    const GURL& origin,
211    leveldb::Env* env_override,
212    base::SingleThreadTaskRunner* io_task_runner,
213    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
226CannedSyncableFileSystem::~CannedSyncableFileSystem() {}
227
228void 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_,
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_,
255      file_task_runner_,
256      storage::ExternalMountPoints::CreateRefCounted().get(),
257      storage_policy.get(),
258      quota_manager_ ? 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
267void 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_);
273  EnsureLastTaskRuns(file_task_runner_);
274}
275
276FileSystemURL 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
284File::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_,
302        FROM_HERE,
303        base::Bind(&CannedSyncableFileSystem::InitializeSyncStatusObserver,
304                   base::Unretained(this)));
305  }
306  return result_;
307}
308
309void CannedSyncableFileSystem::AddSyncStatusObserver(
310    LocalFileSyncStatus::Observer* observer) {
311  sync_status_observers_->AddObserver(observer);
312}
313
314void CannedSyncableFileSystem::RemoveSyncStatusObserver(
315    LocalFileSyncStatus::Observer* observer) {
316  sync_status_observers_->RemoveObserver(observer);
317}
318
319SyncStatusCode 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_,
325                       sync_context->io_task_runner_);
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
336File::Error CannedSyncableFileSystem::CreateDirectory(
337    const FileSystemURL& url) {
338  return RunOnThread<File::Error>(
339      io_task_runner_,
340      FROM_HERE,
341      base::Bind(&CannedSyncableFileSystem::DoCreateDirectory,
342                 base::Unretained(this),
343                 url));
344}
345
346File::Error CannedSyncableFileSystem::CreateFile(const FileSystemURL& url) {
347  return RunOnThread<File::Error>(
348      io_task_runner_,
349      FROM_HERE,
350      base::Bind(&CannedSyncableFileSystem::DoCreateFile,
351                 base::Unretained(this),
352                 url));
353}
354
355File::Error CannedSyncableFileSystem::Copy(
356    const FileSystemURL& src_url, const FileSystemURL& dest_url) {
357  return RunOnThread<File::Error>(
358      io_task_runner_,
359      FROM_HERE,
360      base::Bind(&CannedSyncableFileSystem::DoCopy,
361                 base::Unretained(this),
362                 src_url,
363                 dest_url));
364}
365
366File::Error CannedSyncableFileSystem::Move(
367    const FileSystemURL& src_url, const FileSystemURL& dest_url) {
368  return RunOnThread<File::Error>(
369      io_task_runner_,
370      FROM_HERE,
371      base::Bind(&CannedSyncableFileSystem::DoMove,
372                 base::Unretained(this),
373                 src_url,
374                 dest_url));
375}
376
377File::Error CannedSyncableFileSystem::TruncateFile(
378    const FileSystemURL& url, int64 size) {
379  return RunOnThread<File::Error>(
380      io_task_runner_,
381      FROM_HERE,
382      base::Bind(&CannedSyncableFileSystem::DoTruncateFile,
383                 base::Unretained(this),
384                 url,
385                 size));
386}
387
388File::Error CannedSyncableFileSystem::TouchFile(
389    const FileSystemURL& url,
390    const base::Time& last_access_time,
391    const base::Time& last_modified_time) {
392  return RunOnThread<File::Error>(
393      io_task_runner_,
394      FROM_HERE,
395      base::Bind(&CannedSyncableFileSystem::DoTouchFile,
396                 base::Unretained(this),
397                 url,
398                 last_access_time,
399                 last_modified_time));
400}
401
402File::Error CannedSyncableFileSystem::Remove(
403    const FileSystemURL& url, bool recursive) {
404  return RunOnThread<File::Error>(
405      io_task_runner_,
406      FROM_HERE,
407      base::Bind(&CannedSyncableFileSystem::DoRemove,
408                 base::Unretained(this),
409                 url,
410                 recursive));
411}
412
413File::Error CannedSyncableFileSystem::FileExists(
414    const FileSystemURL& url) {
415  return RunOnThread<File::Error>(
416      io_task_runner_,
417      FROM_HERE,
418      base::Bind(&CannedSyncableFileSystem::DoFileExists,
419                 base::Unretained(this),
420                 url));
421}
422
423File::Error CannedSyncableFileSystem::DirectoryExists(
424    const FileSystemURL& url) {
425  return RunOnThread<File::Error>(
426      io_task_runner_,
427      FROM_HERE,
428      base::Bind(&CannedSyncableFileSystem::DoDirectoryExists,
429                 base::Unretained(this),
430                 url));
431}
432
433File::Error CannedSyncableFileSystem::VerifyFile(
434    const FileSystemURL& url,
435    const std::string& expected_data) {
436  return RunOnThread<File::Error>(
437      io_task_runner_,
438      FROM_HERE,
439      base::Bind(&CannedSyncableFileSystem::DoVerifyFile,
440                 base::Unretained(this),
441                 url,
442                 expected_data));
443}
444
445File::Error CannedSyncableFileSystem::GetMetadataAndPlatformPath(
446    const FileSystemURL& url,
447    base::File::Info* info,
448    base::FilePath* platform_path) {
449  return RunOnThread<File::Error>(
450      io_task_runner_,
451      FROM_HERE,
452      base::Bind(&CannedSyncableFileSystem::DoGetMetadataAndPlatformPath,
453                 base::Unretained(this),
454                 url,
455                 info,
456                 platform_path));
457}
458
459File::Error CannedSyncableFileSystem::ReadDirectory(
460    const storage::FileSystemURL& url,
461    FileEntryList* entries) {
462  return RunOnThread<File::Error>(
463      io_task_runner_,
464      FROM_HERE,
465      base::Bind(&CannedSyncableFileSystem::DoReadDirectory,
466          base::Unretained(this),
467          url,
468          entries));
469}
470
471int64 CannedSyncableFileSystem::Write(
472    net::URLRequestContext* url_request_context,
473    const FileSystemURL& url,
474    scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
475  return RunOnThread<int64>(io_task_runner_,
476                            FROM_HERE,
477                            base::Bind(&CannedSyncableFileSystem::DoWrite,
478                                       base::Unretained(this),
479                                       url_request_context,
480                                       url,
481                                       base::Passed(&blob_data_handle)));
482}
483
484int64 CannedSyncableFileSystem::WriteString(
485    const FileSystemURL& url, const std::string& data) {
486  return RunOnThread<int64>(io_task_runner_,
487                            FROM_HERE,
488                            base::Bind(&CannedSyncableFileSystem::DoWriteString,
489                                       base::Unretained(this),
490                                       url,
491                                       data));
492}
493
494File::Error CannedSyncableFileSystem::DeleteFileSystem() {
495  EXPECT_TRUE(is_filesystem_set_up_);
496  return RunOnThread<File::Error>(
497      io_task_runner_,
498      FROM_HERE,
499      base::Bind(&FileSystemContext::DeleteFileSystem,
500                 file_system_context_,
501                 origin_,
502                 type_));
503}
504
505storage::QuotaStatusCode CannedSyncableFileSystem::GetUsageAndQuota(
506    int64* usage,
507    int64* quota) {
508  return RunOnThread<storage::QuotaStatusCode>(
509      io_task_runner_,
510      FROM_HERE,
511      base::Bind(&CannedSyncableFileSystem::DoGetUsageAndQuota,
512                 base::Unretained(this),
513                 usage,
514                 quota));
515}
516
517void CannedSyncableFileSystem::GetChangedURLsInTracker(
518    FileSystemURLSet* urls) {
519  RunOnThread(
520      file_task_runner_,
521      FROM_HERE,
522      base::Bind(&LocalFileChangeTracker::GetAllChangedURLs,
523                 base::Unretained(backend()->change_tracker()),
524                 urls));
525}
526
527void CannedSyncableFileSystem::ClearChangeForURLInTracker(
528    const FileSystemURL& url) {
529  RunOnThread(
530      file_task_runner_,
531      FROM_HERE,
532      base::Bind(&LocalFileChangeTracker::ClearChangesForURL,
533                 base::Unretained(backend()->change_tracker()),
534                 url));
535}
536
537void CannedSyncableFileSystem::GetChangesForURLInTracker(
538    const FileSystemURL& url,
539    FileChangeList* changes) {
540  RunOnThread(
541      file_task_runner_,
542      FROM_HERE,
543      base::Bind(&LocalFileChangeTracker::GetChangesForURL,
544                 base::Unretained(backend()->change_tracker()),
545                 url, changes));
546}
547
548SyncFileSystemBackend* CannedSyncableFileSystem::backend() {
549  return SyncFileSystemBackend::GetBackend(file_system_context_);
550}
551
552FileSystemOperationRunner* CannedSyncableFileSystem::operation_runner() {
553  return file_system_context_->operation_runner();
554}
555
556void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL& url) {
557  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled,
558                                 url);
559}
560
561void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL& url) {
562  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled,
563                                 url);
564}
565
566void CannedSyncableFileSystem::DoOpenFileSystem(
567    const OpenFileSystemCallback& callback) {
568  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
569  EXPECT_FALSE(is_filesystem_opened_);
570  file_system_context_->OpenFileSystem(
571      origin_,
572      type_,
573      storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
574      callback);
575}
576
577void CannedSyncableFileSystem::DoCreateDirectory(
578    const FileSystemURL& url,
579    const StatusCallback& callback) {
580  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
581  EXPECT_TRUE(is_filesystem_opened_);
582  operation_runner()->CreateDirectory(
583      url, false /* exclusive */, false /* recursive */, callback);
584}
585
586void CannedSyncableFileSystem::DoCreateFile(
587    const FileSystemURL& url,
588    const StatusCallback& callback) {
589  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
590  EXPECT_TRUE(is_filesystem_opened_);
591  operation_runner()->CreateFile(url, false /* exclusive */, callback);
592}
593
594void CannedSyncableFileSystem::DoCopy(
595    const FileSystemURL& src_url,
596    const FileSystemURL& dest_url,
597    const StatusCallback& callback) {
598  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
599  EXPECT_TRUE(is_filesystem_opened_);
600  operation_runner()->Copy(
601      src_url,
602      dest_url,
603      storage::FileSystemOperation::OPTION_NONE,
604      storage::FileSystemOperationRunner::CopyProgressCallback(),
605      callback);
606}
607
608void CannedSyncableFileSystem::DoMove(
609    const FileSystemURL& src_url,
610    const FileSystemURL& dest_url,
611    const StatusCallback& callback) {
612  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
613  EXPECT_TRUE(is_filesystem_opened_);
614  operation_runner()->Move(
615      src_url, dest_url, storage::FileSystemOperation::OPTION_NONE, callback);
616}
617
618void CannedSyncableFileSystem::DoTruncateFile(
619    const FileSystemURL& url, int64 size,
620    const StatusCallback& callback) {
621  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
622  EXPECT_TRUE(is_filesystem_opened_);
623  operation_runner()->Truncate(url, size, callback);
624}
625
626void CannedSyncableFileSystem::DoTouchFile(
627    const FileSystemURL& url,
628    const base::Time& last_access_time,
629    const base::Time& last_modified_time,
630    const StatusCallback& callback) {
631  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
632  EXPECT_TRUE(is_filesystem_opened_);
633  operation_runner()->TouchFile(url, last_access_time,
634                                last_modified_time, callback);
635}
636
637void CannedSyncableFileSystem::DoRemove(
638    const FileSystemURL& url, bool recursive,
639    const StatusCallback& callback) {
640  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
641  EXPECT_TRUE(is_filesystem_opened_);
642  operation_runner()->Remove(url, recursive, callback);
643}
644
645void CannedSyncableFileSystem::DoFileExists(
646    const FileSystemURL& url, const StatusCallback& callback) {
647  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
648  EXPECT_TRUE(is_filesystem_opened_);
649  operation_runner()->FileExists(url, callback);
650}
651
652void CannedSyncableFileSystem::DoDirectoryExists(
653    const FileSystemURL& url, const StatusCallback& callback) {
654  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
655  EXPECT_TRUE(is_filesystem_opened_);
656  operation_runner()->DirectoryExists(url, callback);
657}
658
659void CannedSyncableFileSystem::DoVerifyFile(
660    const FileSystemURL& url,
661    const std::string& expected_data,
662    const StatusCallback& callback) {
663  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
664  EXPECT_TRUE(is_filesystem_opened_);
665  operation_runner()->CreateSnapshotFile(
666      url,
667      base::Bind(&OnCreateSnapshotFileAndVerifyData, expected_data, callback));
668}
669
670void CannedSyncableFileSystem::DoGetMetadataAndPlatformPath(
671    const FileSystemURL& url,
672    base::File::Info* info,
673    base::FilePath* platform_path,
674    const StatusCallback& callback) {
675  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
676  EXPECT_TRUE(is_filesystem_opened_);
677  operation_runner()->CreateSnapshotFile(
678      url, base::Bind(&OnCreateSnapshotFile, info, platform_path, callback));
679}
680
681void CannedSyncableFileSystem::DoReadDirectory(
682    const FileSystemURL& url,
683    FileEntryList* entries,
684    const StatusCallback& callback) {
685  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
686  EXPECT_TRUE(is_filesystem_opened_);
687  operation_runner()->ReadDirectory(
688      url, base::Bind(&OnReadDirectory, entries, callback));
689}
690
691void CannedSyncableFileSystem::DoWrite(
692    net::URLRequestContext* url_request_context,
693    const FileSystemURL& url,
694    scoped_ptr<storage::BlobDataHandle> blob_data_handle,
695    const WriteCallback& callback) {
696  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
697  EXPECT_TRUE(is_filesystem_opened_);
698  WriteHelper* helper = new WriteHelper;
699  operation_runner()->Write(url_request_context, url,
700                            blob_data_handle.Pass(), 0,
701                            base::Bind(&WriteHelper::DidWrite,
702                                       base::Owned(helper), callback));
703}
704
705void CannedSyncableFileSystem::DoWriteString(
706    const FileSystemURL& url,
707    const std::string& data,
708    const WriteCallback& callback) {
709  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
710  EXPECT_TRUE(is_filesystem_opened_);
711  MockBlobURLRequestContext* url_request_context(
712      new MockBlobURLRequestContext(file_system_context_.get()));
713  WriteHelper* helper = new WriteHelper(url_request_context, data);
714  operation_runner()->Write(url_request_context, url,
715                            helper->scoped_text_blob()->GetBlobDataHandle(), 0,
716                            base::Bind(&WriteHelper::DidWrite,
717                                       base::Owned(helper), callback));
718}
719
720void CannedSyncableFileSystem::DoGetUsageAndQuota(
721    int64* usage,
722    int64* quota,
723    const storage::StatusCallback& callback) {
724  EXPECT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
725  EXPECT_TRUE(is_filesystem_opened_);
726  DCHECK(quota_manager_);
727  quota_manager_->GetUsageAndQuota(
728      origin_, storage_type(),
729      base::Bind(&DidGetUsageAndQuota, callback, usage, quota));
730}
731
732void CannedSyncableFileSystem::DidOpenFileSystem(
733    base::SingleThreadTaskRunner* original_task_runner,
734    const base::Closure& quit_closure,
735    const GURL& root,
736    const std::string& name,
737    File::Error result) {
738  if (io_task_runner_->RunsTasksOnCurrentThread()) {
739    EXPECT_FALSE(is_filesystem_opened_);
740    is_filesystem_opened_ = true;
741  }
742  if (!original_task_runner->RunsTasksOnCurrentThread()) {
743    DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
744    original_task_runner->PostTask(
745        FROM_HERE,
746        base::Bind(&CannedSyncableFileSystem::DidOpenFileSystem,
747                   base::Unretained(this),
748                   make_scoped_refptr(original_task_runner),
749                   quit_closure,
750                   root, name, result));
751    return;
752  }
753  result_ = result;
754  root_url_ = root;
755  quit_closure.Run();
756}
757
758void CannedSyncableFileSystem::DidInitializeFileSystemContext(
759    const base::Closure& quit_closure,
760    SyncStatusCode status) {
761  sync_status_ = status;
762  quit_closure.Run();
763}
764
765void CannedSyncableFileSystem::InitializeSyncStatusObserver() {
766  ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
767  backend()->sync_context()->sync_status()->AddObserver(this);
768}
769
770}  // namespace sync_file_system
771