| // 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 "components/consent_auditor/consent_auditor_impl.h" |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/hash/sha1.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/time/time.h" |
| #include "components/sync/protocol/user_consent_specifics.pb.h" |
| #include "components/sync/test/fake_data_type_controller_delegate.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ArcPlayTermsOfServiceConsent = |
| sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent; |
| using AssistantActivityControlConsent = |
| sync_pb::UserConsentTypes::AssistantActivityControlConsent; |
| using SyncConsent = sync_pb::UserConsentTypes::SyncConsent; |
| using sync_pb::UserConsentSpecifics; |
| using sync_pb::UserConsentTypes; |
| using ::testing::ElementsAreArray; |
| |
| namespace consent_auditor { |
| |
| namespace { |
| |
| // Fake product locate for testing. |
| constexpr char kCurrentAppLocale[] = "en-US"; |
| |
| // Fake Gaia ID for testing. |
| constexpr GaiaId::Literal kGaiaId("testing_gaia_id"); |
| |
| // Fake message ids. |
| constexpr std::array<int, 3> kDescriptionMessageIds = {12, 37, 42}; |
| constexpr int kConfirmationMessageId = 47; |
| |
| class FakeConsentSyncBridge : public ConsentSyncBridge { |
| public: |
| ~FakeConsentSyncBridge() override = default; |
| |
| // ConsentSyncBridge implementation. |
| void RecordConsent( |
| std::unique_ptr<sync_pb::UserConsentSpecifics> specifics) override { |
| DCHECK(specifics); |
| recorded_user_consents_.push_back(*specifics); |
| } |
| |
| base::WeakPtr<syncer::DataTypeControllerDelegate> GetControllerDelegate() |
| override { |
| return delegate_; |
| } |
| |
| // Fake methods. |
| void SetControllerDelegate( |
| base::WeakPtr<syncer::DataTypeControllerDelegate> delegate) { |
| delegate_ = delegate; |
| } |
| |
| const std::vector<UserConsentSpecifics>& GetRecordedUserConsents() const { |
| return recorded_user_consents_; |
| } |
| |
| private: |
| base::WeakPtr<syncer::DataTypeControllerDelegate> delegate_; |
| std::vector<UserConsentSpecifics> recorded_user_consents_; |
| }; |
| |
| } // namespace |
| |
| class ConsentAuditorImplTest : public testing::Test { |
| public: |
| void SetUp() override { |
| CreateConsentAuditorImpl(std::make_unique<FakeConsentSyncBridge>()); |
| } |
| |
| void CreateConsentAuditorImpl(std::unique_ptr<FakeConsentSyncBridge> bridge) { |
| consent_sync_bridge_ = bridge.get(); |
| consent_auditor_ = std::make_unique<ConsentAuditorImpl>( |
| std::move(bridge), kCurrentAppLocale, clock()); |
| } |
| |
| base::SimpleTestClock* clock() { return &test_clock_; } |
| ConsentAuditorImpl* consent_auditor() { return consent_auditor_.get(); } |
| FakeConsentSyncBridge* consent_sync_bridge() { |
| return consent_sync_bridge_.get(); |
| } |
| |
| private: |
| // Test helpers. |
| base::SimpleTestClock test_clock_; |
| raw_ptr<FakeConsentSyncBridge, DanglingUntriaged> consent_sync_bridge_ = |
| nullptr; |
| |
| // Test object to be tested. |
| std::unique_ptr<ConsentAuditorImpl> consent_auditor_; |
| }; |
| |
| TEST_F(ConsentAuditorImplTest, RecordGaiaConsentAsUserConsent) { |
| base::Time now; |
| ASSERT_TRUE(base::Time::FromUTCString("2017-11-14T15:15:38Z", &now)); |
| clock()->SetNow(now); |
| |
| SyncConsent sync_consent; |
| sync_consent.set_status(UserConsentTypes::GIVEN); |
| sync_consent.set_confirmation_grd_id(kConfirmationMessageId); |
| for (int id : kDescriptionMessageIds) { |
| sync_consent.add_description_grd_ids(id); |
| } |
| consent_auditor()->RecordSyncConsent(kGaiaId, sync_consent); |
| |
| std::vector<UserConsentSpecifics> consents = |
| consent_sync_bridge()->GetRecordedUserConsents(); |
| ASSERT_EQ(1U, consents.size()); |
| const UserConsentSpecifics& consent = consents[0]; |
| |
| EXPECT_EQ(now.since_origin().InMicroseconds(), |
| consent.client_consent_time_usec()); |
| EXPECT_EQ(kGaiaId.ToString(), consent.obfuscated_gaia_id()); |
| EXPECT_EQ(kCurrentAppLocale, consent.locale()); |
| |
| EXPECT_TRUE(consent.has_sync_consent()); |
| const SyncConsent& actual_sync_consent = consent.sync_consent(); |
| EXPECT_THAT(actual_sync_consent.description_grd_ids(), |
| ElementsAreArray(kDescriptionMessageIds)); |
| EXPECT_EQ(actual_sync_consent.confirmation_grd_id(), kConfirmationMessageId); |
| } |
| |
| TEST_F(ConsentAuditorImplTest, RecordArcPlayConsentRevocation) { |
| base::Time now; |
| ASSERT_TRUE(base::Time::FromUTCString("2017-11-14T15:15:38Z", &now)); |
| clock()->SetNow(now); |
| |
| ArcPlayTermsOfServiceConsent play_consent; |
| play_consent.set_status(UserConsentTypes::NOT_GIVEN); |
| play_consent.set_confirmation_grd_id(kConfirmationMessageId); |
| for (int id : kDescriptionMessageIds) { |
| play_consent.add_description_grd_ids(id); |
| } |
| play_consent.set_consent_flow(ArcPlayTermsOfServiceConsent::SETTING_CHANGE); |
| consent_auditor()->RecordArcPlayConsent(kGaiaId, play_consent); |
| |
| const std::vector<UserConsentSpecifics> consents = |
| consent_sync_bridge()->GetRecordedUserConsents(); |
| ASSERT_EQ(1U, consents.size()); |
| const UserConsentSpecifics& consent = consents[0]; |
| |
| EXPECT_EQ(kGaiaId.ToString(), consent.obfuscated_gaia_id()); |
| EXPECT_EQ(kCurrentAppLocale, consent.locale()); |
| |
| EXPECT_TRUE(consent.has_arc_play_terms_of_service_consent()); |
| const ArcPlayTermsOfServiceConsent& actual_play_consent = |
| consent.arc_play_terms_of_service_consent(); |
| EXPECT_EQ(UserConsentTypes::NOT_GIVEN, actual_play_consent.status()); |
| EXPECT_EQ(ArcPlayTermsOfServiceConsent::SETTING_CHANGE, |
| actual_play_consent.consent_flow()); |
| EXPECT_THAT(actual_play_consent.description_grd_ids(), |
| ElementsAreArray(kDescriptionMessageIds)); |
| EXPECT_EQ(kConfirmationMessageId, actual_play_consent.confirmation_grd_id()); |
| } |
| |
| TEST_F(ConsentAuditorImplTest, RecordArcPlayConsent) { |
| base::Time now; |
| ASSERT_TRUE(base::Time::FromUTCString("2017-11-14T15:15:38Z", &now)); |
| clock()->SetNow(now); |
| |
| ArcPlayTermsOfServiceConsent play_consent; |
| play_consent.set_status(UserConsentTypes::GIVEN); |
| play_consent.set_confirmation_grd_id(kConfirmationMessageId); |
| play_consent.set_consent_flow(ArcPlayTermsOfServiceConsent::SETUP); |
| |
| // Verify the hash: 2fd4e1c6 7a2d28fc ed849ee1 bb76e739 1b93eb12. |
| const uint8_t play_tos_hash[] = {0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, |
| 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76, |
| 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12}; |
| play_consent.set_play_terms_of_service_hash(std::string( |
| reinterpret_cast<const char*>(play_tos_hash), base::kSHA1Length)); |
| play_consent.set_play_terms_of_service_text_length(7); |
| |
| consent_auditor()->RecordArcPlayConsent(kGaiaId, play_consent); |
| |
| const std::vector<UserConsentSpecifics> consents = |
| consent_sync_bridge()->GetRecordedUserConsents(); |
| ASSERT_EQ(1U, consents.size()); |
| const UserConsentSpecifics& consent = consents[0]; |
| |
| EXPECT_EQ(kGaiaId.ToString(), consent.obfuscated_gaia_id()); |
| EXPECT_EQ(kCurrentAppLocale, consent.locale()); |
| |
| EXPECT_TRUE(consent.has_arc_play_terms_of_service_consent()); |
| const ArcPlayTermsOfServiceConsent& actual_play_consent = |
| consent.arc_play_terms_of_service_consent(); |
| |
| EXPECT_EQ(7, actual_play_consent.play_terms_of_service_text_length()); |
| EXPECT_EQ(std::string(reinterpret_cast<const char*>(play_tos_hash), |
| base::kSHA1Length), |
| actual_play_consent.play_terms_of_service_hash()); |
| |
| EXPECT_EQ(kConfirmationMessageId, actual_play_consent.confirmation_grd_id()); |
| EXPECT_EQ(ArcPlayTermsOfServiceConsent::SETUP, |
| actual_play_consent.consent_flow()); |
| EXPECT_EQ(UserConsentTypes::GIVEN, actual_play_consent.status()); |
| } |
| |
| TEST_F(ConsentAuditorImplTest, ShouldReturnSyncDelegateWhenBridgePresent) { |
| auto fake_bridge = std::make_unique<FakeConsentSyncBridge>(); |
| |
| syncer::FakeDataTypeControllerDelegate fake_delegate( |
| syncer::DataType::USER_CONSENTS); |
| auto expected_delegate_ptr = fake_delegate.GetWeakPtr(); |
| DCHECK(expected_delegate_ptr); |
| fake_bridge->SetControllerDelegate(expected_delegate_ptr); |
| CreateConsentAuditorImpl(std::move(fake_bridge)); |
| |
| // There is a bridge (i.e. separate sync type for consents is enabled), thus, |
| // there should be a delegate as well. |
| EXPECT_EQ(expected_delegate_ptr.get(), |
| consent_auditor()->GetControllerDelegate().get()); |
| } |
| |
| } // namespace consent_auditor |