| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/reporting/client/report_queue_configuration.h" |
| |
| #include <cstddef> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/test/task_environment.h" |
| #include "components/reporting/proto/synced/record_constants.pb.h" |
| #include "components/reporting/util/rate_limiter_interface.h" |
| #include "components/reporting/util/status.h" |
| #include "components/reporting/util/status_macros.h" |
| #include "components/reporting/util/statusor.h" |
| #include "components/reporting/util/test_support_callbacks.h" |
| #include "components/reporting/util/wrapped_rate_limiter.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::Eq; |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::WithArgs; |
| |
| namespace reporting { |
| namespace { |
| |
| constexpr char kDmToken[] = "dm_token"; |
| |
| class MockRateLimiter : public RateLimiterInterface { |
| public: |
| MOCK_METHOD(bool, Acquire, (size_t event_size), (override)); |
| }; |
| |
| class ReportQueueConfigurationTest : public ::testing::Test { |
| protected: |
| using PolicyCheckCallback = ReportQueueConfiguration::PolicyCheckCallback; |
| |
| const Destination kInvalidDestination = Destination::UNDEFINED_DESTINATION; |
| const Destination kValidDestination = Destination::UPLOAD_EVENTS; |
| const PolicyCheckCallback kValidCallback = GetSuccessfulCallback(); |
| const PolicyCheckCallback kInvalidCallback = GetInvalidCallback(); |
| |
| static PolicyCheckCallback GetSuccessfulCallback() { |
| return base::BindRepeating([]() { return Status::StatusOK(); }); |
| } |
| |
| static PolicyCheckCallback GetInvalidCallback() { |
| return base::RepeatingCallback<Status(void)>(); |
| } |
| |
| base::test::TaskEnvironment task_environment_; |
| }; |
| |
| // Tests to ensure that only valid parameters are used to generate a |
| // ReportQueueConfiguration. |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithInvalidDestination) { |
| StatusOr<std::unique_ptr<ReportQueueConfiguration>> config_result = |
| ReportQueueConfiguration::Builder({.destination = kInvalidDestination}) |
| .SetDMToken(kDmToken) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithInvalidDestinationInvalidCallback) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kInvalidDestination}) |
| .SetPolicyCheckCallback(kInvalidCallback) |
| .SetDMToken(kDmToken) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithValidParams) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kValidDestination}) |
| .SetDMToken(kDmToken) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_OK(config_result) << config_result.error(); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithNoDMToken) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_OK(config_result) << config_result.error(); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithNoDMTokenInvalidDestination) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kInvalidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithNoDMTokenInvalidCallback) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kValidDestination}) |
| .SetPolicyCheckCallback(kInvalidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithNoDMTokenInvalidDestinationInvalidCallback) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = kInvalidDestination}) |
| .SetPolicyCheckCallback(kInvalidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithDeviceEventType) { |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kDevice, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_OK(config_result) << config_result.error(); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithUserEventType) { |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kUser, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_OK(config_result) << config_result.error(); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithEventTypeInvalidDestination) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.event_type = EventType::kDevice, |
| .destination = kInvalidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithEventTypeInvalidCallback) { |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kDevice, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kInvalidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithEventTypeInvalidReservedSpace) { |
| auto config_result = |
| ReportQueueConfiguration::Create({.event_type = EventType::kDevice, |
| .destination = kValidDestination, |
| .reserved_space = -1L}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, UsesProvidedPolicyCheckCallback) { |
| const Destination destination = Destination::UPLOAD_EVENTS; |
| |
| testing::MockFunction<Status(void)> mock_handler; |
| EXPECT_CALL(mock_handler, Call()).WillOnce(Return(Status::StatusOK())); |
| |
| auto config_result = |
| ReportQueueConfiguration::Create({.destination = destination}) |
| .SetDMToken(kDmToken) |
| .SetPolicyCheckCallback( |
| base::BindRepeating(&::testing::MockFunction<Status(void)>::Call, |
| base::Unretained(&mock_handler))) |
| .Build(); |
| ASSERT_OK(config_result) << config_result.error(); |
| |
| const auto config = std::move(config_result.value()); |
| EXPECT_OK(config->CheckPolicy()); |
| EXPECT_THAT(config->reserved_space(), Eq(0L)); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithRateLimiter) { |
| auto rate_limiter = std::make_unique<MockRateLimiter>(); |
| auto* const mock_rate_limiter = rate_limiter.get(); |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kDevice, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetRateLimiter(std::move(rate_limiter)) |
| .Build(); |
| ASSERT_TRUE(config_result.has_value()) << config_result.error(); |
| const auto config = std::move(config_result.value()); |
| const auto is_event_allowed_cb = config->is_event_allowed_cb(); |
| ASSERT_TRUE(is_event_allowed_cb); |
| |
| EXPECT_CALL(*mock_rate_limiter, Acquire(_)).WillOnce(Return(false)); |
| test::TestEvent<bool> rejected_event; |
| is_event_allowed_cb.Run(/*event_size=*/1000, rejected_event.cb()); |
| EXPECT_FALSE(rejected_event.result()); |
| |
| EXPECT_CALL(*mock_rate_limiter, Acquire(_)).WillOnce(Return(true)); |
| test::TestEvent<bool> acquired_event; |
| is_event_allowed_cb.Run(/*event_size=*/1, acquired_event.cb()); |
| EXPECT_TRUE(acquired_event.result()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithRateLimiterAfterRemoval) { |
| auto rate_limiter = std::make_unique<MockRateLimiter>(); |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kDevice, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetRateLimiter(std::move(rate_limiter)) |
| .Build(); |
| ASSERT_TRUE(config_result.has_value()) << config_result.error(); |
| auto config = std::move(config_result.value()); |
| const auto is_event_allowed_cb = config->is_event_allowed_cb(); |
| ASSERT_TRUE(is_event_allowed_cb); |
| config.reset(); |
| |
| test::TestEvent<bool> rejected_event; |
| is_event_allowed_cb.Run(/*event_size=*/1000, rejected_event.cb()); |
| EXPECT_FALSE(rejected_event.result()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithReservedSpaceSetting) { |
| static constexpr int64_t kReservedSpace = 12345L; |
| auto config_result = |
| ReportQueueConfiguration::Create({.event_type = EventType::kDevice, |
| .destination = kValidDestination, |
| .reserved_space = kReservedSpace}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .Build(); |
| ASSERT_TRUE(config_result.has_value()) << config_result.error(); |
| |
| const auto config = std::move(config_result.value()); |
| EXPECT_THAT(config->reserved_space(), Eq(kReservedSpace)); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithSource) { |
| SourceInfo source_info; |
| source_info.set_source(SourceInfo::ASH); |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kUser, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetSourceInfo(source_info) |
| .Build(); |
| ASSERT_TRUE(config_result.has_value()) << config_result.error(); |
| |
| const auto config = std::move(config_result.value()); |
| ASSERT_TRUE(config->source_info().has_value()); |
| EXPECT_THAT(config->source_info().value().source(), Eq(source_info.source())); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithUnsetSource) { |
| SourceInfo source_info; |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kUser, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetSourceInfo(std::move(source_info)) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, ValidateConfigurationWithSourceVersion) { |
| SourceInfo source_info; |
| source_info.set_source(SourceInfo::ASH); |
| source_info.set_source_version("1.0.0"); |
| auto config_result = |
| ReportQueueConfiguration::Create( |
| {.event_type = EventType::kUser, .destination = kValidDestination}) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetSourceInfo(source_info) |
| .Build(); |
| ASSERT_TRUE(config_result.has_value()) << config_result.error(); |
| |
| const auto config = std::move(config_result.value()); |
| ASSERT_TRUE(config->source_info().has_value()); |
| const auto config_source_info = config->source_info().value(); |
| EXPECT_THAT(config_source_info.source(), Eq(source_info.source())); |
| EXPECT_THAT(config_source_info.source_version(), |
| StrEq(source_info.source_version())); |
| } |
| |
| TEST_F(ReportQueueConfigurationTest, |
| ValidateConfigurationWithSourceVersionAndInvalidSource) { |
| SourceInfo source_info; |
| source_info.set_source(SourceInfo::SOURCE_UNSPECIFIED); |
| source_info.set_source_version("1.0.0"); |
| auto config_result = |
| ReportQueueConfiguration::Create({ |
| .event_type = EventType::kUser, |
| .destination = kValidDestination, |
| }) |
| .SetPolicyCheckCallback(kValidCallback) |
| .SetSourceInfo(std::move(source_info)) |
| .Build(); |
| EXPECT_FALSE(config_result.has_value()); |
| } |
| } // namespace |
| } // namespace reporting |