| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/public/test/test_fileapi_operation_waiter.h" |
| |
| #include "base/bind_helpers.h" |
| #include "base/lazy_instance.h" |
| #include "base/observer_list.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "storage/browser/fileapi/file_system_context.h" |
| #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" |
| |
| namespace content { |
| |
| using storage::FileSystemContext; |
| using storage::FileSystemURL; |
| using storage::FileUpdateObserver; |
| |
| namespace { |
| |
| // Because of how fileapi internally creates copies of its observer lists, |
| // removing an observer is not a supported operation. So to support temporary, |
| // test-style observers, we create one long-lived global observer instance that |
| // dispatches to a list of short-lived observers. |
| // |
| // This object operates on the UI thread, though it registers itself as an |
| // observer on the IO thread. |
| class FileUpdateObserverMultiplexer : public FileUpdateObserver { |
| public: |
| FileUpdateObserverMultiplexer() {} |
| |
| void AddObserver(FileSystemContext* context, FileUpdateObserver* observer) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| |
| // On first initialization, install ourself as an observer. We never |
| // uninstall, because we expect to leak. |
| if (!context_) { |
| // Currently we only listen to kFileSystemTypeTemporary; it should be fine |
| // to add other filesystem types as needed. |
| context_ = context; |
| base::Closure task = base::Bind( |
| &storage::SandboxFileSystemBackendDelegate::AddFileUpdateObserver, |
| base::Unretained(context_->sandbox_delegate()), |
| storage::kFileSystemTypeTemporary, base::Unretained(this), |
| base::RetainedRef( |
| BrowserThread::GetTaskRunnerForThread(BrowserThread::UI))); |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task); |
| } |
| |
| CHECK_EQ(context, context_) << "Multiprofile is not implemented"; |
| |
| observers_.AddObserver(observer); |
| } |
| |
| void RemoveObserver(FileUpdateObserver* observer) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| observers_.RemoveObserver(observer); |
| } |
| |
| // FileUpdateObserver overrides: |
| void OnStartUpdate(const FileSystemURL& url) override { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| for (auto& observer : observers_) |
| observer.OnStartUpdate(url); |
| } |
| void OnUpdate(const FileSystemURL& url, int64_t delta) override { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| for (auto& observer : observers_) |
| observer.OnUpdate(url, delta); |
| } |
| void OnEndUpdate(const FileSystemURL& url) override { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| for (auto& observer : observers_) |
| observer.OnEndUpdate(url); |
| } |
| |
| private: |
| FileSystemContext* context_ = nullptr; |
| base::ObserverList<FileUpdateObserver> observers_; |
| DISALLOW_COPY_AND_ASSIGN(FileUpdateObserverMultiplexer); |
| }; |
| |
| static base::LazyInstance<FileUpdateObserverMultiplexer>::Leaky g_multiplexer = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| } // namespace |
| |
| TestFileapiOperationWaiter::TestFileapiOperationWaiter( |
| FileSystemContext* context) { |
| g_multiplexer.Get().AddObserver(context, this); |
| } |
| |
| TestFileapiOperationWaiter::~TestFileapiOperationWaiter() { |
| g_multiplexer.Get().RemoveObserver(this); |
| } |
| |
| void TestFileapiOperationWaiter::WaitForEndUpdate() { |
| run_loop_.Run(); |
| } |
| |
| void TestFileapiOperationWaiter::OnStartUpdate(const FileSystemURL& url) { |
| did_start_update_ = true; |
| } |
| |
| void TestFileapiOperationWaiter::OnUpdate(const FileSystemURL& url, |
| int64_t delta) {} |
| |
| void TestFileapiOperationWaiter::OnEndUpdate(const FileSystemURL& url) { |
| run_loop_.Quit(); |
| } |
| |
| } // namespace content |