canned_syncable_file_system.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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 "testing/gtest/include/gtest/gtest.h"
24#include "webkit/browser/blob/mock_blob_url_request_context.h"
25#include "webkit/browser/fileapi/external_mount_points.h"
26#include "webkit/browser/fileapi/file_system_backend.h"
27#include "webkit/browser/fileapi/file_system_context.h"
28#include "webkit/browser/fileapi/file_system_operation_context.h"
29#include "webkit/browser/fileapi/file_system_operation_runner.h"
30#include "webkit/browser/fileapi/mock_file_system_options.h"
31#include "webkit/browser/fileapi/sandbox_file_system_backend.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::PlatformFileError;
37using fileapi::FileSystemContext;
38using fileapi::FileSystemOperationRunner;
39using fileapi::FileSystemURL;
40using fileapi::FileSystemURLSet;
41using quota::QuotaManager;
42using webkit_blob::MockBlobURLRequestContext;
43using webkit_blob::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::PlatformFileError result,
103    const base::PlatformFileInfo& file_info,
104    const base::FilePath& platform_path,
105    const scoped_refptr<webkit_blob::ShareableFileReference>& /* file_ref */) {
106  if (result != base::PLATFORM_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::PlatformFileInfo* file_info_out,
120    base::FilePath* platform_path_out,
121    const CannedSyncableFileSystem::StatusCallback& callback,
122    base::PlatformFileError result,
123    const base::PlatformFileInfo& 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::PlatformFileError 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                PlatformFileError error, int64 bytes, bool complete) {
171    if (error == base::PLATFORM_FILE_OK) {
172      bytes_written_ += bytes;
173      if (!complete)
174        return;
175    }
176    completion_callback.Run(error == base::PLATFORM_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    base::SingleThreadTaskRunner* io_task_runner,
209    base::SingleThreadTaskRunner* file_task_runner)
210    : origin_(origin),
211      type_(fileapi::kFileSystemTypeSyncable),
212      result_(base::PLATFORM_FILE_OK),
213      sync_status_(sync_file_system::SYNC_STATUS_OK),
214      io_task_runner_(io_task_runner),
215      file_task_runner_(file_task_runner),
216      is_filesystem_set_up_(false),
217      is_filesystem_opened_(false),
218      sync_status_observers_(new ObserverList) {
219}
220
221CannedSyncableFileSystem::~CannedSyncableFileSystem() {}
222
223void CannedSyncableFileSystem::SetUp() {
224  ASSERT_FALSE(is_filesystem_set_up_);
225  ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
226
227  scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
228      new quota::MockSpecialStoragePolicy();
229
230  quota_manager_ = new QuotaManager(false /* is_incognito */,
231                                    data_dir_.path(),
232                                    io_task_runner_.get(),
233                                    base::MessageLoopProxy::current().get(),
234                                    storage_policy.get());
235
236  std::vector<std::string> additional_allowed_schemes;
237  additional_allowed_schemes.push_back(origin_.scheme());
238  fileapi::FileSystemOptions options(
239      fileapi::FileSystemOptions::PROFILE_MODE_NORMAL,
240      additional_allowed_schemes);
241
242  ScopedVector<fileapi::FileSystemBackend> additional_backends;
243  additional_backends.push_back(SyncFileSystemBackend::CreateForTesting());
244
245  file_system_context_ = new FileSystemContext(
246      io_task_runner_.get(),
247      file_task_runner_.get(),
248      fileapi::ExternalMountPoints::CreateRefCounted().get(),
249      storage_policy.get(),
250      quota_manager_->proxy(),
251      additional_backends.Pass(),
252      data_dir_.path(), options);
253
254  is_filesystem_set_up_ = true;
255}
256
257void CannedSyncableFileSystem::TearDown() {
258  quota_manager_ = NULL;
259  file_system_context_ = NULL;
260
261  // Make sure we give some more time to finish tasks on other threads.
262  EnsureLastTaskRuns(io_task_runner_.get());
263  EnsureLastTaskRuns(file_task_runner_.get());
264}
265
266FileSystemURL CannedSyncableFileSystem::URL(const std::string& path) const {
267  EXPECT_TRUE(is_filesystem_set_up_);
268  EXPECT_TRUE(is_filesystem_opened_);
269
270  GURL url(root_url_.spec() + path);
271  return file_system_context_->CrackURL(url);
272}
273
274PlatformFileError CannedSyncableFileSystem::OpenFileSystem() {
275  EXPECT_TRUE(is_filesystem_set_up_);
276  EXPECT_FALSE(is_filesystem_opened_);
277  file_system_context_->OpenFileSystem(
278      origin_, type_,
279      fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
280      base::Bind(&CannedSyncableFileSystem::DidOpenFileSystem,
281                 base::Unretained(this)));
282  base::MessageLoop::current()->Run();
283  if (backend()->sync_context()) {
284    // Register 'this' as a sync status observer.
285    RunOnThread(
286        io_task_runner_.get(),
287        FROM_HERE,
288        base::Bind(&CannedSyncableFileSystem::InitializeSyncStatusObserver,
289                   base::Unretained(this)));
290  }
291  return result_;
292}
293
294void CannedSyncableFileSystem::AddSyncStatusObserver(
295    LocalFileSyncStatus::Observer* observer) {
296  sync_status_observers_->AddObserver(observer);
297}
298
299void CannedSyncableFileSystem::RemoveSyncStatusObserver(
300    LocalFileSyncStatus::Observer* observer) {
301  sync_status_observers_->RemoveObserver(observer);
302}
303
304SyncStatusCode CannedSyncableFileSystem::MaybeInitializeFileSystemContext(
305    LocalFileSyncContext* sync_context) {
306  DCHECK(sync_context);
307  sync_status_ = sync_file_system::SYNC_STATUS_UNKNOWN;
308  VerifySameTaskRunner(io_task_runner_.get(),
309                       sync_context->io_task_runner_.get());
310  sync_context->MaybeInitializeFileSystemContext(
311      origin_,
312      file_system_context_.get(),
313      base::Bind(&CannedSyncableFileSystem::DidInitializeFileSystemContext,
314                 base::Unretained(this)));
315  base::MessageLoop::current()->Run();
316  return sync_status_;
317}
318
319PlatformFileError CannedSyncableFileSystem::CreateDirectory(
320    const FileSystemURL& url) {
321  return RunOnThread<PlatformFileError>(
322      io_task_runner_.get(),
323      FROM_HERE,
324      base::Bind(&CannedSyncableFileSystem::DoCreateDirectory,
325                 base::Unretained(this),
326                 url));
327}
328
329PlatformFileError CannedSyncableFileSystem::CreateFile(
330    const FileSystemURL& url) {
331  return RunOnThread<PlatformFileError>(
332      io_task_runner_.get(),
333      FROM_HERE,
334      base::Bind(&CannedSyncableFileSystem::DoCreateFile,
335                 base::Unretained(this),
336                 url));
337}
338
339PlatformFileError CannedSyncableFileSystem::Copy(
340    const FileSystemURL& src_url, const FileSystemURL& dest_url) {
341  return RunOnThread<PlatformFileError>(
342      io_task_runner_.get(),
343      FROM_HERE,
344      base::Bind(&CannedSyncableFileSystem::DoCopy,
345                 base::Unretained(this),
346                 src_url,
347                 dest_url));
348}
349
350PlatformFileError CannedSyncableFileSystem::Move(
351    const FileSystemURL& src_url, const FileSystemURL& dest_url) {
352  return RunOnThread<PlatformFileError>(
353      io_task_runner_.get(),
354      FROM_HERE,
355      base::Bind(&CannedSyncableFileSystem::DoMove,
356                 base::Unretained(this),
357                 src_url,
358                 dest_url));
359}
360
361PlatformFileError CannedSyncableFileSystem::TruncateFile(
362    const FileSystemURL& url, int64 size) {
363  return RunOnThread<PlatformFileError>(
364      io_task_runner_.get(),
365      FROM_HERE,
366      base::Bind(&CannedSyncableFileSystem::DoTruncateFile,
367                 base::Unretained(this),
368                 url,
369                 size));
370}
371
372PlatformFileError CannedSyncableFileSystem::TouchFile(
373    const FileSystemURL& url,
374    const base::Time& last_access_time,
375    const base::Time& last_modified_time) {
376  return RunOnThread<PlatformFileError>(
377      io_task_runner_.get(),
378      FROM_HERE,
379      base::Bind(&CannedSyncableFileSystem::DoTouchFile,
380                 base::Unretained(this),
381                 url,
382                 last_access_time,
383                 last_modified_time));
384}
385
386PlatformFileError CannedSyncableFileSystem::Remove(
387    const FileSystemURL& url, bool recursive) {
388  return RunOnThread<PlatformFileError>(
389      io_task_runner_.get(),
390      FROM_HERE,
391      base::Bind(&CannedSyncableFileSystem::DoRemove,
392                 base::Unretained(this),
393                 url,
394                 recursive));
395}
396
397PlatformFileError CannedSyncableFileSystem::FileExists(
398    const FileSystemURL& url) {
399  return RunOnThread<PlatformFileError>(
400      io_task_runner_.get(),
401      FROM_HERE,
402      base::Bind(&CannedSyncableFileSystem::DoFileExists,
403                 base::Unretained(this),
404                 url));
405}
406
407PlatformFileError CannedSyncableFileSystem::DirectoryExists(
408    const FileSystemURL& url) {
409  return RunOnThread<PlatformFileError>(
410      io_task_runner_.get(),
411      FROM_HERE,
412      base::Bind(&CannedSyncableFileSystem::DoDirectoryExists,
413                 base::Unretained(this),
414                 url));
415}
416
417PlatformFileError CannedSyncableFileSystem::VerifyFile(
418    const FileSystemURL& url,
419    const std::string& expected_data) {
420  return RunOnThread<PlatformFileError>(
421      io_task_runner_.get(),
422      FROM_HERE,
423      base::Bind(&CannedSyncableFileSystem::DoVerifyFile,
424                 base::Unretained(this),
425                 url,
426                 expected_data));
427}
428
429PlatformFileError CannedSyncableFileSystem::GetMetadataAndPlatformPath(
430    const FileSystemURL& url,
431    base::PlatformFileInfo* info,
432    base::FilePath* platform_path) {
433  return RunOnThread<PlatformFileError>(
434      io_task_runner_.get(),
435      FROM_HERE,
436      base::Bind(&CannedSyncableFileSystem::DoGetMetadataAndPlatformPath,
437                 base::Unretained(this),
438                 url,
439                 info,
440                 platform_path));
441}
442
443PlatformFileError CannedSyncableFileSystem::ReadDirectory(
444    const fileapi::FileSystemURL& url,
445    FileEntryList* entries) {
446  return RunOnThread<PlatformFileError>(
447      io_task_runner_.get(),
448      FROM_HERE,
449      base::Bind(&CannedSyncableFileSystem::DoReadDirectory,
450          base::Unretained(this),
451          url,
452          entries));
453}
454
455int64 CannedSyncableFileSystem::Write(
456    net::URLRequestContext* url_request_context,
457    const FileSystemURL& url,
458    scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle) {
459  return RunOnThread<int64>(io_task_runner_.get(),
460                            FROM_HERE,
461                            base::Bind(&CannedSyncableFileSystem::DoWrite,
462                                       base::Unretained(this),
463                                       url_request_context,
464                                       url,
465                                       base::Passed(&blob_data_handle)));
466}
467
468int64 CannedSyncableFileSystem::WriteString(
469    const FileSystemURL& url, const std::string& data) {
470  return RunOnThread<int64>(io_task_runner_.get(),
471                            FROM_HERE,
472                            base::Bind(&CannedSyncableFileSystem::DoWriteString,
473                                       base::Unretained(this),
474                                       url,
475                                       data));
476}
477
478PlatformFileError CannedSyncableFileSystem::DeleteFileSystem() {
479  EXPECT_TRUE(is_filesystem_set_up_);
480  return RunOnThread<PlatformFileError>(
481      io_task_runner_.get(),
482      FROM_HERE,
483      base::Bind(&FileSystemContext::DeleteFileSystem,
484                 file_system_context_,
485                 origin_,
486                 type_));
487}
488
489quota::QuotaStatusCode CannedSyncableFileSystem::GetUsageAndQuota(
490    int64* usage, int64* quota) {
491  return RunOnThread<quota::QuotaStatusCode>(
492      io_task_runner_.get(),
493      FROM_HERE,
494      base::Bind(&CannedSyncableFileSystem::DoGetUsageAndQuota,
495                 base::Unretained(this),
496                 usage,
497                 quota));
498}
499
500void CannedSyncableFileSystem::GetChangedURLsInTracker(
501    FileSystemURLSet* urls) {
502  RunOnThread(
503      file_task_runner_.get(),
504      FROM_HERE,
505      base::Bind(&LocalFileChangeTracker::GetAllChangedURLs,
506                 base::Unretained(backend()->change_tracker()),
507                 urls));
508}
509
510void CannedSyncableFileSystem::ClearChangeForURLInTracker(
511    const FileSystemURL& url) {
512  RunOnThread(
513      file_task_runner_.get(),
514      FROM_HERE,
515      base::Bind(&LocalFileChangeTracker::ClearChangesForURL,
516                 base::Unretained(backend()->change_tracker()),
517                 url));
518}
519
520void CannedSyncableFileSystem::GetChangesForURLInTracker(
521    const FileSystemURL& url,
522    FileChangeList* changes) {
523  RunOnThread(
524      file_task_runner_.get(),
525      FROM_HERE,
526      base::Bind(&LocalFileChangeTracker::GetChangesForURL,
527                 base::Unretained(backend()->change_tracker()),
528                 url, changes));
529}
530
531SyncFileSystemBackend* CannedSyncableFileSystem::backend() {
532  return SyncFileSystemBackend::GetBackend(file_system_context_);
533}
534
535FileSystemOperationRunner* CannedSyncableFileSystem::operation_runner() {
536  return file_system_context_->operation_runner();
537}
538
539void CannedSyncableFileSystem::OnSyncEnabled(const FileSystemURL& url) {
540  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnSyncEnabled,
541                                 url);
542}
543
544void CannedSyncableFileSystem::OnWriteEnabled(const FileSystemURL& url) {
545  sync_status_observers_->Notify(&LocalFileSyncStatus::Observer::OnWriteEnabled,
546                                 url);
547}
548
549void CannedSyncableFileSystem::DoCreateDirectory(
550    const FileSystemURL& url,
551    const StatusCallback& callback) {
552  EXPECT_TRUE(is_filesystem_opened_);
553  operation_runner()->CreateDirectory(
554      url, false /* exclusive */, false /* recursive */, callback);
555}
556
557void CannedSyncableFileSystem::DoCreateFile(
558    const FileSystemURL& url,
559    const StatusCallback& callback) {
560  EXPECT_TRUE(is_filesystem_opened_);
561  operation_runner()->CreateFile(url, false /* exclusive */, callback);
562}
563
564void CannedSyncableFileSystem::DoCopy(
565    const FileSystemURL& src_url,
566    const FileSystemURL& dest_url,
567    const StatusCallback& callback) {
568  EXPECT_TRUE(is_filesystem_opened_);
569  operation_runner()->Copy(
570      src_url, dest_url,
571      fileapi::FileSystemOperationRunner::CopyProgressCallback(), callback);
572}
573
574void CannedSyncableFileSystem::DoMove(
575    const FileSystemURL& src_url,
576    const FileSystemURL& dest_url,
577    const StatusCallback& callback) {
578  EXPECT_TRUE(is_filesystem_opened_);
579  operation_runner()->Move(src_url, dest_url, callback);
580}
581
582void CannedSyncableFileSystem::DoTruncateFile(
583    const FileSystemURL& url, int64 size,
584    const StatusCallback& callback) {
585  EXPECT_TRUE(is_filesystem_opened_);
586  operation_runner()->Truncate(url, size, callback);
587}
588
589void CannedSyncableFileSystem::DoTouchFile(
590    const FileSystemURL& url,
591    const base::Time& last_access_time,
592    const base::Time& last_modified_time,
593    const StatusCallback& callback) {
594  EXPECT_TRUE(is_filesystem_opened_);
595  operation_runner()->TouchFile(url, last_access_time,
596                                last_modified_time, callback);
597}
598
599void CannedSyncableFileSystem::DoRemove(
600    const FileSystemURL& url, bool recursive,
601    const StatusCallback& callback) {
602  EXPECT_TRUE(is_filesystem_opened_);
603  operation_runner()->Remove(url, recursive, callback);
604}
605
606void CannedSyncableFileSystem::DoFileExists(
607    const FileSystemURL& url, const StatusCallback& callback) {
608  EXPECT_TRUE(is_filesystem_opened_);
609  operation_runner()->FileExists(url, callback);
610}
611
612void CannedSyncableFileSystem::DoDirectoryExists(
613    const FileSystemURL& url, const StatusCallback& callback) {
614  EXPECT_TRUE(is_filesystem_opened_);
615  operation_runner()->DirectoryExists(url, callback);
616}
617
618void CannedSyncableFileSystem::DoVerifyFile(
619    const FileSystemURL& url,
620    const std::string& expected_data,
621    const StatusCallback& callback) {
622  EXPECT_TRUE(is_filesystem_opened_);
623  operation_runner()->CreateSnapshotFile(
624      url,
625      base::Bind(&OnCreateSnapshotFileAndVerifyData, expected_data, callback));
626}
627
628void CannedSyncableFileSystem::DoGetMetadataAndPlatformPath(
629    const FileSystemURL& url,
630    base::PlatformFileInfo* info,
631    base::FilePath* platform_path,
632    const StatusCallback& callback) {
633  EXPECT_TRUE(is_filesystem_opened_);
634  operation_runner()->CreateSnapshotFile(
635      url, base::Bind(&OnCreateSnapshotFile, info, platform_path, callback));
636}
637
638void CannedSyncableFileSystem::DoReadDirectory(
639    const FileSystemURL& url,
640    FileEntryList* entries,
641    const StatusCallback& callback) {
642  EXPECT_TRUE(is_filesystem_opened_);
643  operation_runner()->ReadDirectory(
644      url, base::Bind(&OnReadDirectory, entries, callback));
645}
646
647void CannedSyncableFileSystem::DoWrite(
648    net::URLRequestContext* url_request_context,
649    const FileSystemURL& url,
650    scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle,
651    const WriteCallback& callback) {
652  EXPECT_TRUE(is_filesystem_opened_);
653  WriteHelper* helper = new WriteHelper;
654  operation_runner()->Write(url_request_context, url,
655                            blob_data_handle.Pass(), 0,
656                            base::Bind(&WriteHelper::DidWrite,
657                                       base::Owned(helper), callback));
658}
659
660void CannedSyncableFileSystem::DoWriteString(
661    const FileSystemURL& url,
662    const std::string& data,
663    const WriteCallback& callback) {
664  MockBlobURLRequestContext* url_request_context(
665      new MockBlobURLRequestContext(file_system_context_.get()));
666  WriteHelper* helper = new WriteHelper(url_request_context, data);
667  operation_runner()->Write(url_request_context, url,
668                            helper->scoped_text_blob()->GetBlobDataHandle(), 0,
669                            base::Bind(&WriteHelper::DidWrite,
670                                       base::Owned(helper), callback));
671}
672
673void CannedSyncableFileSystem::DoGetUsageAndQuota(
674    int64* usage,
675    int64* quota,
676    const quota::StatusCallback& callback) {
677  quota_manager_->GetUsageAndQuota(
678      origin_, storage_type(),
679      base::Bind(&DidGetUsageAndQuota, callback, usage, quota));
680}
681
682void CannedSyncableFileSystem::DidOpenFileSystem(
683    PlatformFileError result, const std::string& name, const GURL& root) {
684  result_ = result;
685  root_url_ = root;
686  is_filesystem_opened_ = true;
687  base::MessageLoop::current()->Quit();
688}
689
690void CannedSyncableFileSystem::DidInitializeFileSystemContext(
691    SyncStatusCode status) {
692  sync_status_ = status;
693  base::MessageLoop::current()->Quit();
694}
695
696void CannedSyncableFileSystem::InitializeSyncStatusObserver() {
697  ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
698  backend()->sync_context()->sync_status()->AddObserver(this);
699}
700
701}  // namespace sync_file_system
702