• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BuildHeartbeatConfig(int interval_ms)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:
TestHeartbeatManager()24   TestHeartbeatManager() {}
~TestHeartbeatManager()25   virtual ~TestHeartbeatManager() {}
26 
27   // Bypass the heartbeat timer, and send the heartbeat now.
28   void TriggerHearbeat();
29 };
30 
TriggerHearbeat()31 void TestHeartbeatManager::TriggerHearbeat() {
32   OnHeartbeatTriggered();
33 }
34 
35 class HeartbeatManagerTest : public testing::Test {
36  public:
37   HeartbeatManagerTest();
~HeartbeatManagerTest()38   virtual ~HeartbeatManagerTest() {}
39 
manager() const40   TestHeartbeatManager* manager() const { return manager_.get(); }
heartbeats_sent() const41   int heartbeats_sent() const { return heartbeats_sent_; }
reconnects_triggered() const42   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 
HeartbeatManagerTest()60 HeartbeatManagerTest::HeartbeatManagerTest()
61     : manager_(new TestHeartbeatManager()),
62       heartbeats_sent_(0),
63       reconnects_triggered_(0) {
64 }
65 
StartManager()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 
SendHeartbeatClosure()73 void HeartbeatManagerTest::SendHeartbeatClosure() {
74   heartbeats_sent_++;
75 }
76 
TriggerReconnectClosure()77 void HeartbeatManagerTest::TriggerReconnectClosure() {
78   reconnects_triggered_++;
79 }
80 
81 // Basic initialization. No heartbeat should be pending.
TEST_F(HeartbeatManagerTest,Init)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.
TEST_F(HeartbeatManagerTest,AckBeforeStart)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.
TEST_F(HeartbeatManagerTest,Start)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.
TEST_F(HeartbeatManagerTest,AckedHeartbeat)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.
TEST_F(HeartbeatManagerTest,UnackedHeartbeat)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.
TEST_F(HeartbeatManagerTest,UpdateIntervalThenStart)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.
TEST_F(HeartbeatManagerTest,StartThenUpdateInterval)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.
TEST_F(HeartbeatManagerTest,Stop)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