1 // Copyright 2013 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/host_status_sender.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/time/time.h"
9 #include "remoting/base/constants.h"
10 #include "remoting/base/logging.h"
11 #include "remoting/base/rsa_key_pair.h"
12 #include "remoting/base/test_rsa_key_pair.h"
13 #include "remoting/host/host_exit_codes.h"
14 #include "remoting/signaling/mock_signal_strategy.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
20 using buzz::XmlElement
;
23 using testing::NotNull
;
24 using testing::Return
;
25 using testing::SaveArg
;
31 const char kTestBotJid
[] = "remotingunittest@bot.talk.google.com";
32 const char kHostId
[] = "0";
33 const char kTestJid
[] = "user@gmail.com/chromoting123";
34 const char kStanzaId
[] = "123";
36 const HostExitCodes kTestExitCode
= kInvalidHostConfigurationExitCode
;
37 const char kTestExitCodeString
[] = "INVALID_HOST_CONFIGURATION";
41 class HostStatusSenderTest
42 : public testing::Test
{
44 virtual void SetUp() OVERRIDE
{
45 key_pair_
= RsaKeyPair::FromString(kTestRsaKeyPair
);
46 ASSERT_TRUE(key_pair_
.get());
48 host_status_sender_
.reset(new HostStatusSender(
49 kHostId
, &signal_strategy_
, key_pair_
, kTestBotJid
));
52 virtual void TearDown() OVERRIDE
{
53 host_status_sender_
.reset();
56 void ValidateHostStatusStanza(XmlElement
* stanza
,
57 HostStatusSender::HostStatus status
);
59 void ValidateSignature(
60 XmlElement
* signature
, HostStatusSender::HostStatus status
);
62 MockSignalStrategy signal_strategy_
;
63 scoped_refptr
<RsaKeyPair
> key_pair_
;
64 scoped_ptr
<HostStatusSender
> host_status_sender_
;
67 TEST_F(HostStatusSenderTest
, SendOnlineStatus
) {
68 XmlElement
* sent_iq
= NULL
;
69 EXPECT_CALL(signal_strategy_
, GetState())
70 .WillOnce(Return(SignalStrategy::DISCONNECTED
))
71 .WillRepeatedly(Return(SignalStrategy::CONNECTED
));
72 EXPECT_CALL(signal_strategy_
, GetLocalJid())
73 .WillRepeatedly(Return(kTestJid
));
74 EXPECT_CALL(signal_strategy_
, GetNextId())
75 .WillOnce(Return(kStanzaId
));
76 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(NotNull()))
77 .WillOnce(DoAll(SaveArg
<0>(&sent_iq
), Return(true)));
79 // Call SendOnlineStatus twice. The first call should be a
80 // no-op because |signal_strategy_| is diconnected.
81 // So we expect SendStanza to be called only once.
82 host_status_sender_
->SendOnlineStatus();
84 host_status_sender_
->OnSignalStrategyStateChange(
85 SignalStrategy::CONNECTED
);
86 host_status_sender_
->SendOnlineStatus();
88 scoped_ptr
<XmlElement
> stanza(sent_iq
);
90 ASSERT_TRUE(stanza
!= NULL
);
92 ValidateHostStatusStanza(stanza
.get(), HostStatusSender::ONLINE
);
95 TEST_F(HostStatusSenderTest
, SendOfflineStatus
) {
96 XmlElement
* sent_iq
= NULL
;
97 EXPECT_CALL(signal_strategy_
, GetState())
98 .WillOnce(Return(SignalStrategy::DISCONNECTED
))
99 .WillRepeatedly(Return(SignalStrategy::CONNECTED
));
100 EXPECT_CALL(signal_strategy_
, GetLocalJid())
101 .WillRepeatedly(Return(kTestJid
));
102 EXPECT_CALL(signal_strategy_
, GetNextId())
103 .WillOnce(Return(kStanzaId
));
104 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(NotNull()))
105 .WillOnce(DoAll(SaveArg
<0>(&sent_iq
), Return(true)));
107 // Call SendOfflineStatus twice. The first call should be a
108 // no-op because |signal_strategy_| is diconnected.
109 // So we expect SendStanza to be called only once.
110 host_status_sender_
->SendOfflineStatus(kTestExitCode
);
112 host_status_sender_
->OnSignalStrategyStateChange(
113 SignalStrategy::CONNECTED
);
114 host_status_sender_
->SendOfflineStatus(kTestExitCode
);
116 scoped_ptr
<XmlElement
> stanza(sent_iq
);
118 ASSERT_TRUE(stanza
!= NULL
);
120 ValidateHostStatusStanza(stanza
.get(), HostStatusSender::OFFLINE
);
123 // Validate a host status stanza.
124 void HostStatusSenderTest::ValidateHostStatusStanza(
125 XmlElement
* stanza
, HostStatusSender::HostStatus status
) {
126 EXPECT_EQ(stanza
->Attr(QName(std::string(), "to")),
127 std::string(kTestBotJid
));
128 EXPECT_EQ(stanza
->Attr(QName(std::string(), "type")), "set");
130 XmlElement
* host_status_stanza
=
131 stanza
->FirstNamed(QName(kChromotingXmlNamespace
, "host-status"));
132 ASSERT_TRUE(host_status_stanza
!= NULL
);
134 if (status
== HostStatusSender::ONLINE
) {
136 host_status_stanza
->Attr(
137 QName(kChromotingXmlNamespace
, "status")));
138 EXPECT_FALSE(host_status_stanza
->HasAttr(
139 QName(kChromotingXmlNamespace
, "exit-code")));
142 host_status_stanza
->Attr(
143 QName(kChromotingXmlNamespace
, "status")));
144 EXPECT_EQ(kTestExitCodeString
,
145 host_status_stanza
->Attr(
146 QName(kChromotingXmlNamespace
, "exit-code")));
149 EXPECT_EQ(std::string(kHostId
),
150 host_status_stanza
->Attr(
151 QName(kChromotingXmlNamespace
, "hostid")));
153 QName
signature_tag(kChromotingXmlNamespace
, "signature");
154 XmlElement
* signature
= host_status_stanza
->FirstNamed(signature_tag
);
155 ASSERT_TRUE(signature
!= NULL
);
156 EXPECT_TRUE(host_status_stanza
->NextNamed(signature_tag
) == NULL
);
158 ValidateSignature(signature
, status
);
161 // Validate the signature.
162 void HostStatusSenderTest::ValidateSignature(
163 XmlElement
* signature
, HostStatusSender::HostStatus status
) {
165 EXPECT_TRUE(signature
->HasAttr(
166 QName(kChromotingXmlNamespace
, "time")));
168 std::string time_str
=
169 signature
->Attr(QName(kChromotingXmlNamespace
, "time"));
172 ASSERT_TRUE(base::StringToInt64(time_str
, &time
));
180 if (status
== HostStatusSender::OFFLINE
) {
181 message
+= "OFFLINE";
183 message
+= kTestExitCodeString
;
188 scoped_refptr
<RsaKeyPair
> key_pair
= RsaKeyPair::FromString(kTestRsaKeyPair
);
189 ASSERT_TRUE(key_pair
.get());
191 std::string expected_signature
=
192 key_pair
->SignMessage(message
);
193 EXPECT_EQ(expected_signature
, signature
->BodyText());
196 } // namespace remoting