blob: d63f3d4f9acb42350c20224985305779340062ef [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/strings/strcat.h"
#include "base/test/test_mock_time_task_runner.h"
#include "components/drive/drive_notification_manager.h"
#include "components/drive/drive_notification_observer.h"
#include "components/invalidation/impl/fake_invalidation_service.h"
#include "components/invalidation/public/invalidation.h"
#include "components/invalidation/public/invalidation_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace drive {
namespace {
const invalidation::Topic kDefaultCorpusTopic = "Drive";
struct ShutdownHelper {
template <typename T>
void operator()(T* object) const {
if (object) {
object->Shutdown();
delete object;
}
}
};
class FakeDriveNotificationObserver : public DriveNotificationObserver {
public:
~FakeDriveNotificationObserver() override = default;
// DriveNotificationObserver overrides
void OnNotificationReceived(
const std::map<std::string, int64_t>& ids) override {
notification_ids_ = ids;
}
void OnNotificationTimerFired() override {}
void OnPushNotificationEnabled(bool enabled) override {}
const std::map<std::string, int64_t> GetNotificationIds() const {
return notification_ids_;
}
void ClearNotificationIds() { notification_ids_.clear(); }
private:
std::map<std::string, int64_t> notification_ids_;
};
invalidation::Topic CreateTeamDriveInvalidationTopic(
const std::string& team_drive_id) {
return base::StrCat({"team-drive-", team_drive_id});
}
} // namespace
class DriveNotificationManagerTest : public testing::Test {
protected:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
base::TestMockTimeTaskRunner::Type::kBoundToThread);
fake_invalidation_service_ =
std::make_unique<invalidation::FakeInvalidationService>();
drive_notification_observer_ =
std::make_unique<FakeDriveNotificationObserver>();
// Can't use make_unique with a custom deleter.
drive_notification_manager_.reset(
new DriveNotificationManager(fake_invalidation_service_.get()));
drive_notification_manager_->AddObserver(
drive_notification_observer_.get());
}
void TearDown() override {
drive_notification_manager_->RemoveObserver(
drive_notification_observer_.get());
}
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<invalidation::FakeInvalidationService>
fake_invalidation_service_;
std::unique_ptr<FakeDriveNotificationObserver> drive_notification_observer_;
std::unique_ptr<DriveNotificationManager, ShutdownHelper>
drive_notification_manager_;
};
TEST_F(DriveNotificationManagerTest, RegisterTeamDrives) {
// By default, we should have registered for default corpus notifications on
// initialization.
auto subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
// TODO(crbug.com/1029698): replace invalidation::TopicMap with
// invalidation::TopicSet once |is_public| become the part of dedicated
// invalidation::Topic struct. This should simplify this test.
invalidation::TopicMap expected_topics;
expected_topics.emplace(kDefaultCorpusTopic,
invalidation::TopicMetadata{/*is_public=*/false});
EXPECT_EQ(expected_topics, subscribed_topics);
const std::string team_drive_id_1 = "td_id_1";
const auto team_drive_1_topic =
CreateTeamDriveInvalidationTopic(team_drive_id_1);
// Add the team drive
drive_notification_manager_->UpdateTeamDriveIds({team_drive_id_1}, {});
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
expected_topics.emplace(team_drive_1_topic,
invalidation::TopicMetadata{/*is_public=*/true});
EXPECT_EQ(expected_topics, subscribed_topics);
// Remove the team drive.
drive_notification_manager_->UpdateTeamDriveIds({}, {team_drive_id_1});
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
expected_topics.erase(team_drive_1_topic);
EXPECT_EQ(expected_topics, subscribed_topics);
const std::string team_drive_id_2 = "td_id_2";
const auto team_drive_2_topic =
CreateTeamDriveInvalidationTopic(team_drive_id_2);
// Add two team drives.
drive_notification_manager_->UpdateTeamDriveIds(
{team_drive_id_1, team_drive_id_2}, {});
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
expected_topics.emplace(team_drive_1_topic,
invalidation::TopicMetadata{/*is_public=*/true});
expected_topics.emplace(team_drive_2_topic,
invalidation::TopicMetadata{/*is_public=*/true});
EXPECT_EQ(expected_topics, subscribed_topics);
// Remove the first team drive.
drive_notification_manager_->UpdateTeamDriveIds({}, {team_drive_id_1});
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
expected_topics.erase(team_drive_1_topic);
EXPECT_EQ(expected_topics, subscribed_topics);
// Remove a team drive that doesn't exists with no changes.
const std::string team_drive_id_3 = "td_id_3";
drive_notification_manager_->UpdateTeamDriveIds({}, {team_drive_id_3});
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
EXPECT_EQ(expected_topics, subscribed_topics);
}
TEST_F(DriveNotificationManagerTest, TestBatchInvalidation) {
// By default we'll be registered for the default change notification.
// Emitting an invalidation should not call our observer until the timer
// expires.
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(kDefaultCorpusTopic, 1, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
task_runner_->FastForwardBy(base::Seconds(30));
// Default corpus is has the id "" when sent to observers.
// DriveNotificationManager::NotifyObserversToUpdate increases the
// invalidation version by 1 before sending it to observers.
std::map<std::string, int64_t> expected_ids = {{"", 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
drive_notification_observer_->ClearNotificationIds();
// Register a team drive for notifications.
const std::string team_drive_id_1 = "td_id_1";
const auto team_drive_1_topic =
CreateTeamDriveInvalidationTopic(team_drive_id_1);
drive_notification_manager_->UpdateTeamDriveIds({team_drive_id_1}, {});
// Emit invalidation for default corpus, should not emit a team drive
// invalidation.
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(kDefaultCorpusTopic, 1, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
task_runner_->FastForwardBy(base::Seconds(30));
// Default corpus is has the id "" when sent to observers.
expected_ids = {{"", 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
drive_notification_observer_->ClearNotificationIds();
// Emit team drive invalidation
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(team_drive_1_topic, 2, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
task_runner_->FastForwardBy(base::Seconds(30));
expected_ids = {{team_drive_id_1, 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
drive_notification_observer_->ClearNotificationIds();
// Emit both default corpus and team drive.
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(kDefaultCorpusTopic, 1, ""));
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(team_drive_1_topic, 2, ""));
// Emit with an earlier version. This should be ignored.
fake_invalidation_service_->EmitInvalidationForTest(
invalidation::Invalidation(kDefaultCorpusTopic, 0, ""));
EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
task_runner_->FastForwardBy(base::Seconds(30));
expected_ids = {{"", 2}, {team_drive_id_1, 2}};
EXPECT_EQ(expected_ids, drive_notification_observer_->GetNotificationIds());
}
TEST_F(DriveNotificationManagerTest, UnregisterOnNoObservers) {
// By default, we should have registered for default corpus notifications on
// initialization.
auto subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
// TODO(crbug.com/1029698): replace invalidation::TopicMap with
// invalidation::TopicSet once |is_public| become the part of dedicated
// invalidation::Topic struct.
invalidation::TopicMap expected_topics;
expected_topics.emplace(kDefaultCorpusTopic,
invalidation::TopicMetadata{/*is_public=*/false});
EXPECT_EQ(expected_topics, subscribed_topics);
// Stop observing drive notification manager.
drive_notification_manager_->RemoveObserver(
drive_notification_observer_.get());
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
EXPECT_EQ(invalidation::TopicMap(), subscribed_topics);
// Start observing drive notification manager again. It should subscribe to
// the previously subscried topics.
drive_notification_manager_->AddObserver(drive_notification_observer_.get());
subscribed_topics = fake_invalidation_service_->invalidator_registrar()
.GetAllSubscribedTopics();
EXPECT_EQ(expected_topics, subscribed_topics);
}
} // namespace drive