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