123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/invalidation/impl/fcm_network_handler.h"
- #include <memory>
- #include <string>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/files/file_path.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/mock_callback.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/task_environment.h"
- #include "base/test/test_mock_time_task_runner.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "build/build_config.h"
- #include "components/gcm_driver/gcm_driver.h"
- #include "components/gcm_driver/instance_id/instance_id.h"
- #include "components/gcm_driver/instance_id/instance_id_driver.h"
- #include "components/invalidation/impl/invalidation_switches.h"
- #include "components/invalidation/impl/status.h"
- #include "google_apis/gcm/engine/account_mapping.h"
- #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
- #include "testing/gmock/include/gmock/gmock.h"
- using base::TestMockTimeTaskRunner;
- using gcm::InstanceIDHandler;
- using instance_id::InstanceID;
- using instance_id::InstanceIDDriver;
- using testing::_;
- using testing::Eq;
- using testing::Invoke;
- using testing::StrictMock;
- using testing::WithArg;
- namespace invalidation {
- namespace {
- const char kInvalidationsAppId[] = "com.google.chrome.fcm.invalidations";
- base::Time GetDummyNow() {
- base::Time out_time;
- EXPECT_TRUE(base::Time::FromUTCString("2017-01-02T00:00:01Z", &out_time));
- return out_time;
- }
- gcm::IncomingMessage CreateValidMessage() {
- gcm::IncomingMessage message;
- message.data["payload"] = "payload";
- message.data["version"] = "42";
- message.sender_id = "private_topic";
- return message;
- }
- class MockInstanceID : public InstanceID {
- public:
- MockInstanceID() : InstanceID("app_id", /*gcm_driver=*/nullptr) {}
- ~MockInstanceID() override = default;
- MOCK_METHOD1(GetID, void(GetIDCallback callback));
- MOCK_METHOD1(GetCreationTime, void(GetCreationTimeCallback callback));
- MOCK_METHOD5(GetToken,
- void(const std::string& authorized_entity,
- const std::string& scope,
- base::TimeDelta time_to_live,
- std::set<Flags> flags,
- GetTokenCallback callback));
- MOCK_METHOD4(ValidateToken,
- void(const std::string& authorized_entity,
- const std::string& scope,
- const std::string& token,
- ValidateTokenCallback callback));
- protected:
- MOCK_METHOD3(DeleteTokenImpl,
- void(const std::string& authorized_entity,
- const std::string& scope,
- DeleteTokenCallback callback));
- MOCK_METHOD1(DeleteIDImpl, void(DeleteIDCallback callback));
- };
- class MockGCMDriver : public gcm::GCMDriver {
- public:
- MockGCMDriver()
- : GCMDriver(
- /*store_path=*/base::FilePath(),
- /*blocking_task_runner=*/nullptr) {}
- ~MockGCMDriver() override = default;
- MOCK_METHOD4(ValidateRegistration,
- void(const std::string& app_id,
- const std::vector<std::string>& sender_ids,
- const std::string& registration_id,
- ValidateRegistrationCallback callback));
- MOCK_METHOD0(OnSignedIn, void());
- MOCK_METHOD0(OnSignedOut, void());
- MOCK_METHOD1(AddConnectionObserver,
- void(gcm::GCMConnectionObserver* observer));
- MOCK_METHOD1(RemoveConnectionObserver,
- void(gcm::GCMConnectionObserver* observer));
- MOCK_METHOD0(Enable, void());
- MOCK_METHOD0(Disable, void());
- MOCK_CONST_METHOD0(GetGCMClientForTesting, gcm::GCMClient*());
- MOCK_CONST_METHOD0(IsStarted, bool());
- MOCK_CONST_METHOD0(IsConnected, bool());
- MOCK_METHOD2(GetGCMStatistics,
- void(GetGCMStatisticsCallback callback,
- ClearActivityLogs clear_logs));
- MOCK_METHOD2(SetGCMRecording,
- void(const GCMStatisticsRecordingCallback& callback,
- bool recording));
- MOCK_METHOD1(SetAccountTokens,
- void(const std::vector<gcm::GCMClient::AccountTokenInfo>&
- account_tokens));
- MOCK_METHOD1(UpdateAccountMapping,
- void(const gcm::AccountMapping& account_mapping));
- MOCK_METHOD1(RemoveAccountMapping, void(const CoreAccountId& account_id));
- MOCK_METHOD0(GetLastTokenFetchTime, base::Time());
- MOCK_METHOD1(SetLastTokenFetchTime, void(const base::Time& time));
- MOCK_METHOD0(GetInstanceIDHandlerInternal, InstanceIDHandler*());
- MOCK_METHOD2(AddHeartbeatInterval,
- void(const std::string& scope, int interval_ms));
- MOCK_METHOD1(RemoveHeartbeatInterval, void(const std::string& scope));
- protected:
- MOCK_METHOD1(EnsureStarted,
- gcm::GCMClient::Result(gcm::GCMClient::StartMode start_mode));
- MOCK_METHOD2(RegisterImpl,
- void(const std::string& app_id,
- const std::vector<std::string>& sender_ids));
- MOCK_METHOD1(UnregisterImpl, void(const std::string& app_id));
- MOCK_METHOD3(SendImpl,
- void(const std::string& app_id,
- const std::string& receiver_id,
- const gcm::OutgoingMessage& message));
- MOCK_METHOD2(RecordDecryptionFailure,
- void(const std::string& app_id,
- gcm::GCMDecryptionResult result));
- };
- class MockInstanceIDDriver : public InstanceIDDriver {
- public:
- MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
- ~MockInstanceIDDriver() override = default;
- MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
- MOCK_METHOD1(RemoveInstanceID, void(const std::string& app_id));
- MOCK_CONST_METHOD1(ExistsInstanceID, bool(const std::string& app_id));
- };
- class MockOnTokenCallback {
- public:
- FCMSyncNetworkChannel::TokenCallback Get() {
- return base::BindRepeating(&MockOnTokenCallback::Run,
- base::Unretained(this));
- }
- MOCK_METHOD1(Run, void(const std::string&));
- };
- class MockOnMessageCallback {
- public:
- FCMSyncNetworkChannel::MessageCallback Get() {
- return base::BindRepeating(&MockOnMessageCallback::Run,
- base::Unretained(this));
- }
- MOCK_METHOD4(Run,
- void(const std::string&,
- const std::string&,
- const std::string&,
- int64_t));
- };
- } // namespace
- class FCMNetworkHandlerTest : public testing::Test {
- public:
- void SetUp() override {
- // Our app handler obtains InstanceID through InstanceIDDriver. We mock
- // InstanceIDDriver and return MockInstanceID through it.
- mock_instance_id_driver_ =
- std::make_unique<StrictMock<MockInstanceIDDriver>>();
- mock_instance_id_ = std::make_unique<StrictMock<MockInstanceID>>();
- mock_gcm_driver_ = std::make_unique<StrictMock<MockGCMDriver>>();
- // This is called in FCMNetworkHandler.
- EXPECT_CALL(*mock_instance_id_driver_, GetInstanceID(kInvalidationsAppId))
- .WillRepeatedly(Return(mock_instance_id_.get()));
- }
- std::unique_ptr<FCMNetworkHandler> MakeHandler(
- const std::string& sender_id = "fake_sender_id") {
- return std::make_unique<FCMNetworkHandler>(mock_gcm_driver_.get(),
- mock_instance_id_driver_.get(),
- sender_id, kInvalidationsAppId);
- }
- std::unique_ptr<FCMNetworkHandler> MakeHandlerReadyForMessage(
- FCMSyncNetworkChannel::MessageCallback mock_on_message_callback) {
- std::unique_ptr<FCMNetworkHandler> handler = MakeHandler();
- handler->SetMessageReceiver(mock_on_message_callback);
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- handler->StartListening();
- return handler;
- }
- StrictMock<MockInstanceID>* mock_instance_id() {
- return mock_instance_id_.get();
- }
- scoped_refptr<TestMockTimeTaskRunner> CreateFakeTaskRunnerAndInjectToHandler(
- std::unique_ptr<FCMNetworkHandler>& handler) {
- scoped_refptr<TestMockTimeTaskRunner> task_runner(
- new TestMockTimeTaskRunner(GetDummyNow(), base::TimeTicks::Now()));
- auto token_validation_timer =
- std::make_unique<base::OneShotTimer>(task_runner->GetMockTickClock());
- token_validation_timer->SetTaskRunner(task_runner);
- handler->SetTokenValidationTimerForTesting(
- std::move(token_validation_timer));
- return task_runner;
- }
- private:
- base::test::SingleThreadTaskEnvironment task_environment_;
- std::unique_ptr<StrictMock<MockGCMDriver>> mock_gcm_driver_;
- std::unique_ptr<StrictMock<MockInstanceIDDriver>> mock_instance_id_driver_;
- std::unique_ptr<StrictMock<MockInstanceID>> mock_instance_id_;
- };
- class FCMNetworkHandlerTestWithTTL : public FCMNetworkHandlerTest {
- public:
- static constexpr int kTimeToLiveInSeconds = 100;
- FCMNetworkHandlerTestWithTTL() {
- base::FieldTrialParams feature_params = {
- {"time_to_live_seconds", base::NumberToString(kTimeToLiveInSeconds)}};
- override_features_.InitWithFeaturesAndParameters(
- /*enabled_features=*/
- {{switches::kSyncInstanceIDTokenTTL, feature_params},
- {switches::kPolicyInstanceIDTokenTTL, feature_params}},
- /*disabled_features=*/{});
- }
- ~FCMNetworkHandlerTestWithTTL() override = default;
- private:
- base::test::ScopedFeatureList override_features_;
- };
- TEST_F(FCMNetworkHandlerTest, ShouldPassTheTokenOnceRecieved) {
- std::unique_ptr<FCMNetworkHandler> handler = MakeHandler();
- MockOnTokenCallback mock_on_token_callback;
- handler->SetTokenReceiver(mock_on_token_callback.Get());
- // Check that the handler gets the token through GetToken.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run("token")).Times(1);
- handler->StartListening();
- }
- TEST_F(FCMNetworkHandlerTest, ShouldPassTheTokenOnceSubscribed) {
- std::unique_ptr<FCMNetworkHandler> handler = MakeHandler();
- MockOnTokenCallback mock_on_token_callback;
- // Check that the handler gets the token through GetToken.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run).Times(0);
- handler->StartListening();
- base::RunLoop().RunUntilIdle();
- EXPECT_CALL(mock_on_token_callback, Run("token")).Times(1);
- handler->SetTokenReceiver(mock_on_token_callback.Get());
- }
- TEST_F(FCMNetworkHandlerTest, ShouldNotInvokeMessageCallbackOnEmptyMessage) {
- MockOnMessageCallback mock_on_message_callback;
- gcm::IncomingMessage message;
- std::unique_ptr<FCMNetworkHandler> handler = MakeHandler();
- EXPECT_CALL(mock_on_message_callback, Run).Times(0);
- handler->SetMessageReceiver(mock_on_message_callback.Get());
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- handler->StartListening();
- handler->OnMessage(kInvalidationsAppId, gcm::IncomingMessage());
- }
- TEST_F(FCMNetworkHandlerTest, ShouldInvokeMessageCallbackOnValidMessage) {
- base::HistogramTester histogram_tester;
- MockOnMessageCallback mock_on_message_callback;
- gcm::IncomingMessage message = CreateValidMessage();
- std::unique_ptr<FCMNetworkHandler> handler =
- MakeHandlerReadyForMessage(mock_on_message_callback.Get());
- EXPECT_CALL(mock_on_message_callback, Run("payload", "private_topic", "", 42))
- .Times(1);
- EXPECT_CALL(mock_on_message_callback,
- Run("payload", "private_topic", "public_topic", 42))
- .Times(1);
- handler->OnMessage(kInvalidationsAppId, message);
- message.data["external_name"] = "public_topic";
- handler->OnMessage(kInvalidationsAppId, message);
- EXPECT_THAT(
- histogram_tester.GetAllSamples("FCMInvalidations.FCMMessageStatus"),
- testing::ElementsAre(base::Bucket(
- static_cast<int>(InvalidationParsingStatus::kSuccess) /* min */,
- 2 /* count */)));
- }
- TEST_F(FCMNetworkHandlerTest,
- ShouldNotInvokeMessageCallbackOnMessageWithEmptyVersion) {
- base::HistogramTester histogram_tester;
- MockOnMessageCallback mock_on_message_callback;
- gcm::IncomingMessage message = CreateValidMessage();
- // Clear version.
- auto it = message.data.find("version");
- message.data.erase(it);
- std::unique_ptr<FCMNetworkHandler> handler =
- MakeHandlerReadyForMessage(mock_on_message_callback.Get());
- EXPECT_CALL(mock_on_message_callback, Run).Times(0);
- handler->OnMessage(kInvalidationsAppId, message);
- EXPECT_THAT(
- histogram_tester.GetAllSamples("FCMInvalidations.FCMMessageStatus"),
- testing::ElementsAre(base::Bucket(
- static_cast<int>(InvalidationParsingStatus::kVersionEmpty) /* min */,
- 1 /* count */)));
- }
- TEST_F(FCMNetworkHandlerTest,
- ShouldNotInvokeMessageCallbackOnMessageWithInvalidVersion) {
- base::HistogramTester histogram_tester;
- MockOnMessageCallback mock_on_message_callback;
- gcm::IncomingMessage message = CreateValidMessage();
- // Set version to something that's not a valid number.
- message.data["version"] = "notanumber";
- std::unique_ptr<FCMNetworkHandler> handler =
- MakeHandlerReadyForMessage(mock_on_message_callback.Get());
- EXPECT_CALL(mock_on_message_callback, Run).Times(0);
- handler->OnMessage(kInvalidationsAppId, message);
- EXPECT_THAT(
- histogram_tester.GetAllSamples("FCMInvalidations.FCMMessageStatus"),
- testing::ElementsAre(base::Bucket(
- /*min=*/static_cast<int>(InvalidationParsingStatus::kVersionInvalid),
- /*count=*/1)));
- }
- TEST_F(FCMNetworkHandlerTest,
- ShouldNotInvokeMessageCallbackOnMessageWithEmptyPrivateTopic) {
- base::HistogramTester histogram_tester;
- MockOnMessageCallback mock_on_message_callback;
- gcm::IncomingMessage message = CreateValidMessage();
- // Clear private topic.
- message.sender_id = std::string();
- std::unique_ptr<FCMNetworkHandler> handler =
- MakeHandlerReadyForMessage(mock_on_message_callback.Get());
- EXPECT_CALL(mock_on_message_callback, Run).Times(0);
- handler->OnMessage(kInvalidationsAppId, message);
- EXPECT_THAT(
- histogram_tester.GetAllSamples("FCMInvalidations.FCMMessageStatus"),
- testing::ElementsAre(base::Bucket(
- static_cast<int>(
- InvalidationParsingStatus::kPrivateTopicEmpty) /* min */,
- 1 /* count */)));
- }
- TEST_F(FCMNetworkHandlerTest, ShouldRequestTokenImmediatellyEvenIfSaved) {
- // Setting up network handler.
- MockOnTokenCallback mock_on_token_callback;
- auto handler = MakeHandler();
- auto task_runner = CreateFakeTaskRunnerAndInjectToHandler(handler);
- handler->SetTokenReceiver(mock_on_token_callback.Get());
- // Check that after StartListening we receive the token and store it.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run("token")).Times(1);
- handler->StartListening();
- handler->StopListening();
- task_runner->RunUntilIdle();
- // Setting up another network handler.
- auto handler2 = MakeHandler();
- auto task_runner2 = CreateFakeTaskRunnerAndInjectToHandler(handler2);
- handler2->SetTokenReceiver(mock_on_token_callback.Get());
- // Check that after StartListening the token will be requested, depite we have
- // saved token.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token_new", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run("token_new")).Times(1);
- handler->StartListening();
- task_runner->RunUntilIdle();
- }
- TEST_F(FCMNetworkHandlerTest, ShouldScheduleTokenValidationAndActOnNewToken) {
- // Setting up network handler.
- MockOnTokenCallback mock_on_token_callback;
- auto handler = MakeHandler();
- auto task_runner = CreateFakeTaskRunnerAndInjectToHandler(handler);
- handler->SetTokenReceiver(mock_on_token_callback.Get());
- // Checking that after start listening the token will be requested
- // and passed to the appropriate token receiver.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(*mock_instance_id(), ValidateToken).Times(0);
- EXPECT_CALL(mock_on_token_callback, Run("token")).Times(1);
- handler->StartListening();
- testing::Mock::VerifyAndClearExpectations(mock_instance_id());
- // Adjust timers and check that validation will happen in time.
- // The old token was invalid, so token listener should be informed.
- const base::TimeDelta time_to_validation = base::Hours(24);
- task_runner->FastForwardBy(time_to_validation - base::Seconds(1));
- // But when it is time, validation happens.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token_new", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run("token_new")).Times(1);
- task_runner->FastForwardBy(base::Seconds(1));
- }
- TEST_F(FCMNetworkHandlerTest,
- ShouldScheduleTokenValidationAndDoNotActOnSameToken) {
- // Setting up network handler.
- MockOnTokenCallback mock_on_token_callback;
- std::unique_ptr<FCMNetworkHandler> handler = MakeHandler();
- auto task_runner = CreateFakeTaskRunnerAndInjectToHandler(handler);
- handler->SetTokenReceiver(mock_on_token_callback.Get());
- // Checking that after start listening the token will be requested
- // and passed to the appropriate token receiver
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(*mock_instance_id(), ValidateToken).Times(0);
- EXPECT_CALL(mock_on_token_callback, Run("token")).Times(1);
- handler->StartListening();
- testing::Mock::VerifyAndClearExpectations(mock_instance_id());
- // Adjust timers and check that validation will happen in time.
- // The old token is valid, so no token listener should be informed.
- const base::TimeDelta time_to_validation = base::Hours(24);
- task_runner->FastForwardBy(time_to_validation - base::Seconds(1));
- // But when it is time, validation happens.
- EXPECT_CALL(*mock_instance_id(), GetToken)
- .WillOnce(WithArg<4>(Invoke([](InstanceID::GetTokenCallback callback) {
- std::move(callback).Run("token", InstanceID::Result::SUCCESS);
- })));
- EXPECT_CALL(mock_on_token_callback, Run).Times(0);
- task_runner->FastForwardBy(base::Seconds(1));
- }
- TEST_F(FCMNetworkHandlerTestWithTTL, ShouldProvideTTLWithSyncSenderID) {
- EXPECT_CALL(*mock_instance_id(),
- GetToken(_, _, Eq(base::Seconds(kTimeToLiveInSeconds)), _, _));
- MakeHandler(/*sender_id=*/"8181035976")->StartListening();
- }
- TEST_F(FCMNetworkHandlerTestWithTTL, ShouldProvideTTLWithPolicySenderID) {
- EXPECT_CALL(*mock_instance_id(),
- GetToken(_, _, Eq(base::Seconds(kTimeToLiveInSeconds)), _, _));
- MakeHandler(/*sender_id=*/"1013309121859")->StartListening();
- }
- TEST_F(FCMNetworkHandlerTestWithTTL, ShouldNotProvideTTLWithFakeSenderID) {
- EXPECT_CALL(*mock_instance_id(), GetToken(_, _, Eq(base::TimeDelta()), _, _));
- MakeHandler(/*sender_id=*/"fake_sender_id")->StartListening();
- }
- } // namespace invalidation
|