blob: ca455098bb8aae5004ccb7e3a44eecc5217cc94c [file] [log] [blame]
// 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