// 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/update_operation.h" #include "base/task_runner_util.h" #include "chrome/browser/chromeos/drive/file_cache.h" #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h" #include "chrome/browser/chromeos/drive/file_system_interface.h" #include "chrome/browser/drive/fake_drive_service.h" #include "google_apis/drive/gdata_wapi_parser.h" #include "google_apis/drive/test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace drive { namespace file_system { class UpdateOperationTest : public OperationTestBase { protected: virtual void SetUp() OVERRIDE { OperationTestBase::SetUp(); operation_.reset(new UpdateOperation(blocking_task_runner(), observer(), scheduler(), metadata(), cache())); } scoped_ptr operation_; }; TEST_F(UpdateOperationTest, UpdateFileByLocalId_PersistentFile) { const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); const std::string kResourceId("file:2_file_resource_id"); const std::string kMd5("3b4382ebefec6e743578c76bbd0575ce"); const base::FilePath kTestFile = temp_dir().Append(FILE_PATH_LITERAL("foo")); const std::string kTestFileContent = "I'm being uploaded! Yay!"; google_apis::test_util::WriteStringToFile(kTestFile, kTestFileContent); const std::string local_id = GetLocalId(kFilePath); EXPECT_FALSE(local_id.empty()); // Pin the file so it'll be store in "persistent" directory. FileError error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::Pin, base::Unretained(cache()), local_id), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // First store a file to cache. error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::Store, base::Unretained(cache()), local_id, kMd5, kTestFile, internal::FileCache::FILE_OPERATION_COPY), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // Add the dirty bit. error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::MarkDirty, base::Unretained(cache()), local_id), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); int64 original_changestamp = fake_service()->largest_changestamp(); // The callback will be called upon completion of UpdateFileByLocalId(). error = FILE_ERROR_FAILED; operation_->UpdateFileByLocalId( local_id, ClientContext(USER_INITIATED), UpdateOperation::RUN_CONTENT_CHECK, google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // Check that the server has received an update. EXPECT_LT(original_changestamp, fake_service()->largest_changestamp()); // Check that the file size is updated to that of the updated content. google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; scoped_ptr server_entry; fake_service()->GetResourceEntry( kResourceId, google_apis::test_util::CreateCopyResultCallback(&gdata_error, &server_entry)); test_util::RunBlockingPoolTask(); EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); EXPECT_EQ(static_cast(kTestFileContent.size()), server_entry->file_size()); // Make sure that the cache is no longer dirty. bool success = false; FileCacheEntry cache_entry; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::GetCacheEntry, base::Unretained(cache()), local_id, &cache_entry), google_apis::test_util::CreateCopyResultCallback(&success)); test_util::RunBlockingPoolTask(); ASSERT_TRUE(success); EXPECT_FALSE(cache_entry.is_dirty()); } TEST_F(UpdateOperationTest, UpdateFileByLocalId_NonexistentFile) { FileError error = FILE_ERROR_OK; operation_->UpdateFileByLocalId( "nonexistent_local_id", ClientContext(USER_INITIATED), UpdateOperation::RUN_CONTENT_CHECK, google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); } TEST_F(UpdateOperationTest, UpdateFileByLocalId_Md5) { const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); const std::string kResourceId("file:2_file_resource_id"); const std::string kMd5("3b4382ebefec6e743578c76bbd0575ce"); const base::FilePath kTestFile = temp_dir().Append(FILE_PATH_LITERAL("foo")); const std::string kTestFileContent = "I'm being uploaded! Yay!"; google_apis::test_util::WriteStringToFile(kTestFile, kTestFileContent); const std::string local_id = GetLocalId(kFilePath); EXPECT_FALSE(local_id.empty()); // First store a file to cache. FileError error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::Store, base::Unretained(cache()), local_id, kMd5, kTestFile, internal::FileCache::FILE_OPERATION_COPY), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // Add the dirty bit. error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::MarkDirty, base::Unretained(cache()), local_id), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); int64 original_changestamp = fake_service()->largest_changestamp(); // The callback will be called upon completion of UpdateFileByLocalId(). error = FILE_ERROR_FAILED; operation_->UpdateFileByLocalId( local_id, ClientContext(USER_INITIATED), UpdateOperation::RUN_CONTENT_CHECK, google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // Check that the server has received an update. EXPECT_LT(original_changestamp, fake_service()->largest_changestamp()); // Check that the file size is updated to that of the updated content. google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; scoped_ptr server_entry; fake_service()->GetResourceEntry( kResourceId, google_apis::test_util::CreateCopyResultCallback(&gdata_error, &server_entry)); test_util::RunBlockingPoolTask(); EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); EXPECT_EQ(static_cast(kTestFileContent.size()), server_entry->file_size()); // Make sure that the cache is no longer dirty. bool success = false; FileCacheEntry cache_entry; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::GetCacheEntry, base::Unretained(cache()), local_id, &cache_entry), google_apis::test_util::CreateCopyResultCallback(&success)); test_util::RunBlockingPoolTask(); ASSERT_TRUE(success); EXPECT_FALSE(cache_entry.is_dirty()); // Again mark the cache file dirty. error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::MarkDirty, base::Unretained(cache()), local_id), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // And call UpdateFileByLocalId again. // In this case, although the file is marked as dirty, but the content // hasn't been changed. Thus, the actual uploading should be skipped. original_changestamp = fake_service()->largest_changestamp(); error = FILE_ERROR_FAILED; operation_->UpdateFileByLocalId( local_id, ClientContext(USER_INITIATED), UpdateOperation::RUN_CONTENT_CHECK, google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); EXPECT_EQ(original_changestamp, fake_service()->largest_changestamp()); // Make sure that the cache is no longer dirty. success = false; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::GetCacheEntry, base::Unretained(cache()), local_id, &cache_entry), google_apis::test_util::CreateCopyResultCallback(&success)); test_util::RunBlockingPoolTask(); ASSERT_TRUE(success); EXPECT_FALSE(cache_entry.is_dirty()); // Once again mark the cache file dirty. error = FILE_ERROR_FAILED; base::PostTaskAndReplyWithResult( blocking_task_runner(), FROM_HERE, base::Bind(&internal::FileCache::MarkDirty, base::Unretained(cache()), local_id), google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // And call UpdateFileByLocalId again. // In this case, NO_CONTENT_CHECK is set, so the actual uploading should run // no matter the content is changed or not. original_changestamp = fake_service()->largest_changestamp(); error = FILE_ERROR_FAILED; operation_->UpdateFileByLocalId( local_id, ClientContext(USER_INITIATED), UpdateOperation::NO_CONTENT_CHECK, google_apis::test_util::CreateCopyResultCallback(&error)); test_util::RunBlockingPoolTask(); EXPECT_EQ(FILE_ERROR_OK, error); // Make sure that the server is receiving a change. EXPECT_LE(original_changestamp, fake_service()->largest_changestamp()); } } // namespace file_system } // namespace drive