Home | History | Annotate | Download | only in host
      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/jingle_glue/mock_objects.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 #include "third_party/libjingle/source/talk/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 (at) bot.talk.google.com";
     32 const char kHostId[] = "0";
     33 const char kTestJid[] = "user (at) 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:
     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 
     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 
     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 
     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.
    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.
    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