heartbeat_sender_unittest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
1// Copyright (c) 2012 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 "remoting/host/heartbeat_sender.h" 6 7#include <set> 8 9#include "base/memory/ref_counted.h" 10#include "base/message_loop/message_loop.h" 11#include "base/message_loop/message_loop_proxy.h" 12#include "base/strings/string_number_conversions.h" 13#include "remoting/base/constants.h" 14#include "remoting/base/rsa_key_pair.h" 15#include "remoting/base/test_rsa_key_pair.h" 16#include "remoting/jingle_glue/iq_sender.h" 17#include "remoting/jingle_glue/mock_objects.h" 18#include "testing/gmock/include/gmock/gmock.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" 21#include "third_party/libjingle/source/talk/xmpp/constants.h" 22 23using buzz::QName; 24using buzz::XmlElement; 25 26using testing::_; 27using testing::DeleteArg; 28using testing::DoAll; 29using testing::Invoke; 30using testing::NotNull; 31using testing::Return; 32using testing::SaveArg; 33 34namespace remoting { 35 36namespace { 37 38const char kTestBotJid[] = "remotingunittest@bot.talk.google.com"; 39const char kHostId[] = "0"; 40const char kTestJid[] = "user@gmail.com/chromoting123"; 41const char kStanzaId[] = "123"; 42 43class MockListener : public HeartbeatSender::Listener { 44 public: 45 // Overridden from HeartbeatSender::Listener 46 virtual void OnUnknownHostIdError() OVERRIDE { 47 NOTREACHED(); 48 } 49 50 // Overridden from HeartbeatSender::Listener 51 MOCK_METHOD0(OnHeartbeatSuccessful, void()); 52}; 53 54} // namespace 55 56ACTION_P(AddListener, list) { 57 list->insert(arg0); 58} 59ACTION_P(RemoveListener, list) { 60 EXPECT_TRUE(list->find(arg0) != list->end()); 61 list->erase(arg0); 62} 63 64class HeartbeatSenderTest 65 : public testing::Test { 66 protected: 67 virtual void SetUp() OVERRIDE { 68 key_pair_ = RsaKeyPair::FromString(kTestRsaKeyPair); 69 ASSERT_TRUE(key_pair_.get()); 70 71 EXPECT_CALL(signal_strategy_, GetState()) 72 .WillOnce(Return(SignalStrategy::DISCONNECTED)); 73 EXPECT_CALL(signal_strategy_, AddListener(NotNull())) 74 .WillRepeatedly(AddListener(&signal_strategy_listeners_)); 75 EXPECT_CALL(signal_strategy_, RemoveListener(NotNull())) 76 .WillRepeatedly(RemoveListener(&signal_strategy_listeners_)); 77 EXPECT_CALL(signal_strategy_, GetLocalJid()) 78 .WillRepeatedly(Return(kTestJid)); 79 80 heartbeat_sender_.reset(new HeartbeatSender( 81 &mock_listener_, kHostId, &signal_strategy_, key_pair_, kTestBotJid)); 82 } 83 84 virtual void TearDown() OVERRIDE { 85 heartbeat_sender_.reset(); 86 EXPECT_TRUE(signal_strategy_listeners_.empty()); 87 } 88 89 void ValidateHeartbeatStanza(XmlElement* stanza, 90 const char* expectedSequenceId); 91 92 base::MessageLoop message_loop_; 93 MockSignalStrategy signal_strategy_; 94 MockListener mock_listener_; 95 std::set<SignalStrategy::Listener*> signal_strategy_listeners_; 96 scoped_refptr<RsaKeyPair> key_pair_; 97 scoped_ptr<HeartbeatSender> heartbeat_sender_; 98}; 99 100// Call Start() followed by Stop(), and make sure a valid heartbeat is sent. 101TEST_F(HeartbeatSenderTest, DoSendStanza) { 102 XmlElement* sent_iq = NULL; 103 EXPECT_CALL(signal_strategy_, GetLocalJid()) 104 .WillRepeatedly(Return(kTestJid)); 105 EXPECT_CALL(signal_strategy_, GetNextId()) 106 .WillOnce(Return(kStanzaId)); 107 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) 108 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true))); 109 110 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); 111 message_loop_.RunUntilIdle(); 112 113 scoped_ptr<XmlElement> stanza(sent_iq); 114 ASSERT_TRUE(stanza != NULL); 115 ValidateHeartbeatStanza(stanza.get(), "0"); 116 117 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED); 118 message_loop_.RunUntilIdle(); 119} 120 121// Call Start() followed by Stop(), twice, and make sure two valid heartbeats 122// are sent, with the correct sequence IDs. 123TEST_F(HeartbeatSenderTest, DoSendStanzaTwice) { 124 XmlElement* sent_iq = NULL; 125 EXPECT_CALL(signal_strategy_, GetLocalJid()) 126 .WillRepeatedly(Return(kTestJid)); 127 EXPECT_CALL(signal_strategy_, GetNextId()) 128 .WillOnce(Return(kStanzaId)); 129 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) 130 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true))); 131 132 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); 133 message_loop_.RunUntilIdle(); 134 135 scoped_ptr<XmlElement> stanza(sent_iq); 136 ASSERT_TRUE(stanza != NULL); 137 ValidateHeartbeatStanza(stanza.get(), "0"); 138 139 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED); 140 message_loop_.RunUntilIdle(); 141 142 EXPECT_CALL(signal_strategy_, GetLocalJid()) 143 .WillRepeatedly(Return(kTestJid)); 144 EXPECT_CALL(signal_strategy_, GetNextId()) 145 .WillOnce(Return(kStanzaId + 1)); 146 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) 147 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true))); 148 149 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); 150 message_loop_.RunUntilIdle(); 151 152 scoped_ptr<XmlElement> stanza2(sent_iq); 153 ValidateHeartbeatStanza(stanza2.get(), "1"); 154 155 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED); 156 message_loop_.RunUntilIdle(); 157} 158 159// Call Start() followed by Stop(), make sure a valid Iq stanza is sent, 160// reply with an expected sequence ID, and make sure two valid heartbeats 161// are sent, with the correct sequence IDs. 162TEST_F(HeartbeatSenderTest, DoSendStanzaWithExpectedSequenceId) { 163 XmlElement* sent_iq = NULL; 164 EXPECT_CALL(signal_strategy_, GetLocalJid()) 165 .WillRepeatedly(Return(kTestJid)); 166 EXPECT_CALL(signal_strategy_, GetNextId()) 167 .WillOnce(Return(kStanzaId)); 168 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) 169 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true))); 170 171 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); 172 message_loop_.RunUntilIdle(); 173 174 scoped_ptr<XmlElement> stanza(sent_iq); 175 ASSERT_TRUE(stanza != NULL); 176 ValidateHeartbeatStanza(stanza.get(), "0"); 177 178 XmlElement* sent_iq2 = NULL; 179 EXPECT_CALL(signal_strategy_, GetLocalJid()) 180 .WillRepeatedly(Return(kTestJid)); 181 EXPECT_CALL(signal_strategy_, GetNextId()) 182 .WillOnce(Return(kStanzaId + 1)); 183 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) 184 .WillOnce(DoAll(SaveArg<0>(&sent_iq2), Return(true))); 185 EXPECT_CALL(mock_listener_, OnHeartbeatSuccessful()); 186 187 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ)); 188 response->AddAttr(QName(std::string(), "type"), "result"); 189 XmlElement* result = 190 new XmlElement(QName(kChromotingXmlNamespace, "heartbeat-result")); 191 response->AddElement(result); 192 XmlElement* expected_sequence_id = new XmlElement( 193 QName(kChromotingXmlNamespace, "expected-sequence-id")); 194 result->AddElement(expected_sequence_id); 195 const int kExpectedSequenceId = 456; 196 expected_sequence_id->AddText(base::IntToString(kExpectedSequenceId)); 197 heartbeat_sender_->ProcessResponse(NULL, response.get()); 198 message_loop_.RunUntilIdle(); 199 200 scoped_ptr<XmlElement> stanza2(sent_iq2); 201 ASSERT_TRUE(stanza2 != NULL); 202 ValidateHeartbeatStanza(stanza2.get(), 203 base::IntToString(kExpectedSequenceId).c_str()); 204 205 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED); 206 message_loop_.RunUntilIdle(); 207} 208 209// Verify that ProcessResponse parses set-interval result. 210TEST_F(HeartbeatSenderTest, ProcessResponseSetInterval) { 211 EXPECT_CALL(mock_listener_, OnHeartbeatSuccessful()); 212 213 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ)); 214 response->AddAttr(QName(std::string(), "type"), "result"); 215 216 XmlElement* result = new XmlElement( 217 QName(kChromotingXmlNamespace, "heartbeat-result")); 218 response->AddElement(result); 219 220 XmlElement* set_interval = new XmlElement( 221 QName(kChromotingXmlNamespace, "set-interval")); 222 result->AddElement(set_interval); 223 224 const int kTestInterval = 123; 225 set_interval->AddText(base::IntToString(kTestInterval)); 226 227 heartbeat_sender_->ProcessResponse(NULL, response.get()); 228 229 EXPECT_EQ(kTestInterval * 1000, heartbeat_sender_->interval_ms_); 230} 231 232// Validate a heartbeat stanza. 233void HeartbeatSenderTest::ValidateHeartbeatStanza( 234 XmlElement* stanza, const char* expectedSequenceId) { 235 EXPECT_EQ(stanza->Attr(buzz::QName(std::string(), "to")), 236 std::string(kTestBotJid)); 237 EXPECT_EQ(stanza->Attr(buzz::QName(std::string(), "type")), "set"); 238 XmlElement* heartbeat_stanza = 239 stanza->FirstNamed(QName(kChromotingXmlNamespace, "heartbeat")); 240 ASSERT_TRUE(heartbeat_stanza != NULL); 241 EXPECT_EQ(expectedSequenceId, heartbeat_stanza->Attr( 242 buzz::QName(kChromotingXmlNamespace, "sequence-id"))); 243 EXPECT_EQ(std::string(kHostId), 244 heartbeat_stanza->Attr(QName(kChromotingXmlNamespace, "hostid"))); 245 246 QName signature_tag(kChromotingXmlNamespace, "signature"); 247 XmlElement* signature = heartbeat_stanza->FirstNamed(signature_tag); 248 ASSERT_TRUE(signature != NULL); 249 EXPECT_TRUE(heartbeat_stanza->NextNamed(signature_tag) == NULL); 250 251 scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::FromString(kTestRsaKeyPair); 252 ASSERT_TRUE(key_pair.get()); 253 std::string expected_signature = 254 key_pair->SignMessage(std::string(kTestJid) + ' ' + expectedSequenceId); 255 EXPECT_EQ(expected_signature, signature->BodyText()); 256} 257 258} // namespace remoting 259