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