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