diff options
Diffstat (limited to 'chrome/browser')
12 files changed, 447 insertions, 7 deletions
diff --git a/chrome/browser/chromeos/drive/dummy_file_system.h b/chrome/browser/chromeos/drive/dummy_file_system.h index 191be66..c0fe931 100644 --- a/chrome/browser/chromeos/drive/dummy_file_system.h +++ b/chrome/browser/chromeos/drive/dummy_file_system.h @@ -58,6 +58,9 @@ class DummyFileSystem : public FileSystemInterface { const FileOperationCallback& callback) OVERRIDE {} virtual void GetFileByPath(const base::FilePath& file_path, const GetFileCallback& callback) OVERRIDE {} + virtual void GetFileByPathForSaving( + const base::FilePath& file_path, + const GetFileCallback& callback) OVERRIDE {} virtual void GetFileContentByPath( const base::FilePath& file_path, const GetFileContentInitializedCallback& initialized_callback, diff --git a/chrome/browser/chromeos/drive/fake_file_system.cc b/chrome/browser/chromeos/drive/fake_file_system.cc index 4b6f6e4..6211872 100644 --- a/chrome/browser/chromeos/drive/fake_file_system.cc +++ b/chrome/browser/chromeos/drive/fake_file_system.cc @@ -134,6 +134,11 @@ void FakeFileSystem::GetFileByPath(const base::FilePath& file_path, DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } +void FakeFileSystem::GetFileByPathForSaving(const base::FilePath& file_path, + const GetFileCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + void FakeFileSystem::GetFileContentByPath( const base::FilePath& file_path, const GetFileContentInitializedCallback& initialized_callback, diff --git a/chrome/browser/chromeos/drive/fake_file_system.h b/chrome/browser/chromeos/drive/fake_file_system.h index da005db..6b20d34 100644 --- a/chrome/browser/chromeos/drive/fake_file_system.h +++ b/chrome/browser/chromeos/drive/fake_file_system.h @@ -91,6 +91,8 @@ class FakeFileSystem : public FileSystemInterface { const FileOperationCallback& callback) OVERRIDE; virtual void GetFileByPath(const base::FilePath& file_path, const GetFileCallback& callback) OVERRIDE; + virtual void GetFileByPathForSaving(const base::FilePath& file_path, + const GetFileCallback& callback) OVERRIDE; virtual void GetFileContentByPath( const base::FilePath& file_path, const GetFileContentInitializedCallback& initialized_callback, diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc index 6b89008..b6f4e93 100644 --- a/chrome/browser/chromeos/drive/file_system.cc +++ b/chrome/browser/chromeos/drive/file_system.cc @@ -20,6 +20,7 @@ #include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h" #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" #include "chrome/browser/chromeos/drive/file_system/download_operation.h" +#include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h" #include "chrome/browser/chromeos/drive/file_system/move_operation.h" #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h" #include "chrome/browser/chromeos/drive/file_system/remove_operation.h" @@ -208,13 +209,20 @@ void FileSystem::Initialize() { cache_)); search_operation_.reset(new file_system::SearchOperation( blocking_task_runner_.get(), scheduler_, resource_metadata_)); + get_file_for_saving_operation_.reset( + new file_system::GetFileForSavingOperation(blocking_task_runner_.get(), + observer, + scheduler_, + resource_metadata_, + cache_, + temporary_file_directory_)); + sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(), observer, scheduler_, resource_metadata_, cache_, temporary_file_directory_)); - hide_hosted_docs_ = pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles); @@ -491,6 +499,14 @@ void FileSystem::GetFileByPath(const base::FilePath& file_path, callback); } +void FileSystem::GetFileByPathForSaving(const base::FilePath& file_path, + const GetFileCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + get_file_for_saving_operation_->GetFileForSaving(file_path, callback); +} + void FileSystem::GetFileContentByPath( const base::FilePath& file_path, const GetFileContentInitializedCallback& initialized_callback, diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h index 5bb1ca8..dacc522 100644 --- a/chrome/browser/chromeos/drive/file_system.h +++ b/chrome/browser/chromeos/drive/file_system.h @@ -46,6 +46,7 @@ class CopyOperation; class CreateDirectoryOperation; class CreateFileOperation; class DownloadOperation; +class GetFileForSavingOperation; class MoveOperation; class OpenFileOperation; class OperationObserver; @@ -122,6 +123,8 @@ class FileSystem : public FileSystemInterface, const FileOperationCallback& callback) OVERRIDE; virtual void GetFileByPath(const base::FilePath& file_path, const GetFileCallback& callback) OVERRIDE; + virtual void GetFileByPathForSaving(const base::FilePath& file_path, + const GetFileCallback& callback) OVERRIDE; virtual void GetFileContentByPath( const base::FilePath& file_path, const GetFileContentInitializedCallback& initialized_callback, @@ -319,6 +322,8 @@ class FileSystem : public FileSystemInterface, scoped_ptr<file_system::DownloadOperation> download_operation_; scoped_ptr<file_system::UpdateOperation> update_operation_; scoped_ptr<file_system::SearchOperation> search_operation_; + scoped_ptr<file_system::GetFileForSavingOperation> + get_file_for_saving_operation_; // Note: This should remain the last member so it'll be destroyed and // invalidate the weak pointers before any other members are destroyed. diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc new file mode 100644 index 0000000..7964876 --- /dev/null +++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc @@ -0,0 +1,146 @@ +// Copyright 2013 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 "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h" + +#include "base/bind.h" +#include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" +#include "chrome/browser/chromeos/drive/file_system/download_operation.h" +#include "chrome/browser/chromeos/drive/file_write_watcher.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace drive { +namespace file_system { + +GetFileForSavingOperation::GetFileForSavingOperation( + base::SequencedTaskRunner* blocking_task_runner, + OperationObserver* observer, + JobScheduler* scheduler, + internal::ResourceMetadata* metadata, + internal::FileCache* cache, + const base::FilePath& temporary_file_directory) + : create_file_operation_(new CreateFileOperation(blocking_task_runner, + observer, + scheduler, + metadata, + cache)), + download_operation_(new DownloadOperation(blocking_task_runner, + observer, + scheduler, + metadata, + cache, + temporary_file_directory)), + file_write_watcher_(new internal::FileWriteWatcher(observer)), + cache_(cache), + weak_ptr_factory_(this) { +} + +GetFileForSavingOperation::~GetFileForSavingOperation() { +} + +void GetFileForSavingOperation::GetFileForSaving( + const base::FilePath& file_path, + const GetFileCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + create_file_operation_->CreateFile( + file_path, + false, // error_if_already_exists + base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterCreate, + weak_ptr_factory_.GetWeakPtr(), + file_path, + callback)); +} + +void GetFileForSavingOperation::GetFileForSavingAfterCreate( + const base::FilePath& file_path, + const GetFileCallback& callback, + FileError error) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + if (error != FILE_ERROR_OK) { + callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>()); + return; + } + + download_operation_->EnsureFileDownloadedByPath( + file_path, + ClientContext(USER_INITIATED), + GetFileContentInitializedCallback(), + google_apis::GetContentCallback(), + base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterDownload, + weak_ptr_factory_.GetWeakPtr(), + callback)); +} + +void GetFileForSavingOperation::GetFileForSavingAfterDownload( + const GetFileCallback& callback, + FileError error, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + if (error != FILE_ERROR_OK) { + callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>()); + return; + } + + const std::string& resource_id = entry->resource_id(); + cache_->MarkDirtyOnUIThread( + resource_id, + base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterMarkDirty, + weak_ptr_factory_.GetWeakPtr(), + callback, + cache_path, + base::Passed(&entry))); +} + +void GetFileForSavingOperation::GetFileForSavingAfterMarkDirty( + const GetFileCallback& callback, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry, + FileError error) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + if (error != FILE_ERROR_OK) { + callback.Run(error, base::FilePath(), scoped_ptr<ResourceEntry>()); + return; + } + + const std::string& resource_id = entry->resource_id(); + file_write_watcher_->StartWatch( + cache_path, + resource_id, + base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterWatch, + weak_ptr_factory_.GetWeakPtr(), + callback, + cache_path, + base::Passed(&entry))); +} + +void GetFileForSavingOperation::GetFileForSavingAfterWatch( + const GetFileCallback& callback, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry, + bool success) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!callback.is_null()); + + if (!success) { + callback.Run(FILE_ERROR_FAILED, + base::FilePath(), scoped_ptr<ResourceEntry>()); + return; + } + + callback.Run(FILE_ERROR_OK, cache_path, entry.Pass()); +} + +} // namespace file_system +} // namespace drive diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h new file mode 100644 index 0000000..3215cc2 --- /dev/null +++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h @@ -0,0 +1,92 @@ +// Copyright 2013 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. + +#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_ +#define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/drive/file_errors.h" +#include "chrome/browser/chromeos/drive/file_system_interface.h" + +namespace base { +class FilePath; +class SequencedTaskRunner; +} // namespace base + +namespace drive { +namespace internal { +class FileCache; +class FileWriteWatcher; +class ResourceMetadata; +} // namespace internal + +class JobScheduler; +class ResourceEntry; + +namespace file_system { + +class CreateFileOperation; +class DownloadOperation; +class OperationObserver; + +// Implements GetFileForSaving() operation that prepares a local cache for +// a Drive file whose next modification is monitored and notified to the +// OperationObserver. +// TODO(kinaba): crbug.com/269424: we might want to monitor all the changes +// to the cache directory, not just the one immediately after the save dialog. +class GetFileForSavingOperation { + public: + GetFileForSavingOperation(base::SequencedTaskRunner* blocking_task_runner, + OperationObserver* observer, + JobScheduler* scheduler, + internal::ResourceMetadata* metadata, + internal::FileCache* cache, + const base::FilePath& temporary_file_directory); + ~GetFileForSavingOperation(); + + // Makes sure that |file_path| in the file system is available in the local + // cache, and marks it as dirty. The next modification to the cache file is + // watched and is automatically notified to the observer. If the entry is not + // present in the file system, it is created. + void GetFileForSaving(const base::FilePath& file_path, + const GetFileCallback& callback); + + internal::FileWriteWatcher* file_write_watcher_for_testing() { + return file_write_watcher_.get(); + } + + private: + void GetFileForSavingAfterCreate(const base::FilePath& file_path, + const GetFileCallback& callback, + FileError error); + void GetFileForSavingAfterDownload(const GetFileCallback& callback, + FileError error, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry); + void GetFileForSavingAfterMarkDirty(const GetFileCallback& callback, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry, + FileError error); + void GetFileForSavingAfterWatch(const GetFileCallback& callback, + const base::FilePath& cache_path, + scoped_ptr<ResourceEntry> entry, + bool success); + + scoped_ptr<CreateFileOperation> create_file_operation_; + scoped_ptr<DownloadOperation> download_operation_; + scoped_ptr<internal::FileWriteWatcher> file_write_watcher_; + internal::FileCache* cache_; + + // Note: This should remain the last member so it'll be destroyed and + // invalidate the weak pointers before any other members are destroyed. + base::WeakPtrFactory<GetFileForSavingOperation> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(GetFileForSavingOperation); +}; + +} // namespace file_system +} // namespace drive + +#endif // CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_ diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc new file mode 100644 index 0000000..08918e6 --- /dev/null +++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc @@ -0,0 +1,158 @@ +// Copyright 2013 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 "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h" + +#include "base/callback.h" +#include "base/file_util.h" +#include "base/files/file_path.h" +#include "base/run_loop.h" +#include "chrome/browser/chromeos/drive/drive.pb.h" +#include "chrome/browser/chromeos/drive/file_errors.h" +#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h" +#include "chrome/browser/chromeos/drive/file_write_watcher.h" +#include "chrome/browser/google_apis/test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace drive { +namespace file_system { + +namespace { + +// If OnCacheFileUploadNeededByOperation is called, records the resource ID and +// calls |quit_closure|. +class TestObserver : public OperationObserver { + public: + void set_quit_closure(const base::Closure& quit_closure) { + quit_closure_ = quit_closure; + } + + const std::string& observerd_resource_id() const { + return observed_resource_id_; + } + + // OperationObserver overrides. + virtual void OnDirectoryChangedByOperation( + const base::FilePath& path) OVERRIDE {} + + virtual void OnCacheFileUploadNeededByOperation( + const std::string& resource_id) OVERRIDE { + observed_resource_id_ = resource_id; + quit_closure_.Run(); + } + + private: + std::string observed_resource_id_; + base::Closure quit_closure_; +}; + +} // namespace + +class GetFileForSavingOperationTest : public OperationTestBase { + protected: + // FileWriteWatcher requires TYPE_IO message loop to run. + GetFileForSavingOperationTest() + : OperationTestBase(content::TestBrowserThreadBundle::IO_MAINLOOP) { + } + + virtual void SetUp() OVERRIDE { + OperationTestBase::SetUp(); + + operation_.reset(new GetFileForSavingOperation( + blocking_task_runner(), &observer_, scheduler(), metadata(), cache(), + temp_dir())); + operation_->file_write_watcher_for_testing()->DisableDelayForTesting(); + } + + TestObserver observer_; + scoped_ptr<GetFileForSavingOperation> operation_; +}; + +TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Exist) { + base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/File 1.txt")); + ResourceEntry src_entry; + ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); + + // Run the operation. + FileError error = FILE_ERROR_FAILED; + scoped_ptr<ResourceEntry> entry; + base::FilePath local_path; + operation_->GetFileForSaving( + drive_path, + google_apis::test_util::CreateCopyResultCallback( + &error, &local_path, &entry)); + test_util::RunBlockingPoolTask(); + + // Checks that the file is retrieved. + EXPECT_EQ(FILE_ERROR_OK, error); + ASSERT_TRUE(entry); + EXPECT_EQ(src_entry.resource_id(), entry->resource_id()); + + // Checks that it presents in cache and marked dirty. + bool success = false; + FileCacheEntry cache_entry; + cache()->GetCacheEntryOnUIThread( + src_entry.resource_id(), + google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry)); + test_util::RunBlockingPoolTask(); + EXPECT_TRUE(success); + EXPECT_TRUE(cache_entry.is_present()); + EXPECT_TRUE(cache_entry.is_dirty()); + + // Write something to the cache and checks that the event is reported. + { + base::RunLoop run_loop; + observer_.set_quit_closure(run_loop.QuitClosure()); + google_apis::test_util::WriteStringToFile(local_path, "hello"); + run_loop.Run(); + EXPECT_EQ(entry->resource_id(), observer_.observerd_resource_id()); + } +} + +TEST_F(GetFileForSavingOperationTest, GetFileForSaving_NotExist) { + base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/NotExist.txt")); + ResourceEntry src_entry; + ASSERT_EQ(FILE_ERROR_NOT_FOUND, + GetLocalResourceEntry(drive_path, &src_entry)); + + // Run the operation. + FileError error = FILE_ERROR_FAILED; + scoped_ptr<ResourceEntry> entry; + base::FilePath local_path; + operation_->GetFileForSaving( + drive_path, + google_apis::test_util::CreateCopyResultCallback( + &error, &local_path, &entry)); + test_util::RunBlockingPoolTask(); + + // Checks that the file is created and retrieved. + EXPECT_EQ(FILE_ERROR_OK, error); + EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); + int64 size = -1; + EXPECT_TRUE(file_util::GetFileSize(local_path, &size)); + EXPECT_EQ(0, size); +} + +TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Directory) { + base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/Directory 1")); + ResourceEntry src_entry; + ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry)); + ASSERT_TRUE(src_entry.file_info().is_directory()); + + // Run the operation. + FileError error = FILE_ERROR_FAILED; + scoped_ptr<ResourceEntry> entry; + base::FilePath local_path; + operation_->GetFileForSaving( + drive_path, + google_apis::test_util::CreateCopyResultCallback( + &error, &local_path, &entry)); + test_util::RunBlockingPoolTask(); + + // Checks that an error is returned. + EXPECT_EQ(FILE_ERROR_EXISTS, error); +} + +} // namespace file_system +} // namespace drive diff --git a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc index ad1fb09..324858d 100644 --- a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc +++ b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc @@ -39,6 +39,10 @@ void OperationTestBase::LoggingObserver::OnCacheFileUploadNeededByOperation( OperationTestBase::OperationTestBase() { } +OperationTestBase::OperationTestBase(int test_thread_bundle_options) + : thread_bundle_(test_thread_bundle_options) { +} + OperationTestBase::~OperationTestBase() { } diff --git a/chrome/browser/chromeos/drive/file_system/operation_test_base.h b/chrome/browser/chromeos/drive/file_system/operation_test_base.h index b8b26cc..4056455 100644 --- a/chrome/browser/chromeos/drive/file_system/operation_test_base.h +++ b/chrome/browser/chromeos/drive/file_system/operation_test_base.h @@ -67,6 +67,7 @@ class OperationTestBase : public testing::Test { }; OperationTestBase(); + explicit OperationTestBase(int test_thread_bundle_options); virtual ~OperationTestBase(); // testing::Test overrides. diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h index 1c5865e..4df3c8f 100644 --- a/chrome/browser/chromeos/drive/file_system_interface.h +++ b/chrome/browser/chromeos/drive/file_system_interface.h @@ -318,15 +318,23 @@ class FileSystemInterface { virtual void Unpin(const base::FilePath& file_path, const FileOperationCallback& callback) = 0; - // Gets |file_path| from the file system. The file entry represented by - // |file_path| needs to be present in in-memory representation of the file - // system in order to be retrieved. If the file is not cached, the file - // will be downloaded through GData API or Drive V2 API. + // Makes sure that |file_path| in the file system is available in the local + // cache. If the file is not cached, the file will be downloaded. The entry + // needs to be present in the file system. // - // |callback| must not be null. + // Returns the cache path and entry info to |callback|. It must not be null. virtual void GetFileByPath(const base::FilePath& file_path, const GetFileCallback& callback) = 0; + // Makes sure that |file_path| in the file system is available in the local + // cache, and mark it as dirty. The next modification to the cache file is + // watched and is automatically uploaded to the server. If the entry is not + // present in the file system, it is created. + // + // Returns the cache path and entry info to |callback|. It must not be null. + virtual void GetFileByPathForSaving(const base::FilePath& file_path, + const GetFileCallback& callback) = 0; + // Gets a file by the given |file_path|. // Calls |initialized_callback| when either: // 1) The cached file (or JSON file for hosted file) is found, or diff --git a/chrome/browser/chromeos/drive/file_write_watcher.h b/chrome/browser/chromeos/drive/file_write_watcher.h index 91c947d..13523df 100644 --- a/chrome/browser/chromeos/drive/file_write_watcher.h +++ b/chrome/browser/chromeos/drive/file_write_watcher.h @@ -46,7 +46,7 @@ class FileWriteWatcher { // 5 seconds has passed after the last write operation is detected. // // TODO(kinaba): investigate the possibility to continuously watch the whole - // cache directory. + // cache directory. http://crbug.com/269424 void StartWatch(const base::FilePath& path, const std::string& resource_id, const StartWatchCallback& callback); |