diff options
-rw-r--r-- | components/gcm_driver/fake_gcm_client.cc | 7 | ||||
-rw-r--r-- | components/gcm_driver/fake_gcm_client.h | 2 | ||||
-rw-r--r-- | components/gcm_driver/fake_gcm_driver.cc | 7 | ||||
-rw-r--r-- | components/gcm_driver/fake_gcm_driver.h | 2 | ||||
-rw-r--r-- | components/gcm_driver/gcm_client.h | 8 | ||||
-rw-r--r-- | components/gcm_driver/gcm_client_impl.cc | 11 | ||||
-rw-r--r-- | components/gcm_driver/gcm_client_impl.h | 2 | ||||
-rw-r--r-- | components/gcm_driver/gcm_driver.h | 22 | ||||
-rw-r--r-- | components/gcm_driver/gcm_driver_android.cc | 7 | ||||
-rw-r--r-- | components/gcm_driver/gcm_driver_android.h | 2 | ||||
-rw-r--r-- | components/gcm_driver/gcm_driver_desktop.cc | 57 | ||||
-rw-r--r-- | components/gcm_driver/gcm_driver_desktop.h | 2 | ||||
-rw-r--r-- | google_apis/gcm/engine/gcm_store.cc | 1 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client.cc | 20 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client.h | 9 | ||||
-rw-r--r-- | google_apis/gcm/engine/mcs_client_unittest.cc | 314 |
16 files changed, 400 insertions, 73 deletions
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc index ffa77d1..50a4598 100644 --- a/components/gcm_driver/fake_gcm_client.cc +++ b/components/gcm_driver/fake_gcm_client.cc @@ -148,6 +148,13 @@ std::string FakeGCMClient::GetInstanceIDData(const std::string& app_id) { return std::string(); } +void FakeGCMClient::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { +} + +void FakeGCMClient::RemoveHeartbeatInterval(const std::string& scope) { +} + void FakeGCMClient::PerformDelayedStart() { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h index c0b03da..155c342 100644 --- a/components/gcm_driver/fake_gcm_client.h +++ b/components/gcm_driver/fake_gcm_client.h @@ -60,6 +60,8 @@ class FakeGCMClient : public GCMClient { const std::string& instance_id_data) override; void RemoveInstanceIDData(const std::string& app_id) override; std::string GetInstanceIDData(const std::string& app_id) override; + void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; + void RemoveHeartbeatInterval(const std::string& scope) override; // Initiate the start that has been delayed. // Called on UI thread. diff --git a/components/gcm_driver/fake_gcm_driver.cc b/components/gcm_driver/fake_gcm_driver.cc index c6f7d9e..15b41fd 100644 --- a/components/gcm_driver/fake_gcm_driver.cc +++ b/components/gcm_driver/fake_gcm_driver.cc @@ -102,4 +102,11 @@ InstanceIDStore* FakeGCMDriver::GetInstanceIDStore() { return NULL; } +void FakeGCMDriver::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { +} + +void FakeGCMDriver::RemoveHeartbeatInterval(const std::string& scope) { +} + } // namespace gcm diff --git a/components/gcm_driver/fake_gcm_driver.h b/components/gcm_driver/fake_gcm_driver.h index 5e334c6..0c289f0 100644 --- a/components/gcm_driver/fake_gcm_driver.h +++ b/components/gcm_driver/fake_gcm_driver.h @@ -42,6 +42,8 @@ class FakeGCMDriver : public GCMDriver { void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; InstanceIDStore* GetInstanceIDStore() override; + void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; + void RemoveHeartbeatInterval(const std::string& scope) override; protected: // GCMDriver implementation: diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h index cd804b2..8672233 100644 --- a/components/gcm_driver/gcm_client.h +++ b/components/gcm_driver/gcm_client.h @@ -320,6 +320,14 @@ class GCMClient { // Retrieves the Instance ID data for a specific app from the persistent // store. virtual std::string GetInstanceIDData(const std::string& app_id) = 0; + + // Gets and sets custom heartbeat interval for the MCS connection. + // |scope| is used to identify the component that requests a custom interval + // to be set, and allows that component to later revoke the setting. It should + // be unique. + virtual void AddHeartbeatInterval(const std::string& scope, + int interval_ms) = 0; + virtual void RemoveHeartbeatInterval(const std::string& scope) = 0; }; } // namespace gcm diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc index 8fb162d..448e416 100644 --- a/components/gcm_driver/gcm_client_impl.cc +++ b/components/gcm_driver/gcm_client_impl.cc @@ -556,6 +556,17 @@ std::string GCMClientImpl::GetInstanceIDData(const std::string& app_id) { return iter->second; } +void GCMClientImpl::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { + DCHECK(mcs_client_); + mcs_client_->AddHeartbeatInterval(scope, interval_ms); +} + +void GCMClientImpl::RemoveHeartbeatInterval(const std::string& scope) { + DCHECK(mcs_client_); + mcs_client_->RemoveHeartbeatInterval(scope); +} + void GCMClientImpl::StartCheckin() { // Make sure no checkin is in progress. if (checkin_request_.get()) diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h index 2db1805..e9f2f14 100644 --- a/components/gcm_driver/gcm_client_impl.h +++ b/components/gcm_driver/gcm_client_impl.h @@ -130,6 +130,8 @@ class GCMClientImpl const std::string& instance_id_data) override; void RemoveInstanceIDData(const std::string& app_id) override; std::string GetInstanceIDData(const std::string& app_id) override; + void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; + void RemoveHeartbeatInterval(const std::string& scope) override; // GCMStatsRecorder::Delegate implemenation. void OnActivityRecorded() override; diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h index aac0975..caae284 100644 --- a/components/gcm_driver/gcm_driver.h +++ b/components/gcm_driver/gcm_driver.h @@ -169,6 +169,28 @@ class GCMDriver { // Supports saving the Instance ID data in the GCM store. virtual InstanceIDStore* GetInstanceIDStore() = 0; + // Adds or removes a custom client requested heartbeat interval. If multiple + // components set that setting, the lowest setting will be used. If the + // setting is outside of GetMax/MinClientHeartbeatIntervalMs() it will be + // ignored. If a new setting is less than the currently used, the connection + // will be reset with the new heartbeat. Client that no longer require + // aggressive heartbeats, should remove their requested interval. Heartbeats + // set this way survive connection/Chrome restart. + // + // GCM Driver can decide to postpone the action until Client is properly + // initialized, hence this setting can be called at any time. + // + // Server can overwrite the setting to a different value. + // + // |scope| is used to identify the component that requests a custom interval + // to be set, and allows that component to later revoke the setting. + // |interval_ms| should be between 2 minues and 15 minues (28 minues on + // cellular networks). For details check + // GetMin/MaxClientHeartbeatItnervalMs() in HeartbeatManager. + virtual void AddHeartbeatInterval(const std::string& scope, + int interval_ms) = 0; + virtual void RemoveHeartbeatInterval(const std::string& scope) = 0; + protected: // Ensures that the GCM service starts (if necessary conditions are met). virtual GCMClient::Result EnsureStarted(GCMClient::StartMode start_mode) = 0; diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc index ec69952..b5960fc 100644 --- a/components/gcm_driver/gcm_driver_android.cc +++ b/components/gcm_driver/gcm_driver_android.cc @@ -167,6 +167,13 @@ InstanceIDStore* GCMDriverAndroid::GetInstanceIDStore() { return NULL; } +void GCMDriverAndroid::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { +} + +void GCMDriverAndroid::RemoveHeartbeatInterval(const std::string& scope) { +} + GCMClient::Result GCMDriverAndroid::EnsureStarted( GCMClient::StartMode start_mode) { // TODO(johnme): Maybe we should check if GMS is available? diff --git a/components/gcm_driver/gcm_driver_android.h b/components/gcm_driver/gcm_driver_android.h index 3c5d357..205fb6e 100644 --- a/components/gcm_driver/gcm_driver_android.h +++ b/components/gcm_driver/gcm_driver_android.h @@ -65,6 +65,8 @@ class GCMDriverAndroid : public GCMDriver { void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; InstanceIDStore* GetInstanceIDStore() override; + void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; + void RemoveHeartbeatInterval(const std::string& scope) override; protected: // GCMDriver implementation: diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc index a711999..dcc5cb2 100644 --- a/components/gcm_driver/gcm_driver_desktop.cc +++ b/components/gcm_driver/gcm_driver_desktop.cc @@ -91,6 +91,8 @@ class GCMDriverDesktop::IOWorker : public GCMClient::Delegate { const std::string& instance_id_data); void RemoveInstanceIDData(const std::string& app_id); void GetInstanceIDData(const std::string& app_id); + void AddHeartbeatInterval(const std::string& scope, int interval_ms); + void RemoveHeartbeatInterval(const std::string& scope); // For testing purpose. Can be called from UI thread. Use with care. GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } @@ -392,6 +394,18 @@ void GCMDriverDesktop::IOWorker::WakeFromSuspendForHeartbeat(bool wake) { #endif } +void GCMDriverDesktop::IOWorker::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { + DCHECK(io_thread_->RunsTasksOnCurrentThread()); + gcm_client_->AddHeartbeatInterval(scope, interval_ms); +} + +void GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval( + const std::string& scope) { + DCHECK(io_thread_->RunsTasksOnCurrentThread()); + gcm_client_->RemoveHeartbeatInterval(scope); +} + GCMDriverDesktop::GCMDriverDesktop( scoped_ptr<GCMClientFactory> gcm_client_factory, const GCMClient::ChromeBuildInfo& chrome_build_info, @@ -768,6 +782,49 @@ void GCMDriverDesktop::WakeFromSuspendForHeartbeat(bool wake) { wake_from_suspend_enabled_)); } +void GCMDriverDesktop::AddHeartbeatInterval(const std::string& scope, + int interval_ms) { + DCHECK(ui_thread_->RunsTasksOnCurrentThread()); + + // The GCM service has not been initialized. + if (!delayed_task_controller_) + return; + + if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { + // The GCM service was initialized but has not started yet. + delayed_task_controller_->AddTask( + base::Bind(&GCMDriverDesktop::AddHeartbeatInterval, + weak_ptr_factory_.GetWeakPtr(), scope, interval_ms)); + return; + } + + io_thread_->PostTask( + FROM_HERE, + base::Bind(&GCMDriverDesktop::IOWorker::AddHeartbeatInterval, + base::Unretained(io_worker_.get()), scope, interval_ms)); +} + +void GCMDriverDesktop::RemoveHeartbeatInterval(const std::string& scope) { + DCHECK(ui_thread_->RunsTasksOnCurrentThread()); + + // The GCM service has not been initialized. + if (!delayed_task_controller_) + return; + + if (!delayed_task_controller_->CanRunTaskWithoutDelay()) { + // The GCM service was initialized but has not started yet. + delayed_task_controller_->AddTask( + base::Bind(&GCMDriverDesktop::RemoveHeartbeatInterval, + weak_ptr_factory_.GetWeakPtr(), scope)); + return; + } + + io_thread_->PostTask( + FROM_HERE, + base::Bind(&GCMDriverDesktop::IOWorker::RemoveHeartbeatInterval, + base::Unretained(io_worker_.get()), scope)); +} + void GCMDriverDesktop::SetAccountTokens( const std::vector<GCMClient::AccountTokenInfo>& account_tokens) { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h index f52dd6bb..3206a91 100644 --- a/components/gcm_driver/gcm_driver_desktop.h +++ b/components/gcm_driver/gcm_driver_desktop.h @@ -85,6 +85,8 @@ class GCMDriverDesktop : public GCMDriver, void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; InstanceIDStore* GetInstanceIDStore() override; + void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; + void RemoveHeartbeatInterval(const std::string& scope) override; // InstanceIDStore overrides: void AddInstanceIDData(const std::string& app_id, diff --git a/google_apis/gcm/engine/gcm_store.cc b/google_apis/gcm/engine/gcm_store.cc index 6f5ab0e..c698528 100644 --- a/google_apis/gcm/engine/gcm_store.cc +++ b/google_apis/gcm/engine/gcm_store.cc @@ -26,6 +26,7 @@ void GCMStore::LoadResult::Reset() { last_token_fetch_time = base::Time::FromInternalValue(0LL); last_checkin_accounts.clear(); account_mappings.clear(); + heartbeat_intervals.clear(); success = false; instance_id_data.clear(); } diff --git a/google_apis/gcm/engine/mcs_client.cc b/google_apis/gcm/engine/mcs_client.cc index 3b1016d..9b4607d 100644 --- a/google_apis/gcm/engine/mcs_client.cc +++ b/google_apis/gcm/engine/mcs_client.cc @@ -276,6 +276,12 @@ void MCSClient::Initialize( collapse_key_map_[collapse_key] = packet_info; } } + + // Establish if there is any custom client interval persisted from the last + // run and set it on the heartbeat manager. + custom_heartbeat_intervals_.swap(load_result->heartbeat_intervals); + int min_interval_ms = GetMinHeartbeatIntervalMs(); + heartbeat_manager_.SetClientHeartbeatIntervalMs(min_interval_ms); } void MCSClient::Login(uint64 android_id, uint64 security_token) { @@ -380,19 +386,25 @@ void MCSClient::AddHeartbeatInterval(const std::string& scope, return; custom_heartbeat_intervals_[scope] = interval_ms; - // TODO(fgorski): Save in the gcm store as well. + gcm_store_->AddHeartbeatInterval(scope, interval_ms, + base::Bind(&MCSClient::OnGCMUpdateFinished, + weak_ptr_factory_.GetWeakPtr())); - int min_interval_ms = GetMinCustomHeartbeatInterval(); + int min_interval_ms = GetMinHeartbeatIntervalMs(); heartbeat_manager_.SetClientHeartbeatIntervalMs(min_interval_ms); } void MCSClient::RemoveHeartbeatInterval(const std::string& scope) { custom_heartbeat_intervals_.erase(scope); - int min_interval = GetMinCustomHeartbeatInterval(); + gcm_store_->RemoveHeartbeatInterval( + scope, base::Bind(&MCSClient::OnGCMUpdateFinished, + weak_ptr_factory_.GetWeakPtr())); + + int min_interval = GetMinHeartbeatIntervalMs(); heartbeat_manager_.SetClientHeartbeatIntervalMs(min_interval); } -int MCSClient::GetMinCustomHeartbeatInterval() { +int MCSClient::GetMinHeartbeatIntervalMs() { if (custom_heartbeat_intervals_.empty()) return kNoCustomHeartbeat; diff --git a/google_apis/gcm/engine/mcs_client.h b/google_apis/gcm/engine/mcs_client.h index a81bcbe..8d35fd4 100644 --- a/google_apis/gcm/engine/mcs_client.h +++ b/google_apis/gcm/engine/mcs_client.h @@ -160,8 +160,8 @@ class GCM_EXPORT MCSClient { void AddHeartbeatInterval(const std::string& scope, int interval_ms); void RemoveHeartbeatInterval(const std::string& scope); - HeartbeatManager& GetHeartbeatManagerForTesting() { - return heartbeat_manager_; + HeartbeatManager* GetHeartbeatManagerForTesting() { + return &heartbeat_manager_; } private: @@ -225,8 +225,9 @@ class GCM_EXPORT MCSClient { // any associated state). MCSPacketInternal PopMessageForSend(); - // Gets the minimum interval from the map of scopes to intervals. - int GetMinCustomHeartbeatInterval(); + // Gets the minimum interval from the map of scopes to intervals in + // milliseconds. + int GetMinHeartbeatIntervalMs(); // Local version string. Sent on login. const std::string version_string_; diff --git a/google_apis/gcm/engine/mcs_client_unittest.cc b/google_apis/gcm/engine/mcs_client_unittest.cc index 1b6d2ef..644c702 100644 --- a/google_apis/gcm/engine/mcs_client_unittest.cc +++ b/google_apis/gcm/engine/mcs_client_unittest.cc @@ -113,8 +113,11 @@ class MCSClientTest : public testing::Test { void InitializeClient(); void StoreCredentials(); void LoginClient(const std::vector<std::string>& acknowledged_ids); + void LoginClientWithHeartbeat( + const std::vector<std::string>& acknowledged_ids, + int heartbeat_interval_ms); void AddExpectedLoginRequest(const std::vector<std::string>& acknowledged_ids, - int custom_heartbeat_interval); + int heartbeat_interval_ms); base::SimpleTestClock* clock() { return &clock_; } TestMCSClient* mcs_client() const { return mcs_client_.get(); } @@ -209,7 +212,13 @@ void MCSClientTest::InitializeClient() { void MCSClientTest::LoginClient( const std::vector<std::string>& acknowledged_ids) { - AddExpectedLoginRequest(acknowledged_ids, 0); + LoginClientWithHeartbeat(acknowledged_ids, 0); +} + +void MCSClientTest::LoginClientWithHeartbeat( + const std::vector<std::string>& acknowledged_ids, + int heartbeat_interval_ms) { + AddExpectedLoginRequest(acknowledged_ids, heartbeat_interval_ms); mcs_client_->Login(kAndroidId, kSecurityToken); run_loop_->Run(); run_loop_.reset(new base::RunLoop()); @@ -217,15 +226,15 @@ void MCSClientTest::LoginClient( void MCSClientTest::AddExpectedLoginRequest( const std::vector<std::string>& acknowledged_ids, - int custom_heartbeat_interval) { + int heartbeat_interval_ms) { scoped_ptr<mcs_proto::LoginRequest> login_request = BuildLoginRequest(kAndroidId, kSecurityToken, ""); for (size_t i = 0; i < acknowledged_ids.size(); ++i) login_request->add_received_persistent_id(acknowledged_ids[i]); - if (custom_heartbeat_interval) { + if (heartbeat_interval_ms) { mcs_proto::Setting* setting = login_request->add_setting(); setting->set_name("hbping"); - setting->set_value(base::IntToString(custom_heartbeat_interval)); + setting->set_value(base::IntToString(heartbeat_interval_ms)); } GetFakeHandler()->ExpectOutgoingMessage( MCSMessage(kLoginRequestTag, login_request.Pass())); @@ -898,97 +907,272 @@ TEST_F(MCSClientTest, CollapseKeysDifferentUser) { PumpLoop(); } -// Tests adding and removing custom heartbeat interval. -TEST_F(MCSClientTest, CustomHeartbeatInterval) { +// Test case for setting a custom heartbeat interval, when it is too short. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalTooShort) { BuildMCSClient(); InitializeClient(); LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); - TestConnectionListener test_connection_listener; - connection_factory()->SetConnectionListener(&test_connection_listener); - - HeartbeatManager& hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); // By default custom client interval is not set. - EXPECT_FALSE(hb_manager.HasClientHeartbeatInterval()); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); const std::string component_1 = "component1"; int interval_ms = 30 * 1000; // 30 seconds, too low. mcs_client()->AddHeartbeatInterval(component_1, interval_ms); // Setting was too low so it was ignored. - EXPECT_FALSE(hb_manager.HasClientHeartbeatInterval()); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); + + // Restore and check again to make sure that nothing was set in store. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), 0); + PumpLoop(); + + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); +} - interval_ms = 60 * 60 * 1000; // 1 hour, too high. +// Test case for setting a custom heartbeat interval, when it is too long. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalTooLong) { + BuildMCSClient(); + InitializeClient(); + LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); + + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + + const std::string component_1 = "component1"; + int interval_ms = 60 * 60 * 1000; // 1 hour, too high. mcs_client()->AddHeartbeatInterval(component_1, interval_ms); // Setting was too high, again it was ignored. - EXPECT_FALSE(hb_manager.HasClientHeartbeatInterval()); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); + + // Restore and check again to make sure that nothing was set in store. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), 0); + PumpLoop(); + + // Setting was too high, again it was ignored. + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); +} - int expected_disconnect_counter = 0; - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); +// Tests adding and removing custom heartbeat interval. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalSingleInterval) { + BuildMCSClient(); + InitializeClient(); + LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); + + TestConnectionListener test_connection_listener; + connection_factory()->SetConnectionListener(&test_connection_listener); + + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. - interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. AddExpectedLoginRequest(std::vector<std::string>(), interval_ms); mcs_client()->AddHeartbeatInterval(component_1, interval_ms); - // Setting was OK. HearbeatManager should get that setting now. - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); + PumpLoop(); + + // Interval was OK. HearbeatManager should get that setting now. + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); + EXPECT_EQ(1, test_connection_listener.get_disconnect_counter()); + + // Check that setting was persisted and will take effect upon restart. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms); + PumpLoop(); + + // HB manger uses the shortest persisted interval after restart. + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); + + mcs_client()->RemoveHeartbeatInterval(component_1); + PumpLoop(); + + // Check that setting was persisted and will take effect upon restart. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), 0); + PumpLoop(); + + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_FALSE(hb_manager->HasClientHeartbeatInterval()); +} + +// Tests adding custom heartbeat interval before connection is initialized. +TEST_F(MCSClientTest, CustomHeartbeatIntervalSetBeforeInitialize) { + BuildMCSClient(); + + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. + mcs_client()->AddHeartbeatInterval(component_1, interval_ms); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms); + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); +} + +// Tests adding custom heartbeat interval after connection is initialized, but +// but before login is sent. +TEST_F(MCSClientTest, CustomHeartbeatIntervalSetBeforeLogin) { + BuildMCSClient(); + + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. + InitializeClient(); + mcs_client()->AddHeartbeatInterval(component_1, interval_ms); + LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms); + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); +} + +// Tests situation when two heartbeat intervals are set and second is longer. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalSecondIntervalLonger) { + BuildMCSClient(); + InitializeClient(); + LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); + + TestConnectionListener test_connection_listener; + connection_factory()->SetConnectionListener(&test_connection_listener); + + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); - ++expected_disconnect_counter; - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. + + AddExpectedLoginRequest(std::vector<std::string>(), interval_ms); + mcs_client()->AddHeartbeatInterval(component_1, interval_ms); + PumpLoop(); const std::string component_2 = "component2"; int other_interval_ms = 10 * 60 * 1000; // 10 minutes. A valid setting. mcs_client()->AddHeartbeatInterval(component_2, other_interval_ms); - // Setting was OK, but higher than the previous setting and HearbeatManager - // will not be updated. - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); - // No connection reset expected. - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + PumpLoop(); + + // Interval was OK, but longer. HearbeatManager will use the first one. + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); + EXPECT_EQ(1, test_connection_listener.get_disconnect_counter()); + + // Check that setting was persisted and will take effect upon restart. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms); + PumpLoop(); - other_interval_ms = 3 * 60 * 1000; // 3 minutes. A valid setting. + // HB manger uses the shortest persisted interval after restart. + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); +} + +// Tests situation when two heartbeat intervals are set and second is shorter. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalSecondIntervalShorter) { + BuildMCSClient(); + InitializeClient(); + LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); + + TestConnectionListener test_connection_listener; + connection_factory()->SetConnectionListener(&test_connection_listener); + + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. + + AddExpectedLoginRequest(std::vector<std::string>(), interval_ms); + mcs_client()->AddHeartbeatInterval(component_1, interval_ms); + PumpLoop(); + + const std::string component_2 = "component2"; + int other_interval_ms = 3 * 60 * 1000; // 3 minutes. A valid setting. AddExpectedLoginRequest(std::vector<std::string>(), other_interval_ms); mcs_client()->AddHeartbeatInterval(component_2, other_interval_ms); - // Setting was OK and lower then present setting. HearbeatManager should get - // that setting now. - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(other_interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); - ++expected_disconnect_counter; - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + PumpLoop(); + // Interval was OK. HearbeatManager should get that setting now. + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(other_interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); + EXPECT_EQ(2, test_connection_listener.get_disconnect_counter()); - mcs_client()->RemoveHeartbeatInterval(component_2); - // Removing the lowest setting reverts to second lowest. - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); - // No connection reset expected. - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + // Check that setting was persisted and will take effect upon restart. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), other_interval_ms); + PumpLoop(); - mcs_client()->RemoveHeartbeatInterval(component_1); - // Removing all of the intervals, removes it from the HeartbeatManager. - EXPECT_FALSE(hb_manager.HasClientHeartbeatInterval()); - // No connection reset expected. - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + // HB manger uses the shortest persisted interval after restart. + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(other_interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); +} - mcs_client()->AddHeartbeatInterval(component_2, other_interval_ms); +// Tests situation shorter of two intervals is removed. +// Covers both connection restart and storing of custom intervals. +TEST_F(MCSClientTest, CustomHeartbeatIntervalRemoveShorterInterval) { + BuildMCSClient(); + InitializeClient(); + LoginClient(std::vector<std::string>()); + PumpLoop(); + StoreCredentials(); + + TestConnectionListener test_connection_listener; + connection_factory()->SetConnectionListener(&test_connection_listener); + + HeartbeatManager* hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + + const std::string component_1 = "component1"; + int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting. + + AddExpectedLoginRequest(std::vector<std::string>(), interval_ms); mcs_client()->AddHeartbeatInterval(component_1, interval_ms); - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(other_interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); - // No connection reset expected. - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + PumpLoop(); - // Removing interval other than lowest does not change anything. - mcs_client()->RemoveHeartbeatInterval(component_1); - EXPECT_TRUE(hb_manager.HasClientHeartbeatInterval()); - EXPECT_EQ(other_interval_ms, hb_manager.GetClientHeartbeatIntervalMs()); + const std::string component_2 = "component2"; + int other_interval_ms = 3 * 60 * 1000; // 3 minutes. A valid setting. + AddExpectedLoginRequest(std::vector<std::string>(), other_interval_ms); + mcs_client()->AddHeartbeatInterval(component_2, other_interval_ms); + PumpLoop(); + + mcs_client()->RemoveHeartbeatInterval(component_2); + PumpLoop(); + + // Removing the lowest setting reverts to second lowest. + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); // No connection reset expected. - EXPECT_EQ(expected_disconnect_counter, - test_connection_listener.get_disconnect_counter()); + EXPECT_EQ(2, test_connection_listener.get_disconnect_counter()); + + // Check that setting was persisted and will take effect upon restart. + BuildMCSClient(); + InitializeClient(); + LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms); + PumpLoop(); + + // HB manger uses the shortest persisted interval after restart. + hb_manager = mcs_client()->GetHeartbeatManagerForTesting(); + EXPECT_TRUE(hb_manager->HasClientHeartbeatInterval()); + EXPECT_EQ(interval_ms, hb_manager->GetClientHeartbeatIntervalMs()); } } // namespace |