Home | History | Annotate | Download | only in engine
      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