Home | History | Annotate | Download | only in test
      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 "content/public/test/test_file_system_backend.h"
      6 
      7 #include <set>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/files/file.h"
     12 #include "base/files/file_util.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/observer_list.h"
     15 #include "base/sequenced_task_runner.h"
     16 #include "base/thread_task_runner_handle.h"
     17 #include "storage/browser/blob/file_stream_reader.h"
     18 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
     19 #include "storage/browser/fileapi/file_observers.h"
     20 #include "storage/browser/fileapi/file_system_operation.h"
     21 #include "storage/browser/fileapi/file_system_operation_context.h"
     22 #include "storage/browser/fileapi/file_system_quota_util.h"
     23 #include "storage/browser/fileapi/local_file_util.h"
     24 #include "storage/browser/fileapi/native_file_util.h"
     25 #include "storage/browser/fileapi/quota/quota_reservation.h"
     26 #include "storage/browser/fileapi/sandbox_file_stream_writer.h"
     27 #include "storage/browser/fileapi/watcher_manager.h"
     28 #include "storage/browser/quota/quota_manager.h"
     29 #include "storage/common/fileapi/file_system_util.h"
     30 
     31 using storage::FileSystemContext;
     32 using storage::FileSystemOperation;
     33 using storage::FileSystemOperationContext;
     34 using storage::FileSystemURL;
     35 
     36 namespace content {
     37 
     38 namespace {
     39 
     40 // Stub implementation of storage::LocalFileUtil.
     41 class TestFileUtil : public storage::LocalFileUtil {
     42  public:
     43   explicit TestFileUtil(const base::FilePath& base_path)
     44       : base_path_(base_path) {}
     45   virtual ~TestFileUtil() {}
     46 
     47   // LocalFileUtil overrides.
     48   virtual base::File::Error GetLocalFilePath(
     49       FileSystemOperationContext* context,
     50       const FileSystemURL& file_system_url,
     51       base::FilePath* local_file_path) OVERRIDE {
     52     *local_file_path = base_path_.Append(file_system_url.path());
     53     return base::File::FILE_OK;
     54   }
     55 
     56  private:
     57   base::FilePath base_path_;
     58 };
     59 
     60 // Stub implementation of storage::WatcherManager. Emits a fake notification
     61 // after a directory watcher is set successfully.
     62 class TestWatcherManager : public storage::WatcherManager {
     63  public:
     64   TestWatcherManager() : weak_ptr_factory_(this) {}
     65   virtual ~TestWatcherManager() {}
     66 
     67   // storage::WatcherManager overrides.
     68   virtual void AddObserver(Observer* observer) OVERRIDE {
     69     observers_.AddObserver(observer);
     70   }
     71 
     72   virtual void RemoveObserver(Observer* observer) OVERRIDE {
     73     observers_.RemoveObserver(observer);
     74   }
     75 
     76   virtual bool HasObserver(Observer* observer) const OVERRIDE {
     77     return observers_.HasObserver(observer);
     78   }
     79 
     80   virtual void WatchDirectory(const storage::FileSystemURL& url,
     81                               bool recursive,
     82                               const StatusCallback& callback) OVERRIDE {
     83     if (recursive) {
     84       base::ThreadTaskRunnerHandle::Get()->PostTask(
     85           FROM_HERE,
     86           base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
     87       return;
     88     }
     89 
     90     const GURL gurl = url.ToGURL();
     91     if (watched_urls_.find(gurl) != watched_urls_.end()) {
     92       base::ThreadTaskRunnerHandle::Get()->PostTask(
     93           FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_EXISTS));
     94       return;
     95     }
     96 
     97     watched_urls_.insert(gurl);
     98     base::ThreadTaskRunnerHandle::Get()->PostTask(
     99         FROM_HERE, base::Bind(callback, base::File::FILE_OK));
    100 
    101     // Send a fake changed notification.
    102     base::ThreadTaskRunnerHandle::Get()->PostTask(
    103         FROM_HERE,
    104         base::Bind(&TestWatcherManager::SendFakeChangeNotification,
    105                    weak_ptr_factory_.GetWeakPtr(),
    106                    url));
    107 
    108     // Send a fake removed notification.
    109     base::ThreadTaskRunnerHandle::Get()->PostTask(
    110         FROM_HERE,
    111         base::Bind(&TestWatcherManager::SendFakeRemoveNotification,
    112                    weak_ptr_factory_.GetWeakPtr(),
    113                    url));
    114   }
    115 
    116   virtual void UnwatchEntry(const storage::FileSystemURL& url,
    117                             const StatusCallback& callback) OVERRIDE {
    118     const GURL gurl = url.ToGURL();
    119     if (watched_urls_.find(gurl) == watched_urls_.end()) {
    120       base::ThreadTaskRunnerHandle::Get()->PostTask(
    121           FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND));
    122       return;
    123     }
    124 
    125     watched_urls_.erase(gurl);
    126     base::ThreadTaskRunnerHandle::Get()->PostTask(
    127         FROM_HERE, base::Bind(callback, base::File::FILE_OK));
    128   }
    129 
    130  private:
    131   // Sends a fake notification to each observer about a changed entry
    132   // represented by |url|, as long as it is still being watched.
    133   void SendFakeChangeNotification(const storage::FileSystemURL& url) {
    134     if (watched_urls_.find(url.ToGURL()) == watched_urls_.end())
    135       return;
    136 
    137     FOR_EACH_OBSERVER(Observer, observers_, OnEntryChanged(url));
    138   }
    139 
    140   // Sends a fake notification to each observer about a removed entry
    141   // represented by |url|, as long as it is still being watched.
    142   void SendFakeRemoveNotification(const storage::FileSystemURL& url) {
    143     if (watched_urls_.find(url.ToGURL()) == watched_urls_.end())
    144       return;
    145 
    146     FOR_EACH_OBSERVER(Observer, observers_, OnEntryRemoved(url));
    147   }
    148 
    149   ObserverList<Observer> observers_;
    150   std::set<GURL> watched_urls_;
    151 
    152   base::WeakPtrFactory<TestWatcherManager> weak_ptr_factory_;
    153 };
    154 
    155 }  // namespace
    156 
    157 // This only supports single origin.
    158 class TestFileSystemBackend::QuotaUtil : public storage::FileSystemQuotaUtil,
    159                                          public storage::FileUpdateObserver {
    160  public:
    161   QuotaUtil() : usage_(0) {}
    162   virtual ~QuotaUtil() {}
    163 
    164   // FileSystemQuotaUtil overrides.
    165   virtual base::File::Error DeleteOriginDataOnFileTaskRunner(
    166       FileSystemContext* context,
    167       storage::QuotaManagerProxy* proxy,
    168       const GURL& origin_url,
    169       storage::FileSystemType type) OVERRIDE {
    170     NOTREACHED();
    171     return base::File::FILE_OK;
    172   }
    173 
    174   virtual scoped_refptr<storage::QuotaReservation>
    175   CreateQuotaReservationOnFileTaskRunner(
    176       const GURL& origin_url,
    177       storage::FileSystemType type) OVERRIDE {
    178     NOTREACHED();
    179     return scoped_refptr<storage::QuotaReservation>();
    180   }
    181 
    182   virtual void GetOriginsForTypeOnFileTaskRunner(
    183       storage::FileSystemType type,
    184       std::set<GURL>* origins) OVERRIDE {
    185     NOTREACHED();
    186   }
    187 
    188   virtual void GetOriginsForHostOnFileTaskRunner(
    189       storage::FileSystemType type,
    190       const std::string& host,
    191       std::set<GURL>* origins) OVERRIDE {
    192     NOTREACHED();
    193   }
    194 
    195   virtual int64 GetOriginUsageOnFileTaskRunner(
    196       FileSystemContext* context,
    197       const GURL& origin_url,
    198       storage::FileSystemType type) OVERRIDE {
    199     return usage_;
    200   }
    201 
    202   // FileUpdateObserver overrides.
    203   virtual void OnStartUpdate(const FileSystemURL& url) OVERRIDE {}
    204   virtual void OnUpdate(const FileSystemURL& url, int64 delta) OVERRIDE {
    205     usage_ += delta;
    206   }
    207   virtual void OnEndUpdate(const FileSystemURL& url) OVERRIDE {}
    208 
    209  private:
    210   int64 usage_;
    211   DISALLOW_COPY_AND_ASSIGN(QuotaUtil);
    212 };
    213 
    214 TestFileSystemBackend::TestFileSystemBackend(
    215     base::SequencedTaskRunner* task_runner,
    216     const base::FilePath& base_path)
    217     : base_path_(base_path),
    218       task_runner_(task_runner),
    219       file_util_(
    220           new storage::AsyncFileUtilAdapter(new TestFileUtil(base_path))),
    221       watcher_manager_(new TestWatcherManager()),
    222       quota_util_(new QuotaUtil),
    223       require_copy_or_move_validator_(false) {
    224   update_observers_ =
    225       update_observers_.AddObserver(quota_util_.get(), task_runner_.get());
    226 }
    227 
    228 TestFileSystemBackend::~TestFileSystemBackend() {
    229 }
    230 
    231 bool TestFileSystemBackend::CanHandleType(storage::FileSystemType type) const {
    232   return (type == storage::kFileSystemTypeTest);
    233 }
    234 
    235 void TestFileSystemBackend::Initialize(FileSystemContext* context) {
    236 }
    237 
    238 void TestFileSystemBackend::ResolveURL(const FileSystemURL& url,
    239                                        storage::OpenFileSystemMode mode,
    240                                        const OpenFileSystemCallback& callback) {
    241   callback.Run(GetFileSystemRootURI(url.origin(), url.type()),
    242                GetFileSystemName(url.origin(), url.type()),
    243                base::File::FILE_OK);
    244 }
    245 
    246 storage::AsyncFileUtil* TestFileSystemBackend::GetAsyncFileUtil(
    247     storage::FileSystemType type) {
    248   return file_util_.get();
    249 }
    250 
    251 storage::WatcherManager* TestFileSystemBackend::GetWatcherManager(
    252     storage::FileSystemType type) {
    253   return watcher_manager_.get();
    254 }
    255 
    256 storage::CopyOrMoveFileValidatorFactory*
    257 TestFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
    258     storage::FileSystemType type,
    259     base::File::Error* error_code) {
    260   DCHECK(error_code);
    261   *error_code = base::File::FILE_OK;
    262   if (require_copy_or_move_validator_) {
    263     if (!copy_or_move_file_validator_factory_)
    264       *error_code = base::File::FILE_ERROR_SECURITY;
    265     return copy_or_move_file_validator_factory_.get();
    266   }
    267   return NULL;
    268 }
    269 
    270 void TestFileSystemBackend::InitializeCopyOrMoveFileValidatorFactory(
    271     scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory) {
    272   if (!copy_or_move_file_validator_factory_)
    273     copy_or_move_file_validator_factory_ = factory.Pass();
    274 }
    275 
    276 FileSystemOperation* TestFileSystemBackend::CreateFileSystemOperation(
    277     const FileSystemURL& url,
    278     FileSystemContext* context,
    279     base::File::Error* error_code) const {
    280   scoped_ptr<FileSystemOperationContext> operation_context(
    281       new FileSystemOperationContext(context));
    282   operation_context->set_update_observers(*GetUpdateObservers(url.type()));
    283   operation_context->set_change_observers(*GetChangeObservers(url.type()));
    284   return FileSystemOperation::Create(url, context, operation_context.Pass());
    285 }
    286 
    287 bool TestFileSystemBackend::SupportsStreaming(
    288     const storage::FileSystemURL& url) const {
    289   return false;
    290 }
    291 
    292 bool TestFileSystemBackend::HasInplaceCopyImplementation(
    293     storage::FileSystemType type) const {
    294   return true;
    295 }
    296 
    297 scoped_ptr<storage::FileStreamReader>
    298 TestFileSystemBackend::CreateFileStreamReader(
    299     const FileSystemURL& url,
    300     int64 offset,
    301     int64 max_bytes_to_read,
    302     const base::Time& expected_modification_time,
    303     FileSystemContext* context) const {
    304   return scoped_ptr<storage::FileStreamReader>(
    305       storage::FileStreamReader::CreateForFileSystemFile(
    306           context, url, offset, expected_modification_time));
    307 }
    308 
    309 scoped_ptr<storage::FileStreamWriter>
    310 TestFileSystemBackend::CreateFileStreamWriter(
    311     const FileSystemURL& url,
    312     int64 offset,
    313     FileSystemContext* context) const {
    314   return scoped_ptr<storage::FileStreamWriter>(
    315       new storage::SandboxFileStreamWriter(
    316           context, url, offset, *GetUpdateObservers(url.type())));
    317 }
    318 
    319 storage::FileSystemQuotaUtil* TestFileSystemBackend::GetQuotaUtil() {
    320   return quota_util_.get();
    321 }
    322 
    323 const storage::UpdateObserverList* TestFileSystemBackend::GetUpdateObservers(
    324     storage::FileSystemType type) const {
    325   return &update_observers_;
    326 }
    327 
    328 const storage::ChangeObserverList* TestFileSystemBackend::GetChangeObservers(
    329     storage::FileSystemType type) const {
    330   return &change_observers_;
    331 }
    332 
    333 const storage::AccessObserverList* TestFileSystemBackend::GetAccessObservers(
    334     storage::FileSystemType type) const {
    335   return NULL;
    336 }
    337 
    338 void TestFileSystemBackend::AddFileChangeObserver(
    339     storage::FileChangeObserver* observer) {
    340   change_observers_ =
    341       change_observers_.AddObserver(observer, task_runner_.get());
    342 }
    343 
    344 }  // namespace content
    345