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.
5 #include "remoting/host/heartbeat_sender.h"
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"
24 using buzz::XmlElement
;
27 using testing::DeleteArg
;
29 using testing::Invoke
;
30 using testing::NotNull
;
31 using testing::Return
;
32 using testing::SaveArg
;
38 const char kTestBotJid
[] = "remotingunittest@bot.talk.google.com";
39 const char kHostId
[] = "0";
40 const char kTestJid
[] = "user@gmail.com/chromoting123";
41 const char kStanzaId
[] = "123";
43 class MockListener
: public HeartbeatSender::Listener
{
45 // Overridden from HeartbeatSender::Listener
46 virtual void OnUnknownHostIdError() OVERRIDE
{
50 // Overridden from HeartbeatSender::Listener
51 MOCK_METHOD0(OnHeartbeatSuccessful
, void());
56 ACTION_P(AddListener
, list
) {
59 ACTION_P(RemoveListener
, list
) {
60 EXPECT_TRUE(list
->find(arg0
) != list
->end());
64 class HeartbeatSenderTest
65 : public testing::Test
{
67 virtual void SetUp() OVERRIDE
{
68 key_pair_
= RsaKeyPair::FromString(kTestRsaKeyPair
);
69 ASSERT_TRUE(key_pair_
.get());
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
));
80 heartbeat_sender_
.reset(new HeartbeatSender(
81 &mock_listener_
, kHostId
, &signal_strategy_
, key_pair_
, kTestBotJid
));
84 virtual void TearDown() OVERRIDE
{
85 heartbeat_sender_
.reset();
86 EXPECT_TRUE(signal_strategy_listeners_
.empty());
89 void ValidateHeartbeatStanza(XmlElement
* stanza
,
90 const char* expectedSequenceId
);
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_
;
100 // Call Start() followed by Stop(), and make sure a valid heartbeat is sent.
101 TEST_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)));
110 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
111 message_loop_
.RunUntilIdle();
113 scoped_ptr
<XmlElement
> stanza(sent_iq
);
114 ASSERT_TRUE(stanza
!= NULL
);
115 ValidateHeartbeatStanza(stanza
.get(), "0");
117 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
118 message_loop_
.RunUntilIdle();
121 // Call Start() followed by Stop(), twice, and make sure two valid heartbeats
122 // are sent, with the correct sequence IDs.
123 TEST_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)));
132 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
133 message_loop_
.RunUntilIdle();
135 scoped_ptr
<XmlElement
> stanza(sent_iq
);
136 ASSERT_TRUE(stanza
!= NULL
);
137 ValidateHeartbeatStanza(stanza
.get(), "0");
139 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
140 message_loop_
.RunUntilIdle();
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)));
149 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
150 message_loop_
.RunUntilIdle();
152 scoped_ptr
<XmlElement
> stanza2(sent_iq
);
153 ValidateHeartbeatStanza(stanza2
.get(), "1");
155 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
156 message_loop_
.RunUntilIdle();
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.
162 TEST_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)));
171 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
172 message_loop_
.RunUntilIdle();
174 scoped_ptr
<XmlElement
> stanza(sent_iq
);
175 ASSERT_TRUE(stanza
!= NULL
);
176 ValidateHeartbeatStanza(stanza
.get(), "0");
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());
187 scoped_ptr
<XmlElement
> response(new XmlElement(buzz::QN_IQ
));
188 response
->AddAttr(QName(std::string(), "type"), "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();
200 scoped_ptr
<XmlElement
> stanza2(sent_iq2
);
201 ASSERT_TRUE(stanza2
!= NULL
);
202 ValidateHeartbeatStanza(stanza2
.get(),
203 base::IntToString(kExpectedSequenceId
).c_str());
205 heartbeat_sender_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
206 message_loop_
.RunUntilIdle();
209 // Verify that ProcessResponse parses set-interval result.
210 TEST_F(HeartbeatSenderTest
, ProcessResponseSetInterval
) {
211 EXPECT_CALL(mock_listener_
, OnHeartbeatSuccessful());
213 scoped_ptr
<XmlElement
> response(new XmlElement(buzz::QN_IQ
));
214 response
->AddAttr(QName(std::string(), "type"), "result");
216 XmlElement
* result
= new XmlElement(
217 QName(kChromotingXmlNamespace
, "heartbeat-result"));
218 response
->AddElement(result
);
220 XmlElement
* set_interval
= new XmlElement(
221 QName(kChromotingXmlNamespace
, "set-interval"));
222 result
->AddElement(set_interval
);
224 const int kTestInterval
= 123;
225 set_interval
->AddText(base::IntToString(kTestInterval
));
227 heartbeat_sender_
->ProcessResponse(NULL
, response
.get());
229 EXPECT_EQ(kTestInterval
* 1000, heartbeat_sender_
->interval_ms_
);
232 // Validate a heartbeat stanza.
233 void 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")));
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
);
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());
258 } // namespace remoting