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.
5 #include "google_apis/gcm/engine/heartbeat_manager.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/time/time.h"
11 #include "base/timer/timer.h"
12 #include "google_apis/gcm/protocol/mcs.pb.h"
13 #include "testing/gtest/include/gtest/gtest.h"
19 mcs_proto::HeartbeatConfig
BuildHeartbeatConfig(int interval_ms
) {
20 mcs_proto::HeartbeatConfig config
;
21 config
.set_interval_ms(interval_ms
);
25 class TestHeartbeatManager
: public HeartbeatManager
{
27 TestHeartbeatManager()
28 : HeartbeatManager(make_scoped_ptr(
29 new base::Timer(true, /* retain user task */
30 false /* non repeating */))) {}
31 virtual ~TestHeartbeatManager() {}
33 // Bypass the heartbeat timer, and send the heartbeat now.
34 void TriggerHearbeat();
36 // Check for a missed heartbeat now.
37 void TriggerMissedHeartbeatCheck();
40 void TestHeartbeatManager::TriggerHearbeat() {
41 OnHeartbeatTriggered();
44 void TestHeartbeatManager::TriggerMissedHeartbeatCheck() {
45 CheckForMissedHeartbeat();
48 class HeartbeatManagerTest
: public testing::Test
{
50 HeartbeatManagerTest();
51 virtual ~HeartbeatManagerTest() {}
53 TestHeartbeatManager
* manager() const { return manager_
.get(); }
54 int heartbeats_sent() const { return heartbeats_sent_
; }
55 int reconnects_triggered() const { return reconnects_triggered_
; }
57 // Starts the heartbeat manager.
61 // Helper functions for verifying heartbeat manager effects.
62 void SendHeartbeatClosure();
63 void TriggerReconnectClosure();
65 scoped_ptr
<TestHeartbeatManager
> manager_
;
68 int reconnects_triggered_
;
70 base::MessageLoop message_loop_
;
73 HeartbeatManagerTest::HeartbeatManagerTest()
74 : manager_(new TestHeartbeatManager()),
76 reconnects_triggered_(0) {
79 void HeartbeatManagerTest::StartManager() {
80 manager_
->Start(base::Bind(&HeartbeatManagerTest::SendHeartbeatClosure
,
81 base::Unretained(this)),
82 base::Bind(&HeartbeatManagerTest::TriggerReconnectClosure
,
83 base::Unretained(this)));
86 void HeartbeatManagerTest::SendHeartbeatClosure() {
90 void HeartbeatManagerTest::TriggerReconnectClosure() {
91 reconnects_triggered_
++;
94 // Basic initialization. No heartbeat should be pending.
95 TEST_F(HeartbeatManagerTest
, Init
) {
96 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null());
99 // Acknowledging a heartbeat before starting the manager should have no effect.
100 TEST_F(HeartbeatManagerTest
, AckBeforeStart
) {
101 manager()->OnHeartbeatAcked();
102 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null());
105 // Starting the manager should start the heartbeat timer.
106 TEST_F(HeartbeatManagerTest
, Start
) {
108 EXPECT_GT(manager()->GetNextHeartbeatTime(), base::TimeTicks::Now());
109 EXPECT_EQ(0, heartbeats_sent());
110 EXPECT_EQ(0, reconnects_triggered());
113 // Acking the heartbeat should trigger a new heartbeat timer.
114 TEST_F(HeartbeatManagerTest
, AckedHeartbeat
) {
116 manager()->TriggerHearbeat();
117 base::TimeTicks heartbeat
= manager()->GetNextHeartbeatTime();
118 EXPECT_GT(heartbeat
, base::TimeTicks::Now());
119 EXPECT_EQ(1, heartbeats_sent());
120 EXPECT_EQ(0, reconnects_triggered());
122 manager()->OnHeartbeatAcked();
123 EXPECT_LT(heartbeat
, manager()->GetNextHeartbeatTime());
124 EXPECT_EQ(1, heartbeats_sent());
125 EXPECT_EQ(0, reconnects_triggered());
127 manager()->TriggerHearbeat();
128 EXPECT_EQ(2, heartbeats_sent());
129 EXPECT_EQ(0, reconnects_triggered());
132 // Trigger a heartbeat when one was outstanding should reset the connection.
133 TEST_F(HeartbeatManagerTest
, UnackedHeartbeat
) {
135 manager()->TriggerHearbeat();
136 EXPECT_EQ(1, heartbeats_sent());
137 EXPECT_EQ(0, reconnects_triggered());
139 manager()->TriggerHearbeat();
140 EXPECT_EQ(1, heartbeats_sent());
141 EXPECT_EQ(1, reconnects_triggered());
144 // Updating the heartbeat interval before starting should result in the new
145 // interval being used at Start time.
146 TEST_F(HeartbeatManagerTest
, UpdateIntervalThenStart
) {
147 const int kIntervalMs
= 60 * 1000; // 60 seconds.
148 manager()->UpdateHeartbeatConfig(BuildHeartbeatConfig(kIntervalMs
));
149 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null());
151 EXPECT_LE(manager()->GetNextHeartbeatTime() - base::TimeTicks::Now(),
152 base::TimeDelta::FromMilliseconds(kIntervalMs
));
155 // Updating the heartbeat interval after starting should only use the new
156 // interval on the next heartbeat.
157 TEST_F(HeartbeatManagerTest
, StartThenUpdateInterval
) {
158 const int kIntervalMs
= 60 * 1000; // 60 seconds.
160 base::TimeTicks heartbeat
= manager()->GetNextHeartbeatTime();
161 EXPECT_GT(heartbeat
- base::TimeTicks::Now(),
162 base::TimeDelta::FromMilliseconds(kIntervalMs
));
164 // Updating the interval should not affect an outstanding heartbeat.
165 manager()->UpdateHeartbeatConfig(BuildHeartbeatConfig(kIntervalMs
));
166 EXPECT_EQ(heartbeat
, manager()->GetNextHeartbeatTime());
168 // Triggering and acking the heartbeat should result in a heartbeat being
169 // posted with the new interval.
170 manager()->TriggerHearbeat();
171 manager()->OnHeartbeatAcked();
173 EXPECT_LE(manager()->GetNextHeartbeatTime() - base::TimeTicks::Now(),
174 base::TimeDelta::FromMilliseconds(kIntervalMs
));
175 EXPECT_NE(heartbeat
, manager()->GetNextHeartbeatTime());
178 // Stopping the manager should reset the heartbeat timer.
179 TEST_F(HeartbeatManagerTest
, Stop
) {
181 EXPECT_GT(manager()->GetNextHeartbeatTime(), base::TimeTicks::Now());
184 EXPECT_TRUE(manager()->GetNextHeartbeatTime().is_null());
187 // Simulate missing a heartbeat by manually invoking the check method. The
188 // heartbeat should only be triggered once, and only if the heartbeat timer
189 // is running. Because the period is several minutes, none should fire.
190 TEST_F(HeartbeatManagerTest
, MissedHeartbeat
) {
191 // Do nothing while stopped.
192 manager()->TriggerMissedHeartbeatCheck();
194 EXPECT_EQ(0, heartbeats_sent());
196 // Do nothing before the period is reached.
197 manager()->TriggerMissedHeartbeatCheck();
198 EXPECT_EQ(0, heartbeats_sent());