fcm_handler_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Copyright 2020 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/sync/invalidations/fcm_handler.h"
  5. #include <set>
  6. #include <string>
  7. #include <utility>
  8. #include "base/files/file_path.h"
  9. #include "base/test/scoped_feature_list.h"
  10. #include "base/test/task_environment.h"
  11. #include "components/gcm_driver/fake_gcm_driver.h"
  12. #include "components/gcm_driver/gcm_driver.h"
  13. #include "components/gcm_driver/instance_id/instance_id.h"
  14. #include "components/gcm_driver/instance_id/instance_id_driver.h"
  15. #include "components/sync/base/features.h"
  16. #include "components/sync/invalidations/fcm_registration_token_observer.h"
  17. #include "components/sync/invalidations/invalidations_listener.h"
  18. #include "google_apis/gcm/engine/account_mapping.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. using instance_id::InstanceID;
  22. using testing::_;
  23. using testing::Invoke;
  24. using testing::NiceMock;
  25. using testing::Return;
  26. using testing::WithArg;
  27. namespace syncer {
  28. namespace {
  29. const char kDefaultSenderId[] = "fake_sender_id";
  30. const char kSyncInvalidationsAppId[] = "com.google.chrome.sync.invalidations";
  31. const int kTokenValidationPeriodMinutesDefault = 60 * 24;
  32. class MockInstanceID : public InstanceID {
  33. public:
  34. MockInstanceID() : InstanceID("app_id", /*gcm_driver=*/nullptr) {}
  35. ~MockInstanceID() override = default;
  36. MOCK_METHOD(void, GetID, (GetIDCallback callback), (override));
  37. MOCK_METHOD(void,
  38. GetCreationTime,
  39. (GetCreationTimeCallback callback),
  40. (override));
  41. MOCK_METHOD(void,
  42. GetToken,
  43. (const std::string& authorized_entity,
  44. const std::string& scope,
  45. base::TimeDelta time_to_live,
  46. std::set<Flags> flags,
  47. GetTokenCallback callback),
  48. (override));
  49. MOCK_METHOD(void,
  50. ValidateToken,
  51. (const std::string& authorized_entity,
  52. const std::string& scope,
  53. const std::string& token,
  54. ValidateTokenCallback callback),
  55. (override));
  56. protected:
  57. MOCK_METHOD(void,
  58. DeleteTokenImpl,
  59. (const std::string& authorized_entity,
  60. const std::string& scope,
  61. DeleteTokenCallback callback),
  62. (override));
  63. MOCK_METHOD(void, DeleteIDImpl, (DeleteIDCallback callback), (override));
  64. };
  65. class MockInstanceIDDriver : public instance_id::InstanceIDDriver {
  66. public:
  67. MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
  68. ~MockInstanceIDDriver() override = default;
  69. MOCK_METHOD(InstanceID*,
  70. GetInstanceID,
  71. (const std::string& app_id),
  72. (override));
  73. MOCK_METHOD(void, RemoveInstanceID, (const std::string& app_id), (override));
  74. MOCK_METHOD(bool,
  75. ExistsInstanceID,
  76. (const std::string& app_id),
  77. (const override));
  78. };
  79. class MockListener : public InvalidationsListener {
  80. public:
  81. MOCK_METHOD(void,
  82. OnInvalidationReceived,
  83. (const std::string& payload),
  84. (override));
  85. };
  86. class MockTokenObserver : public FCMRegistrationTokenObserver {
  87. public:
  88. MOCK_METHOD(void, OnFCMRegistrationTokenChanged, (), (override));
  89. };
  90. class FCMHandlerTest : public testing::Test {
  91. public:
  92. FCMHandlerTest()
  93. : fcm_handler_(&fake_gcm_driver_,
  94. &mock_instance_id_driver_,
  95. kDefaultSenderId,
  96. kSyncInvalidationsAppId) {
  97. // This is called in the FCMHandler.
  98. ON_CALL(mock_instance_id_driver_, GetInstanceID(kSyncInvalidationsAppId))
  99. .WillByDefault(Return(&mock_instance_id_));
  100. override_features_.InitWithFeatures(
  101. /*enabled_features=*/{kSyncSendInterestedDataTypes,
  102. kUseSyncInvalidations},
  103. /*disabled_features=*/{});
  104. }
  105. protected:
  106. base::test::SingleThreadTaskEnvironment task_environment_{
  107. base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
  108. base::test::ScopedFeatureList override_features_;
  109. gcm::FakeGCMDriver fake_gcm_driver_;
  110. NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
  111. NiceMock<MockInstanceID> mock_instance_id_;
  112. FCMHandler fcm_handler_;
  113. };
  114. TEST_F(FCMHandlerTest, ShouldReturnValidToken) {
  115. // Check that the handler gets the token through GetToken.
  116. EXPECT_CALL(mock_instance_id_, GetToken)
  117. .WillOnce(
  118. WithArg<4>(Invoke([this](InstanceID::GetTokenCallback callback) {
  119. EXPECT_TRUE(fcm_handler_.IsWaitingForToken());
  120. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  121. })));
  122. fcm_handler_.StartListening();
  123. EXPECT_EQ("token", fcm_handler_.GetFCMRegistrationToken());
  124. EXPECT_FALSE(fcm_handler_.IsWaitingForToken());
  125. }
  126. TEST_F(FCMHandlerTest, ShouldPropagatePayloadToListener) {
  127. const std::string kPayloadValue = "some_payload";
  128. NiceMock<MockListener> mock_listener;
  129. fcm_handler_.AddListener(&mock_listener);
  130. gcm::IncomingMessage gcm_message;
  131. gcm_message.raw_data = kPayloadValue;
  132. EXPECT_CALL(mock_listener, OnInvalidationReceived(kPayloadValue));
  133. fcm_handler_.OnMessage(kSyncInvalidationsAppId, gcm_message);
  134. fcm_handler_.RemoveListener(&mock_listener);
  135. }
  136. TEST_F(FCMHandlerTest, ShouldNotifyOnTokenChange) {
  137. NiceMock<MockTokenObserver> mock_token_observer;
  138. fcm_handler_.AddTokenObserver(&mock_token_observer);
  139. // Check that the handler gets the token through GetToken.
  140. ON_CALL(mock_instance_id_, GetToken)
  141. .WillByDefault(
  142. WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  143. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  144. })));
  145. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged());
  146. fcm_handler_.StartListening();
  147. fcm_handler_.RemoveTokenObserver(&mock_token_observer);
  148. }
  149. TEST_F(FCMHandlerTest, ShouldScheduleTokenValidationAndActOnNewToken) {
  150. NiceMock<MockTokenObserver> mock_token_observer;
  151. fcm_handler_.AddTokenObserver(&mock_token_observer);
  152. // Check that the handler gets the token through GetToken and notifies the
  153. // observer.
  154. EXPECT_CALL(mock_instance_id_, GetToken)
  155. .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  156. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  157. })));
  158. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged()).Times(1);
  159. fcm_handler_.StartListening();
  160. // Adjust the time and check that validation will happen in time.
  161. // The old token is invalid, so token observer should be informed.
  162. task_environment_.FastForwardBy(
  163. base::Minutes(kTokenValidationPeriodMinutesDefault) - base::Seconds(1));
  164. // When it is time, validation happens.
  165. EXPECT_CALL(mock_instance_id_, GetToken)
  166. .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  167. std::move(callback).Run("new token", InstanceID::Result::SUCCESS);
  168. })));
  169. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged()).Times(1);
  170. task_environment_.FastForwardBy(base::Seconds(1));
  171. fcm_handler_.RemoveTokenObserver(&mock_token_observer);
  172. }
  173. TEST_F(FCMHandlerTest, ShouldScheduleTokenValidationAndNotActOnSameToken) {
  174. NiceMock<MockTokenObserver> mock_token_observer;
  175. fcm_handler_.AddTokenObserver(&mock_token_observer);
  176. // Check that the handler gets the token through GetToken and notifies the
  177. // observer.
  178. EXPECT_CALL(mock_instance_id_, GetToken)
  179. .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  180. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  181. })));
  182. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged()).Times(1);
  183. fcm_handler_.StartListening();
  184. // Adjust the time and check that validation will happen in time.
  185. // The old token is valid, so token observer should not be informed.
  186. task_environment_.FastForwardBy(
  187. base::Minutes(kTokenValidationPeriodMinutesDefault) - base::Seconds(1));
  188. // When it is time, validation happens.
  189. EXPECT_CALL(mock_instance_id_, GetToken)
  190. .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  191. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  192. })));
  193. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged()).Times(0);
  194. task_environment_.FastForwardBy(base::Seconds(1));
  195. fcm_handler_.RemoveTokenObserver(&mock_token_observer);
  196. }
  197. TEST_F(FCMHandlerTest, ShouldClearTokenOnStopListeningPermanently) {
  198. // Check that the handler gets the token through GetToken.
  199. EXPECT_CALL(mock_instance_id_, GetToken)
  200. .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  201. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  202. })));
  203. fcm_handler_.StartListening();
  204. NiceMock<MockTokenObserver> mock_token_observer;
  205. fcm_handler_.AddTokenObserver(&mock_token_observer);
  206. EXPECT_CALL(mock_instance_id_driver_,
  207. ExistsInstanceID(kSyncInvalidationsAppId))
  208. .WillOnce(Return(true));
  209. // Token should be cleared when StopListeningPermanently() is called.
  210. EXPECT_CALL(mock_token_observer, OnFCMRegistrationTokenChanged());
  211. fcm_handler_.StopListeningPermanently();
  212. EXPECT_EQ("", fcm_handler_.GetFCMRegistrationToken());
  213. fcm_handler_.RemoveTokenObserver(&mock_token_observer);
  214. }
  215. TEST_F(FCMHandlerTest, ShouldReplayIncomingMessagesOnAddingListener) {
  216. const std::string kPayloadValue1 = "payload_1";
  217. const std::string kPayloadValue2 = "payload_2";
  218. gcm::IncomingMessage gcm_message;
  219. gcm_message.raw_data = kPayloadValue1;
  220. fcm_handler_.OnMessage(kSyncInvalidationsAppId, gcm_message);
  221. gcm_message.raw_data = kPayloadValue2;
  222. fcm_handler_.OnMessage(kSyncInvalidationsAppId, gcm_message);
  223. NiceMock<MockListener> mock_listener;
  224. EXPECT_CALL(mock_listener, OnInvalidationReceived(kPayloadValue1));
  225. EXPECT_CALL(mock_listener, OnInvalidationReceived(kPayloadValue2));
  226. fcm_handler_.AddListener(&mock_listener);
  227. // Adding the same listener twice should have no effect.
  228. fcm_handler_.AddListener(&mock_listener);
  229. fcm_handler_.RemoveListener(&mock_listener);
  230. }
  231. TEST_F(FCMHandlerTest, ShouldLimitIncomingMessagesForReplay) {
  232. gcm::IncomingMessage gcm_message;
  233. gcm_message.raw_data = "payload";
  234. for (size_t i = 0; i < 100; ++i) {
  235. fcm_handler_.OnMessage(kSyncInvalidationsAppId, gcm_message);
  236. }
  237. NiceMock<MockListener> mock_listener;
  238. EXPECT_CALL(mock_listener, OnInvalidationReceived).Times(5);
  239. fcm_handler_.AddListener(&mock_listener);
  240. fcm_handler_.RemoveListener(&mock_listener);
  241. }
  242. TEST_F(FCMHandlerTest, ShouldClearLastIncomingMessagesOnStopListening) {
  243. EXPECT_CALL(mock_instance_id_, GetToken)
  244. .WillRepeatedly(
  245. WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
  246. std::move(callback).Run("token", InstanceID::Result::SUCCESS);
  247. })));
  248. fcm_handler_.StartListening();
  249. gcm::IncomingMessage gcm_message;
  250. gcm_message.raw_data = "payload";
  251. fcm_handler_.OnMessage(kSyncInvalidationsAppId, gcm_message);
  252. fcm_handler_.StopListening();
  253. fcm_handler_.StartListening();
  254. NiceMock<MockListener> mock_listener;
  255. EXPECT_CALL(mock_listener, OnInvalidationReceived).Times(0);
  256. fcm_handler_.AddListener(&mock_listener);
  257. fcm_handler_.RemoveListener(&mock_listener);
  258. }
  259. } // namespace
  260. } // namespace syncer