Home | History | Annotate | Download | only in host
      1 // Copyright 2014 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_logger.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "remoting/host/fake_host_status_monitor.h"
     10 #include "remoting/signaling/mock_signal_strategy.h"
     11 #include "testing/gmock/include/gmock/gmock.h"
     12 #include "testing/gmock_mutant.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
     15 
     16 using buzz::XmlElement;
     17 using buzz::QName;
     18 using testing::_;
     19 using testing::DeleteArg;
     20 using testing::InSequence;
     21 using testing::Return;
     22 
     23 namespace remoting {
     24 
     25 namespace {
     26 
     27 ACTION_P(QuitMainMessageLoop, message_loop) {
     28   message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     29 }
     30 
     31 const char kJabberClientNamespace[] = "jabber:client";
     32 const char kChromotingNamespace[] = "google:remoting";
     33 const char kTestBotJid[] = "remotingunittest (at) bot.talk.google.com";
     34 const char kClientJid1[] = "client (at) domain.com/1234";
     35 const char kClientJid2[] = "client (at) domain.com/5678";
     36 const char kHostJid[] = "host (at) domain.com/1234";
     37 
     38 bool IsLogEntryForConnection(XmlElement* node, const char* connection_type) {
     39   return (node->Name() == QName(kChromotingNamespace, "entry") &&
     40           node->Attr(QName(std::string(), "event-name")) == "session-state" &&
     41           node->Attr(QName(std::string(), "session-state")) == "connected" &&
     42           node->Attr(QName(std::string(), "role")) == "host" &&
     43           node->Attr(QName(std::string(), "mode")) == "me2me" &&
     44           node->Attr(QName(std::string(), "connection-type")) ==
     45               connection_type);
     46 }
     47 
     48 MATCHER_P(IsClientConnected, connection_type, "") {
     49   if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
     50     return false;
     51   }
     52   buzz::XmlElement* log_stanza = arg->FirstChild()->AsElement();
     53   if (log_stanza->Name() != QName(kChromotingNamespace, "log")) {
     54     return false;
     55   }
     56   if (log_stanza->NextChild()) {
     57     return false;
     58   }
     59   buzz::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
     60   if (!IsLogEntryForConnection(log_entry, connection_type)) {
     61     return false;
     62   }
     63   if (log_entry->NextChild()) {
     64     return false;
     65   }
     66   return true;
     67 }
     68 
     69 MATCHER_P2(IsTwoClientsConnected, connection_type1, connection_type2, "") {
     70   if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
     71     return false;
     72   }
     73   buzz::XmlElement* log_stanza = arg->FirstChild()->AsElement();
     74   if (log_stanza->Name() != QName(kChromotingNamespace, "log")) {
     75     return false;
     76   }
     77   if (log_stanza->NextChild()) {
     78     return false;
     79   }
     80   buzz::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
     81   if (!IsLogEntryForConnection(log_entry, connection_type1)) {
     82     return false;
     83   }
     84   log_entry = log_entry->NextChild()->AsElement();
     85   if (!IsLogEntryForConnection(log_entry, connection_type2)) {
     86     return false;
     87   }
     88   if (log_entry->NextChild()) {
     89     return false;
     90   }
     91   return true;
     92 }
     93 
     94 bool IsLogEntryForDisconnection(XmlElement* node) {
     95   return (node->Name() == QName(kChromotingNamespace, "entry") &&
     96           node->Attr(QName(std::string(), "event-name")) == "session-state" &&
     97           node->Attr(QName(std::string(), "session-state")) == "closed" &&
     98           node->Attr(QName(std::string(), "role")) == "host" &&
     99           node->Attr(QName(std::string(), "mode")) == "me2me");
    100 }
    101 
    102 MATCHER(IsClientDisconnected, "") {
    103   if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
    104     return false;
    105   }
    106   buzz::XmlElement* log_stanza = arg->FirstChild()->AsElement();
    107   if (log_stanza->Name() !=QName(kChromotingNamespace, "log")) {
    108     return false;
    109   }
    110   if (log_stanza->NextChild()) {
    111     return false;
    112   }
    113   buzz::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
    114   if (!IsLogEntryForDisconnection(log_entry)) {
    115     return false;
    116   }
    117   if (log_entry->NextChild()) {
    118     return false;
    119   }
    120   return true;
    121 }
    122 
    123 }  // namespace
    124 
    125 class HostStatusLoggerTest : public testing::Test {
    126  public:
    127   HostStatusLoggerTest() {}
    128   virtual void SetUp() OVERRIDE {
    129     message_loop_proxy_ = base::MessageLoopProxy::current();
    130     EXPECT_CALL(signal_strategy_, AddListener(_));
    131     host_status_logger_.reset(
    132         new HostStatusLogger(host_status_monitor_.AsWeakPtr(),
    133                              ServerLogEntry::ME2ME,
    134                              &signal_strategy_,
    135                              kTestBotJid));
    136     EXPECT_CALL(signal_strategy_, RemoveListener(_));
    137   }
    138 
    139  protected:
    140   base::MessageLoop message_loop_;
    141   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
    142   MockSignalStrategy signal_strategy_;
    143   scoped_ptr<HostStatusLogger> host_status_logger_;
    144   FakeHostStatusMonitor host_status_monitor_;
    145 };
    146 
    147 TEST_F(HostStatusLoggerTest, SendNow) {
    148   {
    149     InSequence s;
    150     EXPECT_CALL(signal_strategy_, GetLocalJid())
    151         .WillRepeatedly(Return(kHostJid));
    152     EXPECT_CALL(signal_strategy_, AddListener(_));
    153     EXPECT_CALL(signal_strategy_, GetNextId());
    154     EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
    155         .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    156     EXPECT_CALL(signal_strategy_, RemoveListener(_))
    157         .WillOnce(QuitMainMessageLoop(&message_loop_))
    158         .RetiresOnSaturation();
    159   }
    160   host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
    161   protocol::TransportRoute route;
    162   route.type = protocol::TransportRoute::DIRECT;
    163   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route);
    164   host_status_logger_->OnClientAuthenticated(kClientJid1);
    165   host_status_logger_->OnClientConnected(kClientJid1);
    166   host_status_logger_->SetSignalingStateForTest(
    167       SignalStrategy::DISCONNECTED);
    168   message_loop_.Run();
    169 }
    170 
    171 TEST_F(HostStatusLoggerTest, SendLater) {
    172   protocol::TransportRoute route;
    173   route.type = protocol::TransportRoute::DIRECT;
    174   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route);
    175   host_status_logger_->OnClientAuthenticated(kClientJid1);
    176   host_status_logger_->OnClientConnected(kClientJid1);
    177   {
    178     InSequence s;
    179     EXPECT_CALL(signal_strategy_, GetLocalJid())
    180         .WillRepeatedly(Return(kHostJid));
    181     EXPECT_CALL(signal_strategy_, AddListener(_));
    182     EXPECT_CALL(signal_strategy_, GetNextId());
    183     EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
    184         .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    185     EXPECT_CALL(signal_strategy_, RemoveListener(_))
    186         .WillOnce(QuitMainMessageLoop(&message_loop_))
    187         .RetiresOnSaturation();
    188   }
    189   host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
    190   host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
    191   message_loop_.Run();
    192 }
    193 
    194 TEST_F(HostStatusLoggerTest, SendTwoEntriesLater) {
    195   protocol::TransportRoute route1;
    196   route1.type = protocol::TransportRoute::DIRECT;
    197   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route1);
    198   host_status_logger_->OnClientAuthenticated(kClientJid1);
    199   host_status_logger_->OnClientConnected(kClientJid1);
    200   protocol::TransportRoute route2;
    201   route2.type = protocol::TransportRoute::STUN;
    202   host_status_logger_->OnClientRouteChange(kClientJid2, "video", route2);
    203   host_status_logger_->OnClientAuthenticated(kClientJid2);
    204   host_status_logger_->OnClientConnected(kClientJid2);
    205   {
    206     InSequence s;
    207     EXPECT_CALL(signal_strategy_, GetLocalJid())
    208         .WillRepeatedly(Return(kHostJid));
    209     EXPECT_CALL(signal_strategy_, AddListener(_));
    210     EXPECT_CALL(signal_strategy_, GetNextId());
    211     EXPECT_CALL(signal_strategy_,
    212         SendStanzaPtr(IsTwoClientsConnected("direct", "stun")))
    213             .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    214     EXPECT_CALL(signal_strategy_, RemoveListener(_))
    215         .WillOnce(QuitMainMessageLoop(&message_loop_))
    216         .RetiresOnSaturation();
    217   }
    218   host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
    219   host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
    220   message_loop_.Run();
    221 }
    222 
    223 TEST_F(HostStatusLoggerTest, HandleRouteChangeInUnusualOrder) {
    224   {
    225     InSequence s;
    226     EXPECT_CALL(signal_strategy_, GetLocalJid())
    227         .WillRepeatedly(Return(kHostJid));
    228     EXPECT_CALL(signal_strategy_, AddListener(_));
    229     EXPECT_CALL(signal_strategy_, GetNextId());
    230     EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
    231         .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    232     EXPECT_CALL(signal_strategy_, GetNextId());
    233     EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientDisconnected()))
    234         .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    235     EXPECT_CALL(signal_strategy_, GetNextId());
    236     EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("stun")))
    237         .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
    238     EXPECT_CALL(signal_strategy_, RemoveListener(_))
    239         .WillOnce(QuitMainMessageLoop(&message_loop_))
    240         .RetiresOnSaturation();
    241   }
    242   host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
    243   protocol::TransportRoute route1;
    244   route1.type = protocol::TransportRoute::DIRECT;
    245   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route1);
    246   host_status_logger_->OnClientAuthenticated(kClientJid1);
    247   host_status_logger_->OnClientConnected(kClientJid1);
    248   protocol::TransportRoute route2;
    249   route2.type = protocol::TransportRoute::STUN;
    250   host_status_logger_->OnClientRouteChange(kClientJid2, "video", route2);
    251   host_status_logger_->OnClientDisconnected(kClientJid1);
    252   host_status_logger_->OnClientAuthenticated(kClientJid2);
    253   host_status_logger_->OnClientConnected(kClientJid2);
    254   host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
    255   message_loop_.Run();
    256 }
    257 
    258 }  // namespace remoting
    259