1 // Copyright 2014 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 5 #include "google_apis/gcm/engine/heartbeat_manager.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "base/time/time.h" 9 #include "google_apis/gcm/protocol/mcs.pb.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace gcm { 13 14 namespace { 15 16 mcs_proto::HeartbeatConfig BuildHeartbeatConfig(int interval_ms) { 17 mcs_proto::HeartbeatConfig config; 18 config.set_interval_ms(interval_ms); 19 return config; 20 } 21 22 class TestHeartbeatManager : public HeartbeatManager { 23 public: 24 TestHeartbeatManager() {} 25 virtual ~TestHeartbeatManager() {} 26 27 // Bypass the heartbeat timer, and send the heartbeat now. 28 void TriggerHearbeat(); 29 }; 30 31 void TestHeartbeatManager::TriggerHearbeat() { 32 OnHeartbeatTriggered(); 33 } 34 35 class HeartbeatManagerTest : public testing::Test { 36 public: 37 HeartbeatManagerTest(); 38 virtual ~HeartbeatManagerTest() {} 39 40 TestHeartbeatManager* manager() const { return manager_.get(); } 41 int heartbeats_sent() const { return heartbeats_sent_; } 42 int reconnects_triggered() const { return reconnects_triggered_; } 43 44 // Starts the heartbeat manager. 45 void StartManager(); 46 47 private: 48 // Helper functions for verifying heartbeat manager effects. 49 void SendHeartbeatClosure(); 50 void TriggerReconnectClosure(); 51 52 scoped_ptr<TestHeartbeatManager> manager_; 53 54 int heartbeats_sent_; 55 int reconnects_triggered_; 56 57 base::MessageLoop message_loop_; 58 }; 59 60 HeartbeatManagerTest::HeartbeatManagerTest() 61 : manager_(new TestHeartbeatManager()), 62 heartbeats_sent_(0), 63 reconnects_triggered_(0) { 64 } 65 66 void HeartbeatManagerTest::StartManager() { 67 manager_->Start(base::Bind(&HeartbeatManagerTest::SendHeartbeatClosure, 68 base::Unretained(this)), 69 base::Bind(&HeartbeatManagerTest::TriggerReconnectClosure, 70 base::Unretained(this))); 71 } 72 73 void HeartbeatManagerTest::SendHeartbeatClosure() { 74 heartbeats_sent_++; 75 } 76 77 void HeartbeatManagerTest::TriggerReconnectClosure() { 78 reconnects_triggered_++; 79 } 80 81 // Basic initialization. No heartbeat should be pending. 82 TEST_F(HeartbeatManagerTest, Init) { 83 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null()); 84 } 85 86 // Acknowledging a heartbeat before starting the manager should have no effect. 87 TEST_F(HeartbeatManagerTest, AckBeforeStart) { 88 manager()->OnHeartbeatAcked(); 89 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null()); 90 } 91 92 // Starting the manager should start the heartbeat timer. 93 TEST_F(HeartbeatManagerTest, Start) { 94 StartManager(); 95 EXPECT_GT(manager()->GetNextHeartbeatTime(), base::TimeTicks::Now()); 96 EXPECT_EQ(0, heartbeats_sent()); 97 EXPECT_EQ(0, reconnects_triggered()); 98 } 99 100 // Acking the heartbeat should trigger a new heartbeat timer. 101 TEST_F(HeartbeatManagerTest, AckedHeartbeat) { 102 StartManager(); 103 manager()->TriggerHearbeat(); 104 base::TimeTicks heartbeat = manager()->GetNextHeartbeatTime(); 105 EXPECT_GT(heartbeat, base::TimeTicks::Now()); 106 EXPECT_EQ(1, heartbeats_sent()); 107 EXPECT_EQ(0, reconnects_triggered()); 108 109 manager()->OnHeartbeatAcked(); 110 EXPECT_LT(heartbeat, manager()->GetNextHeartbeatTime()); 111 EXPECT_EQ(1, heartbeats_sent()); 112 EXPECT_EQ(0, reconnects_triggered()); 113 114 manager()->TriggerHearbeat(); 115 EXPECT_EQ(2, heartbeats_sent()); 116 EXPECT_EQ(0, reconnects_triggered()); 117 } 118 119 // Trigger a heartbeat when one was outstanding should reset the connection. 120 TEST_F(HeartbeatManagerTest, UnackedHeartbeat) { 121 StartManager(); 122 manager()->TriggerHearbeat(); 123 EXPECT_EQ(1, heartbeats_sent()); 124 EXPECT_EQ(0, reconnects_triggered()); 125 126 manager()->TriggerHearbeat(); 127 EXPECT_EQ(1, heartbeats_sent()); 128 EXPECT_EQ(1, reconnects_triggered()); 129 } 130 131 // Updating the heartbeat interval before starting should result in the new 132 // interval being used at Start time. 133 TEST_F(HeartbeatManagerTest, UpdateIntervalThenStart) { 134 const int kIntervalMs = 60 * 1000; // 60 seconds. 135 manager()->UpdateHeartbeatConfig(BuildHeartbeatConfig(kIntervalMs)); 136 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null()); 137 StartManager(); 138 EXPECT_LE(manager()->GetNextHeartbeatTime() - base::TimeTicks::Now(), 139 base::TimeDelta::FromMilliseconds(kIntervalMs)); 140 } 141 142 // Updating the heartbeat interval after starting should only use the new 143 // interval on the next heartbeat. 144 TEST_F(HeartbeatManagerTest, StartThenUpdateInterval) { 145 const int kIntervalMs = 60 * 1000; // 60 seconds. 146 StartManager(); 147 base::TimeTicks heartbeat = manager()->GetNextHeartbeatTime(); 148 EXPECT_GT(heartbeat - base::TimeTicks::Now(), 149 base::TimeDelta::FromMilliseconds(kIntervalMs)); 150 151 // Updating the interval should not affect an outstanding heartbeat. 152 manager()->UpdateHeartbeatConfig(BuildHeartbeatConfig(kIntervalMs)); 153 EXPECT_EQ(heartbeat, manager()->GetNextHeartbeatTime()); 154 155 // Triggering and acking the heartbeat should result in a heartbeat being 156 // posted with the new interval. 157 manager()->TriggerHearbeat(); 158 manager()->OnHeartbeatAcked(); 159 160 EXPECT_LE(manager()->GetNextHeartbeatTime() - base::TimeTicks::Now(), 161 base::TimeDelta::FromMilliseconds(kIntervalMs)); 162 EXPECT_NE(heartbeat, manager()->GetNextHeartbeatTime()); 163 } 164 165 // Stopping the manager should reset the heartbeat timer. 166 TEST_F(HeartbeatManagerTest, Stop) { 167 StartManager(); 168 EXPECT_GT(manager()->GetNextHeartbeatTime(), base::TimeTicks::Now()); 169 170 manager()->Stop(); 171 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null()); 172 } 173 174 } // namespace 175 176 } // namespace gcm 177