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