| // Copyright 2018 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 "components/drive/chromeos/about_resource_loader.h" |
| |
| #include <memory> |
| |
| #include "base/command_line.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/test/test_mock_time_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "components/drive/chromeos/drive_test_util.h" |
| #include "components/drive/chromeos/file_cache.h" |
| #include "components/drive/chromeos/resource_metadata.h" |
| #include "components/drive/event_logger.h" |
| #include "components/drive/job_scheduler.h" |
| #include "components/drive/resource_metadata_storage.h" |
| #include "components/drive/service/fake_drive_service.h" |
| #include "components/drive/service/test_util.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "services/network/test/test_network_connection_tracker.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace drive { |
| namespace internal { |
| |
| namespace { |
| |
| struct DestroyHelper { |
| template <typename T> |
| void operator()(T* object) const { |
| if (object) { |
| object->Destroy(); |
| } |
| } |
| }; |
| |
| } // namespace |
| |
| class AboutResourceLoaderTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>( |
| base::TestMockTimeTaskRunner::Type::kBoundToThread); |
| |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| |
| pref_service_ = std::make_unique<TestingPrefServiceSimple>(); |
| test_util::RegisterDrivePrefs(pref_service_->registry()); |
| |
| logger_ = std::make_unique<EventLogger>(); |
| |
| drive_service_ = std::make_unique<FakeDriveService>(); |
| ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get())); |
| |
| network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( |
| network::mojom::ConnectionType::CONNECTION_WIFI); |
| scheduler_ = std::make_unique<JobScheduler>( |
| pref_service_.get(), logger_.get(), drive_service_.get(), |
| network::TestNetworkConnectionTracker::GetInstance(), |
| task_runner_.get(), nullptr); |
| metadata_storage_.reset( |
| new ResourceMetadataStorage(temp_dir_.GetPath(), task_runner_.get())); |
| ASSERT_TRUE(metadata_storage_->Initialize()); |
| |
| cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(), |
| task_runner_.get(), |
| nullptr /* free_disk_space_getter */)); |
| ASSERT_TRUE(cache_->Initialize()); |
| |
| metadata_.reset(new ResourceMetadata(metadata_storage_.get(), cache_.get(), |
| task_runner_.get())); |
| ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); |
| |
| about_resource_loader_ = std::make_unique<AboutResourceLoader>( |
| scheduler_.get(), task_runner_->GetMockTickClock()); |
| } |
| |
| void TearDown() override { |
| // We need to manually reset the objects that implement the Destroy idiom, |
| // that deletes the object on the |task_runner_|. This is simpler than |
| // introducing custom deleters that capture the |task_runner_| and |
| // invoke RunUntilIdle(). |
| metadata_.reset(); |
| cache_.reset(); |
| metadata_storage_.reset(); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| // Adds a new file to the root directory of the service. |
| std::unique_ptr<google_apis::FileResource> AddNewFile( |
| const std::string& title) { |
| google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR; |
| std::unique_ptr<google_apis::FileResource> entry; |
| drive_service_->AddNewFile( |
| "text/plain", "content text", drive_service_->GetRootResourceId(), |
| title, |
| false, // shared_with_me |
| google_apis::test_util::CreateCopyResultCallback(&error, &entry)); |
| task_runner_->RunUntilIdle(); |
| EXPECT_EQ(google_apis::HTTP_CREATED, error); |
| return entry; |
| } |
| |
| scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| base::ScopedTempDir temp_dir_; |
| std::unique_ptr<TestingPrefServiceSimple> pref_service_; |
| std::unique_ptr<EventLogger> logger_; |
| std::unique_ptr<FakeDriveService> drive_service_; |
| std::unique_ptr<JobScheduler> scheduler_; |
| std::unique_ptr<ResourceMetadataStorage, DestroyHelper> metadata_storage_; |
| std::unique_ptr<FileCache, DestroyHelper> cache_; |
| std::unique_ptr<ResourceMetadata, DestroyHelper> metadata_; |
| std::unique_ptr<AboutResourceLoader> about_resource_loader_; |
| }; |
| |
| TEST_F(AboutResourceLoaderTest, AboutResourceLoader) { |
| google_apis::DriveApiErrorCode error[6] = {}; |
| std::unique_ptr<google_apis::AboutResource> about[6]; |
| |
| // No resource is cached at the beginning. |
| ASSERT_FALSE(about_resource_loader_->cached_about_resource()); |
| |
| // Since no resource is cached, this "Get" should trigger the update. |
| about_resource_loader_->GetAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 0, about + 0)); |
| // Since there is one in-flight update, the next "Get" just wait for it. |
| about_resource_loader_->GetAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 1, about + 1)); |
| |
| task_runner_->RunUntilIdle(); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]); |
| const int64_t first_changestamp = about[0]->largest_change_id(); |
| EXPECT_EQ(first_changestamp, about[1]->largest_change_id()); |
| ASSERT_TRUE(about_resource_loader_->cached_about_resource()); |
| EXPECT_EQ( |
| first_changestamp, |
| about_resource_loader_->cached_about_resource()->largest_change_id()); |
| |
| // Increment changestamp by 1. |
| AddNewFile("temp"); |
| // Explicitly calling UpdateAboutResource will start another API call. |
| about_resource_loader_->UpdateAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 2, about + 2)); |
| // It again waits for the in-flight UpdateAboutResoure call, even though this |
| // time there is a cached result. |
| about_resource_loader_->GetAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 3, about + 3)); |
| |
| task_runner_->RunUntilIdle(); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]); |
| EXPECT_EQ(first_changestamp + 1, about[2]->largest_change_id()); |
| EXPECT_EQ(first_changestamp + 1, about[3]->largest_change_id()); |
| EXPECT_EQ( |
| first_changestamp + 1, |
| about_resource_loader_->cached_about_resource()->largest_change_id()); |
| |
| // Increment changestamp by 1. |
| AddNewFile("temp2"); |
| // Now no UpdateAboutResource task is running. Returns the cached result. |
| about_resource_loader_->GetAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 4, about + 4)); |
| // Explicitly calling UpdateAboutResource will start another API call. |
| about_resource_loader_->UpdateAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(error + 5, about + 5)); |
| |
| task_runner_->RunUntilIdle(); |
| EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]); |
| EXPECT_EQ(first_changestamp + 1, about[4]->largest_change_id()); |
| EXPECT_EQ(first_changestamp + 2, about[5]->largest_change_id()); |
| EXPECT_EQ( |
| first_changestamp + 2, |
| about_resource_loader_->cached_about_resource()->largest_change_id()); |
| |
| EXPECT_EQ(3, drive_service_->about_resource_load_count()); |
| } |
| |
| TEST_F(AboutResourceLoaderTest, EvictCache) { |
| google_apis::DriveApiErrorCode error; |
| std::unique_ptr<google_apis::AboutResource> about; |
| |
| // No resource is cached at the beginning. |
| ASSERT_FALSE(about_resource_loader_->cached_about_resource()); |
| |
| // Since no resource is cached, this "Get" should trigger the update. |
| about_resource_loader_->GetAboutResource( |
| google_apis::test_util::CreateCopyResultCallback(&error, &about)); |
| |
| task_runner_->RunUntilIdle(); |
| EXPECT_EQ(google_apis::HTTP_SUCCESS, error); |
| |
| // Should have a cached resource. |
| ASSERT_TRUE(about_resource_loader_->cached_about_resource()); |
| |
| // Advance the timer should evict the cache. |
| task_runner_->FastForwardUntilNoTasksRemain(); |
| |
| // Cache should be evicted. |
| ASSERT_FALSE(about_resource_loader_->cached_about_resource()); |
| } |
| |
| } // namespace internal |
| } // namespace drive |