fcm_invalidation_service_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/invalidation/impl/fcm_invalidation_service.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "base/files/file_path.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/strings/strcat.h"
  14. #include "base/test/task_environment.h"
  15. #include "base/values.h"
  16. #include "components/gcm_driver/fake_gcm_driver.h"
  17. #include "components/gcm_driver/gcm_driver.h"
  18. #include "components/gcm_driver/instance_id/instance_id.h"
  19. #include "components/gcm_driver/instance_id/instance_id_driver.h"
  20. #include "components/invalidation/impl/fake_invalidation_handler.h"
  21. #include "components/invalidation/impl/fcm_invalidation_listener.h"
  22. #include "components/invalidation/impl/fcm_network_handler.h"
  23. #include "components/invalidation/impl/fcm_sync_network_channel.h"
  24. #include "components/invalidation/impl/invalidation_prefs.h"
  25. #include "components/invalidation/impl/invalidation_service_test_template.h"
  26. #include "components/invalidation/impl/profile_identity_provider.h"
  27. #include "components/invalidation/public/topic_invalidation_map.h"
  28. #include "components/prefs/pref_registry_simple.h"
  29. #include "components/prefs/scoped_user_pref_update.h"
  30. #include "components/prefs/testing_pref_service.h"
  31. #include "components/signin/public/identity_manager/identity_test_environment.h"
  32. #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
  33. #include "services/network/public/cpp/shared_url_loader_factory.h"
  34. #include "services/network/test/test_url_loader_factory.h"
  35. #include "testing/gmock/include/gmock/gmock.h"
  36. #include "testing/gtest/include/gtest/gtest.h"
  37. using instance_id::InstanceID;
  38. using instance_id::InstanceIDDriver;
  39. using testing::_;
  40. namespace invalidation {
  41. namespace {
  42. class TestFCMSyncNetworkChannel : public FCMSyncNetworkChannel {
  43. public:
  44. void StartListening() override {}
  45. void StopListening() override {}
  46. void RequestDetailedStatus(
  47. const base::RepeatingCallback<void(base::Value::Dict)>& callback)
  48. override {}
  49. };
  50. // TODO: Make FCMInvalidationListener class abstract and explicitly make all the
  51. // methods virtual. Provide FCMInvalidationListenerImpl and
  52. // FakeFCMInvalidationListener classes that will inherit from
  53. // FCMInvalidationListener. The reason for such a change is that
  54. // FCMInvalidationService relies of FCMInvalidationListener class.
  55. class FakeFCMInvalidationListener : public FCMInvalidationListener {
  56. public:
  57. explicit FakeFCMInvalidationListener(
  58. std::unique_ptr<FCMSyncNetworkChannel> network_channel)
  59. : FCMInvalidationListener(std::move(network_channel)) {}
  60. ~FakeFCMInvalidationListener() override = default;
  61. void RequestDetailedStatus(
  62. const base::RepeatingCallback<void(base::Value::Dict)>& callback)
  63. const override {
  64. callback.Run(base::Value::Dict());
  65. }
  66. };
  67. } // namespace
  68. const char kApplicationName[] = "com.google.chrome.fcm.invalidations";
  69. const char kSenderId[] = "invalidations-sender-id";
  70. class MockInstanceID : public InstanceID {
  71. public:
  72. MockInstanceID() : InstanceID("app_id", /*gcm_driver=*/nullptr) {}
  73. ~MockInstanceID() override = default;
  74. MOCK_METHOD1(GetID, void(GetIDCallback callback));
  75. MOCK_METHOD1(GetCreationTime, void(GetCreationTimeCallback callback));
  76. MOCK_METHOD5(GetToken,
  77. void(const std::string& authorized_entity,
  78. const std::string& scope,
  79. base::TimeDelta time_to_live,
  80. std::set<Flags> flags,
  81. GetTokenCallback callback));
  82. MOCK_METHOD4(ValidateToken,
  83. void(const std::string& authorized_entity,
  84. const std::string& scope,
  85. const std::string& token,
  86. ValidateTokenCallback callback));
  87. MOCK_METHOD3(DeleteTokenImpl,
  88. void(const std::string& authorized_entity,
  89. const std::string& scope,
  90. DeleteTokenCallback callback));
  91. MOCK_METHOD1(DeleteIDImpl, void(DeleteIDCallback callback));
  92. };
  93. class MockInstanceIDDriver : public InstanceIDDriver {
  94. public:
  95. MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
  96. ~MockInstanceIDDriver() override = default;
  97. MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
  98. MOCK_METHOD1(RemoveInstanceID, void(const std::string& app_id));
  99. MOCK_CONST_METHOD1(ExistsInstanceID, bool(const std::string& app_id));
  100. };
  101. class FCMInvalidationServiceTestDelegate {
  102. public:
  103. FCMInvalidationServiceTestDelegate() {
  104. pref_service_.registry()->RegisterStringPref(
  105. prefs::kFCMInvalidationClientIDCacheDeprecated,
  106. /*default_value=*/std::string());
  107. pref_service_.registry()->RegisterDictionaryPref(
  108. prefs::kInvalidationClientIDCache);
  109. InvalidatorRegistrarWithMemory::RegisterProfilePrefs(
  110. pref_service_.registry());
  111. }
  112. ~FCMInvalidationServiceTestDelegate() = default;
  113. void CreateInvalidationService() {
  114. CreateUninitializedInvalidationService();
  115. InitializeInvalidationService();
  116. }
  117. void CreateUninitializedInvalidationService() {
  118. gcm_driver_ = std::make_unique<gcm::FakeGCMDriver>();
  119. identity_provider_ = std::make_unique<ProfileIdentityProvider>(
  120. identity_test_env_.identity_manager());
  121. mock_instance_id_driver_ =
  122. std::make_unique<testing::NiceMock<MockInstanceIDDriver>>();
  123. mock_instance_id_ = std::make_unique<testing::NiceMock<MockInstanceID>>();
  124. ON_CALL(*mock_instance_id_driver_,
  125. GetInstanceID(base::StrCat({kApplicationName, "-", kSenderId})))
  126. .WillByDefault(testing::Return(mock_instance_id_.get()));
  127. ON_CALL(*mock_instance_id_, GetID(_))
  128. .WillByDefault(testing::WithArg<0>(
  129. testing::Invoke([](InstanceID::GetIDCallback callback) {
  130. std::move(callback).Run("FakeIID");
  131. })));
  132. invalidation_service_ = std::make_unique<FCMInvalidationService>(
  133. identity_provider_.get(),
  134. base::BindRepeating(&FCMNetworkHandler::Create, gcm_driver_.get(),
  135. mock_instance_id_driver_.get()),
  136. base::BindRepeating(&PerUserTopicSubscriptionManager::Create,
  137. identity_provider_.get(), &pref_service_,
  138. &url_loader_factory_),
  139. mock_instance_id_driver_.get(), &pref_service_, kSenderId);
  140. }
  141. void InitializeInvalidationService() {
  142. fake_listener_ = new FakeFCMInvalidationListener(
  143. std::make_unique<TestFCMSyncNetworkChannel>());
  144. invalidation_service_->InitForTest(base::WrapUnique(fake_listener_.get()));
  145. }
  146. FCMInvalidationService* GetInvalidationService() {
  147. return invalidation_service_.get();
  148. }
  149. void DestroyInvalidationService() { invalidation_service_.reset(); }
  150. void TriggerOnInvalidatorStateChange(InvalidatorState state) {
  151. fake_listener_->EmitStateChangeForTest(state);
  152. }
  153. void TriggerOnIncomingInvalidation(
  154. const TopicInvalidationMap& invalidation_map) {
  155. fake_listener_->EmitSavedInvalidationsForTest(invalidation_map);
  156. }
  157. base::test::TaskEnvironment task_environment_;
  158. data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
  159. std::unique_ptr<gcm::GCMDriver> gcm_driver_;
  160. std::unique_ptr<MockInstanceIDDriver> mock_instance_id_driver_;
  161. std::unique_ptr<MockInstanceID> mock_instance_id_;
  162. signin::IdentityTestEnvironment identity_test_env_;
  163. std::unique_ptr<IdentityProvider> identity_provider_;
  164. raw_ptr<FCMInvalidationListener> fake_listener_; // Owned by the service.
  165. network::TestURLLoaderFactory url_loader_factory_;
  166. TestingPrefServiceSimple pref_service_;
  167. // The service has to be below the provider since the service keeps
  168. // a non-owned pointer to the provider.
  169. std::unique_ptr<FCMInvalidationService> invalidation_service_;
  170. };
  171. INSTANTIATE_TYPED_TEST_SUITE_P(FCMInvalidationServiceTest,
  172. InvalidationServiceTest,
  173. FCMInvalidationServiceTestDelegate);
  174. TEST(FCMInvalidationServiceTest, NotifiesAboutInstanceID) {
  175. auto delegate = std::make_unique<FCMInvalidationServiceTestDelegate>();
  176. // Set up a cached InstanceID aka client ID stored in prefs.
  177. {
  178. DictionaryPrefUpdate update(&delegate->pref_service_,
  179. prefs::kInvalidationClientIDCache);
  180. update->SetStringKey(kSenderId, "InstanceIDFromPrefs");
  181. }
  182. // Create the invalidation service, but do not initialize it yet.
  183. delegate->CreateUninitializedInvalidationService();
  184. FCMInvalidationService* invalidation_service =
  185. delegate->GetInvalidationService();
  186. ASSERT_TRUE(invalidation_service->GetInvalidatorClientId().empty());
  187. // Register a handler *before* initializing the invalidation service.
  188. FakeInvalidationHandler handler("owner_1");
  189. invalidation_service->RegisterInvalidationHandler(&handler);
  190. // Because the invalidation service hasn't been initialized, the client ID is
  191. // still empty.
  192. EXPECT_TRUE(handler.GetInvalidatorClientId().empty());
  193. // Make sure the MockInstanceID doesn't immediately provide a fresh client ID.
  194. InstanceID::GetIDCallback get_id_callback;
  195. EXPECT_CALL(*delegate->mock_instance_id_, GetID(_))
  196. .WillOnce([&](InstanceID::GetIDCallback callback) {
  197. get_id_callback = std::move(callback);
  198. });
  199. // Initialize the service. It should read the client ID from prefs.
  200. delegate->InitializeInvalidationService();
  201. // The invalidation service has requested a fresh client ID.
  202. ASSERT_FALSE(get_id_callback.is_null());
  203. // The invalidation service should have restored the client ID from prefs, and
  204. // passed it on to the handler.
  205. EXPECT_EQ(handler.GetInvalidatorClientId(), "InstanceIDFromPrefs");
  206. // Once the invalidation service receives a fresh client ID, it should notify
  207. // the handler again. (Note that in practice, the fresh ID will almost always
  208. // be identical to the cached one.)
  209. std::move(get_id_callback).Run("FreshInstanceID");
  210. EXPECT_EQ(handler.GetInvalidatorClientId(), "FreshInstanceID");
  211. // Another handler that gets registered should immediately be informed of the
  212. // client ID.
  213. FakeInvalidationHandler handler2(/*owner=*/"owner_2");
  214. invalidation_service->RegisterInvalidationHandler(&handler2);
  215. EXPECT_EQ(handler2.GetInvalidatorClientId(), "FreshInstanceID");
  216. invalidation_service->UnregisterInvalidationHandler(&handler2);
  217. invalidation_service->UnregisterInvalidationHandler(&handler);
  218. }
  219. TEST(FCMInvalidationServiceTest, ClearsInstanceIDOnSignout) {
  220. // Set up an invalidation service and make sure it generated a client ID (aka
  221. // InstanceID).
  222. auto delegate = std::make_unique<FCMInvalidationServiceTestDelegate>();
  223. delegate->CreateInvalidationService();
  224. FCMInvalidationService* invalidation_service =
  225. delegate->GetInvalidationService();
  226. ASSERT_FALSE(invalidation_service->GetInvalidatorClientId().empty());
  227. // Remove the active account (in practice, this means disabling
  228. // Sync-the-feature, or just signing out of the content are if only
  229. // Sync-the-transport was running). This should trigger deleting the
  230. // InstanceID.
  231. EXPECT_CALL(*delegate->mock_instance_id_, DeleteIDImpl(_));
  232. invalidation_service->OnActiveAccountLogout();
  233. // Also the cached InstanceID (aka ClientID) in the invalidation service
  234. // should be gone. (Right now, the invalidation service clears its cache
  235. // immediately. In the future, it might be changed to first wait for the
  236. // asynchronous DeleteID operation to complete, in which case this test will
  237. // have to be updated.)
  238. EXPECT_TRUE(invalidation_service->GetInvalidatorClientId().empty());
  239. }
  240. namespace internal {
  241. class FakeCallbackContainer {
  242. public:
  243. void FakeCallback(base::Value::Dict value) { called_ = true; }
  244. bool called_ = false;
  245. base::WeakPtrFactory<FakeCallbackContainer> weak_ptr_factory_{this};
  246. };
  247. } // namespace internal
  248. // Test that requesting for detailed status doesn't crash even if the
  249. // underlying invalidator is not initialized.
  250. TEST(FCMInvalidationServiceLoggingTest, DetailedStatusCallbacksWork) {
  251. std::unique_ptr<FCMInvalidationServiceTestDelegate> delegate(
  252. new FCMInvalidationServiceTestDelegate());
  253. delegate->CreateUninitializedInvalidationService();
  254. InvalidationService* const invalidator = delegate->GetInvalidationService();
  255. internal::FakeCallbackContainer fake_container;
  256. invalidator->RequestDetailedStatus(
  257. base::BindRepeating(&internal::FakeCallbackContainer::FakeCallback,
  258. fake_container.weak_ptr_factory_.GetWeakPtr()));
  259. EXPECT_TRUE(fake_container.called_);
  260. delegate->InitializeInvalidationService();
  261. invalidator->RequestDetailedStatus(
  262. base::BindRepeating(&internal::FakeCallbackContainer::FakeCallback,
  263. fake_container.weak_ptr_factory_.GetWeakPtr()));
  264. EXPECT_TRUE(fake_container.called_);
  265. }
  266. } // namespace invalidation