• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "remoting/host/host_status_sender.h"
6 
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"
18 
19 using buzz::QName;
20 using buzz::XmlElement;
21 
22 using testing::DoAll;
23 using testing::NotNull;
24 using testing::Return;
25 using testing::SaveArg;
26 
27 namespace remoting {
28 
29 namespace {
30 
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";
35 
36 const HostExitCodes kTestExitCode = kInvalidHostConfigurationExitCode;
37 const char kTestExitCodeString[] = "INVALID_HOST_CONFIGURATION";
38 
39 }  // namespace
40 
41 class HostStatusSenderTest
42     : public testing::Test {
43  protected:
SetUp()44   virtual void SetUp() OVERRIDE {
45     key_pair_ = RsaKeyPair::FromString(kTestRsaKeyPair);
46     ASSERT_TRUE(key_pair_.get());
47 
48     host_status_sender_.reset(new HostStatusSender(
49         kHostId, &signal_strategy_, key_pair_, kTestBotJid));
50   }
51 
TearDown()52   virtual void TearDown() OVERRIDE {
53     host_status_sender_.reset();
54   }
55 
56   void ValidateHostStatusStanza(XmlElement* stanza,
57                                 HostStatusSender::HostStatus status);
58 
59   void ValidateSignature(
60       XmlElement* signature, HostStatusSender::HostStatus status);
61 
62   MockSignalStrategy signal_strategy_;
63   scoped_refptr<RsaKeyPair> key_pair_;
64   scoped_ptr<HostStatusSender> host_status_sender_;
65 };
66 
TEST_F(HostStatusSenderTest,SendOnlineStatus)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)));
78 
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();
83 
84   host_status_sender_->OnSignalStrategyStateChange(
85       SignalStrategy::CONNECTED);
86   host_status_sender_->SendOnlineStatus();
87 
88   scoped_ptr<XmlElement> stanza(sent_iq);
89 
90   ASSERT_TRUE(stanza != NULL);
91 
92   ValidateHostStatusStanza(stanza.get(), HostStatusSender::ONLINE);
93 }
94 
TEST_F(HostStatusSenderTest,SendOfflineStatus)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)));
106 
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);
111 
112   host_status_sender_->OnSignalStrategyStateChange(
113       SignalStrategy::CONNECTED);
114   host_status_sender_->SendOfflineStatus(kTestExitCode);
115 
116   scoped_ptr<XmlElement> stanza(sent_iq);
117 
118   ASSERT_TRUE(stanza != NULL);
119 
120   ValidateHostStatusStanza(stanza.get(), HostStatusSender::OFFLINE);
121 }
122 
123 // Validate a host status stanza.
ValidateHostStatusStanza(XmlElement * stanza,HostStatusSender::HostStatus status)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");
129 
130   XmlElement* host_status_stanza =
131       stanza->FirstNamed(QName(kChromotingXmlNamespace, "host-status"));
132   ASSERT_TRUE(host_status_stanza != NULL);
133 
134   if (status == HostStatusSender::ONLINE) {
135     EXPECT_EQ("ONLINE",
136               host_status_stanza->Attr(
137                   QName(kChromotingXmlNamespace, "status")));
138     EXPECT_FALSE(host_status_stanza->HasAttr(
139         QName(kChromotingXmlNamespace, "exit-code")));
140   } else {
141     EXPECT_EQ("OFFLINE",
142               host_status_stanza->Attr(
143                   QName(kChromotingXmlNamespace, "status")));
144     EXPECT_EQ(kTestExitCodeString,
145               host_status_stanza->Attr(
146                   QName(kChromotingXmlNamespace, "exit-code")));
147   }
148 
149   EXPECT_EQ(std::string(kHostId),
150             host_status_stanza->Attr(
151                 QName(kChromotingXmlNamespace, "hostid")));
152 
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);
157 
158   ValidateSignature(signature, status);
159 }
160 
161 // Validate the signature.
ValidateSignature(XmlElement * signature,HostStatusSender::HostStatus status)162 void HostStatusSenderTest::ValidateSignature(
163     XmlElement* signature, HostStatusSender::HostStatus status) {
164 
165   EXPECT_TRUE(signature->HasAttr(
166       QName(kChromotingXmlNamespace, "time")));
167 
168   std::string time_str =
169       signature->Attr(QName(kChromotingXmlNamespace, "time"));
170 
171   int64 time;
172   ASSERT_TRUE(base::StringToInt64(time_str, &time));
173 
174   std::string message;
175   message += kTestJid;
176   message += " ";
177   message += time_str;
178   message += " ";
179 
180   if (status == HostStatusSender::OFFLINE) {
181     message += "OFFLINE";
182     message += " ";
183     message += kTestExitCodeString;
184   } else {
185     message += "ONLINE";
186   }
187 
188   scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::FromString(kTestRsaKeyPair);
189   ASSERT_TRUE(key_pair.get());
190 
191   std::string expected_signature =
192       key_pair->SignMessage(message);
193   EXPECT_EQ(expected_signature, signature->BodyText());
194 }
195 
196 }  // namespace remoting
197