GN + Android: extract android_standalone_library rule.
[chromium-blink-merge.git] / remoting / host / heartbeat_sender_unittest.cc
blob4a6888c08c03745a147b4bc642cc146fa333db58
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"
7 #include <set>
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/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "remoting/base/constants.h"
15 #include "remoting/base/rsa_key_pair.h"
16 #include "remoting/base/test_rsa_key_pair.h"
17 #include "remoting/host/mock_callback.h"
18 #include "remoting/signaling/iq_sender.h"
19 #include "remoting/signaling/mock_signal_strategy.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
23 #include "third_party/webrtc/libjingle/xmpp/constants.h"
25 using buzz::QName;
26 using buzz::XmlElement;
28 using testing::_;
29 using testing::DeleteArg;
30 using testing::DoAll;
31 using testing::Invoke;
32 using testing::NotNull;
33 using testing::Return;
34 using testing::SaveArg;
36 namespace remoting {
38 namespace {
40 const char kTestBotJid[] = "remotingunittest@bot.talk.google.com";
41 const char kHostId[] = "0";
42 const char kTestJid[] = "user@gmail.com/chromoting123";
43 const char kStanzaId[] = "123";
44 const int kTestInterval = 123;
46 } // namespace
48 ACTION_P(AddListener, list) {
49 list->insert(arg0);
51 ACTION_P(RemoveListener, list) {
52 EXPECT_TRUE(list->find(arg0) != list->end());
53 list->erase(arg0);
56 class HeartbeatSenderTest
57 : public testing::Test {
58 protected:
59 void SetUp() override {
60 key_pair_ = RsaKeyPair::FromString(kTestRsaKeyPair);
61 ASSERT_TRUE(key_pair_.get());
63 EXPECT_CALL(signal_strategy_, GetState())
64 .WillOnce(Return(SignalStrategy::DISCONNECTED));
65 EXPECT_CALL(signal_strategy_, AddListener(NotNull()))
66 .WillRepeatedly(AddListener(&signal_strategy_listeners_));
67 EXPECT_CALL(signal_strategy_, RemoveListener(NotNull()))
68 .WillRepeatedly(RemoveListener(&signal_strategy_listeners_));
69 EXPECT_CALL(signal_strategy_, GetLocalJid())
70 .WillRepeatedly(Return(kTestJid));
71 EXPECT_CALL(mock_unknown_host_id_error_callback_, Run())
72 .Times(0);
74 heartbeat_sender_.reset(new HeartbeatSender(
75 mock_heartbeat_successful_callback_.GetCallback(),
76 mock_unknown_host_id_error_callback_.GetCallback(),
77 kHostId, &signal_strategy_, key_pair_, kTestBotJid));
80 void TearDown() override {
81 heartbeat_sender_.reset();
82 EXPECT_TRUE(signal_strategy_listeners_.empty());
85 void ValidateHeartbeatStanza(XmlElement* stanza,
86 const char* expected_sequence_id,
87 const char* expected_host_offline_reason);
89 void ProcessResponseWithInterval(
90 bool is_offline_heartbeat_response,
91 int interval);
93 base::MessageLoop message_loop_;
94 MockSignalStrategy signal_strategy_;
95 MockClosure mock_heartbeat_successful_callback_;
96 MockClosure mock_unknown_host_id_error_callback_;
97 std::set<SignalStrategy::Listener*> signal_strategy_listeners_;
98 scoped_refptr<RsaKeyPair> key_pair_;
99 scoped_ptr<HeartbeatSender> heartbeat_sender_;
102 // Call Start() followed by Stop(), and make sure a valid heartbeat is sent.
103 TEST_F(HeartbeatSenderTest, DoSendStanza) {
104 XmlElement* sent_iq = NULL;
105 EXPECT_CALL(signal_strategy_, GetLocalJid())
106 .WillRepeatedly(Return(kTestJid));
107 EXPECT_CALL(signal_strategy_, GetNextId())
108 .WillOnce(Return(kStanzaId));
109 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
110 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true)));
111 EXPECT_CALL(signal_strategy_, GetState())
112 .WillRepeatedly(Return(SignalStrategy::CONNECTED));
114 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
115 base::RunLoop().RunUntilIdle();
117 scoped_ptr<XmlElement> stanza(sent_iq);
118 ASSERT_TRUE(stanza != NULL);
119 ValidateHeartbeatStanza(stanza.get(), "0", nullptr);
121 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
122 base::RunLoop().RunUntilIdle();
125 // Call Start() followed by Stop(), twice, and make sure two valid heartbeats
126 // are sent, with the correct sequence IDs.
127 TEST_F(HeartbeatSenderTest, DoSendStanzaTwice) {
128 XmlElement* sent_iq = NULL;
129 EXPECT_CALL(signal_strategy_, GetLocalJid())
130 .WillRepeatedly(Return(kTestJid));
131 EXPECT_CALL(signal_strategy_, GetNextId())
132 .WillOnce(Return(kStanzaId));
133 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
134 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true)));
135 EXPECT_CALL(signal_strategy_, GetState())
136 .WillRepeatedly(Return(SignalStrategy::CONNECTED));
138 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
139 base::RunLoop().RunUntilIdle();
141 scoped_ptr<XmlElement> stanza(sent_iq);
142 ASSERT_TRUE(stanza != NULL);
143 ValidateHeartbeatStanza(stanza.get(), "0", nullptr);
145 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
146 base::RunLoop().RunUntilIdle();
148 EXPECT_CALL(signal_strategy_, GetLocalJid())
149 .WillRepeatedly(Return(kTestJid));
150 EXPECT_CALL(signal_strategy_, GetNextId())
151 .WillOnce(Return(kStanzaId + 1));
152 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
153 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true)));
155 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
156 base::RunLoop().RunUntilIdle();
158 scoped_ptr<XmlElement> stanza2(sent_iq);
159 ValidateHeartbeatStanza(stanza2.get(), "1", nullptr);
161 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
162 base::RunLoop().RunUntilIdle();
165 // Call Start() followed by Stop(), make sure a valid Iq stanza is sent,
166 // reply with an expected sequence ID, and make sure two valid heartbeats
167 // are sent, with the correct sequence IDs.
168 TEST_F(HeartbeatSenderTest, DoSendStanzaWithExpectedSequenceId) {
169 XmlElement* sent_iq = NULL;
170 EXPECT_CALL(signal_strategy_, GetLocalJid())
171 .WillRepeatedly(Return(kTestJid));
172 EXPECT_CALL(signal_strategy_, GetNextId())
173 .WillOnce(Return(kStanzaId));
174 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
175 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true)));
176 EXPECT_CALL(signal_strategy_, GetState())
177 .WillRepeatedly(Return(SignalStrategy::CONNECTED));
179 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
180 base::RunLoop().RunUntilIdle();
182 scoped_ptr<XmlElement> stanza(sent_iq);
183 ASSERT_TRUE(stanza != NULL);
184 ValidateHeartbeatStanza(stanza.get(), "0", nullptr);
186 XmlElement* sent_iq2 = NULL;
187 EXPECT_CALL(signal_strategy_, GetLocalJid())
188 .WillRepeatedly(Return(kTestJid));
189 EXPECT_CALL(signal_strategy_, GetNextId())
190 .WillOnce(Return(kStanzaId + 1));
191 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
192 .WillOnce(DoAll(SaveArg<0>(&sent_iq2), Return(true)));
194 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
195 response->AddAttr(QName(std::string(), "type"), "result");
196 XmlElement* result =
197 new XmlElement(QName(kChromotingXmlNamespace, "heartbeat-result"));
198 response->AddElement(result);
199 XmlElement* expected_sequence_id = new XmlElement(
200 QName(kChromotingXmlNamespace, "expected-sequence-id"));
201 result->AddElement(expected_sequence_id);
202 const int kExpectedSequenceId = 456;
203 expected_sequence_id->AddText(base::IntToString(kExpectedSequenceId));
204 heartbeat_sender_->ProcessResponse(false, NULL, response.get());
205 base::RunLoop().RunUntilIdle();
207 scoped_ptr<XmlElement> stanza2(sent_iq2);
208 ASSERT_TRUE(stanza2 != NULL);
209 ValidateHeartbeatStanza(stanza2.get(),
210 base::IntToString(kExpectedSequenceId).c_str(),
211 nullptr);
213 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
214 base::RunLoop().RunUntilIdle();
217 void HeartbeatSenderTest::ProcessResponseWithInterval(
218 bool is_offline_heartbeat_response,
219 int interval) {
220 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
221 response->AddAttr(QName(std::string(), "type"), "result");
223 XmlElement* result = new XmlElement(
224 QName(kChromotingXmlNamespace, "heartbeat-result"));
225 response->AddElement(result);
227 XmlElement* set_interval = new XmlElement(
228 QName(kChromotingXmlNamespace, "set-interval"));
229 result->AddElement(set_interval);
231 set_interval->AddText(base::IntToString(interval));
233 heartbeat_sender_->ProcessResponse(
234 is_offline_heartbeat_response, NULL, response.get());
237 // Verify that ProcessResponse parses set-interval result.
238 TEST_F(HeartbeatSenderTest, ProcessResponseSetInterval) {
239 EXPECT_CALL(mock_heartbeat_successful_callback_, Run());
241 ProcessResponseWithInterval(false, kTestInterval);
243 EXPECT_EQ(kTestInterval * 1000, heartbeat_sender_->interval_ms_);
246 // Make sure SetHostOfflineReason sends a correct stanza.
247 TEST_F(HeartbeatSenderTest, DoSetHostOfflineReason) {
248 XmlElement* sent_iq = NULL;
249 EXPECT_CALL(signal_strategy_, GetLocalJid())
250 .WillRepeatedly(Return(kTestJid));
251 EXPECT_CALL(signal_strategy_, GetNextId())
252 .WillOnce(Return(kStanzaId));
253 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
254 .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true)));
255 EXPECT_CALL(signal_strategy_, GetState())
256 .WillOnce(Return(SignalStrategy::DISCONNECTED))
257 .WillRepeatedly(Return(SignalStrategy::CONNECTED));
259 heartbeat_sender_->SetHostOfflineReason(
260 "test_error",
261 base::Bind(base::DoNothing));
262 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
263 base::RunLoop().RunUntilIdle();
265 scoped_ptr<XmlElement> stanza(sent_iq);
266 ASSERT_TRUE(stanza != NULL);
267 ValidateHeartbeatStanza(stanza.get(), "0", "test_error");
269 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
270 base::RunLoop().RunUntilIdle();
273 // Make sure SetHostOfflineReason triggers a callback when bot responds.
274 TEST_F(HeartbeatSenderTest, ProcessHostOfflineResponses) {
275 MockClosure mock_ack_callback;
277 EXPECT_CALL(signal_strategy_, GetLocalJid())
278 .WillRepeatedly(Return(kTestJid));
279 EXPECT_CALL(signal_strategy_, GetNextId())
280 .WillOnce(Return(kStanzaId));
281 EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull()))
282 .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
283 EXPECT_CALL(signal_strategy_, GetState())
284 .WillOnce(Return(SignalStrategy::DISCONNECTED))
285 .WillRepeatedly(Return(SignalStrategy::CONNECTED));
286 EXPECT_CALL(mock_heartbeat_successful_callback_, Run())
287 .WillRepeatedly(Return());
289 // Callback should not run, until response to offline-reason.
290 EXPECT_CALL(mock_ack_callback, Run()).Times(0);
292 heartbeat_sender_->SetHostOfflineReason(
293 "test_error",
294 mock_ack_callback.GetCallback());
295 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
296 base::RunLoop().RunUntilIdle();
298 ProcessResponseWithInterval(
299 false, // <- This is not a response to offline-reason.
300 kTestInterval);
301 base::RunLoop().RunUntilIdle();
303 // Callback should run once, when we get response to offline-reason.
304 EXPECT_CALL(mock_ack_callback, Run()).Times(1);
305 ProcessResponseWithInterval(
306 true, // <- This is a response to offline-reason.
307 kTestInterval);
308 base::RunLoop().RunUntilIdle();
310 // When subsequent responses to offline-reason come,
311 // the callback should not be called again.
312 EXPECT_CALL(mock_ack_callback, Run()).Times(0);
313 ProcessResponseWithInterval(true, kTestInterval);
314 base::RunLoop().RunUntilIdle();
316 heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
317 base::RunLoop().RunUntilIdle();
320 // Validate a heartbeat stanza.
321 void HeartbeatSenderTest::ValidateHeartbeatStanza(
322 XmlElement* stanza,
323 const char* expected_sequence_id,
324 const char* expected_host_offline_reason) {
325 EXPECT_EQ(stanza->Attr(buzz::QName(std::string(), "to")),
326 std::string(kTestBotJid));
327 EXPECT_EQ(stanza->Attr(buzz::QName(std::string(), "type")), "set");
328 XmlElement* heartbeat_stanza =
329 stanza->FirstNamed(QName(kChromotingXmlNamespace, "heartbeat"));
330 ASSERT_TRUE(heartbeat_stanza != NULL);
331 EXPECT_EQ(expected_sequence_id, heartbeat_stanza->Attr(
332 buzz::QName(kChromotingXmlNamespace, "sequence-id")));
333 if (expected_host_offline_reason == nullptr) {
334 EXPECT_FALSE(heartbeat_stanza->HasAttr(
335 buzz::QName(kChromotingXmlNamespace, "host-offline-reason")));
336 } else {
337 EXPECT_EQ(expected_host_offline_reason, heartbeat_stanza->Attr(
338 buzz::QName(kChromotingXmlNamespace, "host-offline-reason")));
340 EXPECT_EQ(std::string(kHostId),
341 heartbeat_stanza->Attr(QName(kChromotingXmlNamespace, "hostid")));
343 QName signature_tag(kChromotingXmlNamespace, "signature");
344 XmlElement* signature = heartbeat_stanza->FirstNamed(signature_tag);
345 ASSERT_TRUE(signature != NULL);
346 EXPECT_TRUE(heartbeat_stanza->NextNamed(signature_tag) == NULL);
348 scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::FromString(kTestRsaKeyPair);
349 ASSERT_TRUE(key_pair.get());
350 std::string expected_signature =
351 key_pair->SignMessage(std::string(kTestJid) + ' ' + expected_sequence_id);
352 EXPECT_EQ(expected_signature, signature->BodyText());
355 } // namespace remoting