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/client/client_status_logger.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop_proxy.h" 9 #include "remoting/client/chromoting_stats.h" 10 #include "remoting/signaling/mock_signal_strategy.h" 11 #include "remoting/signaling/server_log_entry_unittest.h" 12 #include "testing/gmock/include/gmock/gmock.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 remoting::protocol::ConnectionToHost; 19 using testing::_; 20 using testing::DeleteArg; 21 using testing::InSequence; 22 using testing::Return; 23 24 namespace remoting { 25 26 namespace { 27 28 ACTION_P(QuitMainMessageLoop, message_loop) { 29 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 30 } 31 32 const char kTestBotJid[] = "remotingunittest (at) bot.talk.google.com"; 33 const char kClientJid[] = "host (at) domain.com/1234"; 34 35 MATCHER_P2(IsStateChange, new_state, error, "") { 36 XmlElement* entry = GetSingleLogEntryFromStanza(arg); 37 if (!entry) { 38 return false; 39 } 40 41 bool is_state_change = ( 42 entry->Attr(QName(std::string(), "event-name")) == "session-state" && 43 entry->Attr(QName(std::string(), "session-state")) == new_state && 44 entry->Attr(QName(std::string(), "role")) == "client" && 45 entry->Attr(QName(std::string(), "mode")) == "me2me"); 46 if (!std::string(error).empty()) { 47 is_state_change = is_state_change && 48 entry->Attr(QName(std::string(), "connection-error")) == error; 49 } 50 return is_state_change; 51 } 52 53 MATCHER(IsStatisticsLog, "") { 54 XmlElement* entry = GetSingleLogEntryFromStanza(arg); 55 if (!entry) { 56 return false; 57 } 58 59 return entry->Attr(QName(std::string(), "event-name")) == 60 "connection-statistics"; 61 } 62 63 } // namespace 64 65 class ClientStatusLoggerTest : public testing::Test { 66 public: 67 ClientStatusLoggerTest() {} 68 virtual void SetUp() OVERRIDE { 69 EXPECT_CALL(signal_strategy_, AddListener(_)); 70 EXPECT_CALL(signal_strategy_, RemoveListener(_)); 71 message_loop_proxy_ = base::MessageLoopProxy::current(); 72 client_status_logger_.reset( 73 new ClientStatusLogger(ServerLogEntry::ME2ME, 74 &signal_strategy_, 75 kTestBotJid)); 76 } 77 78 protected: 79 base::MessageLoop message_loop_; 80 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; 81 MockSignalStrategy signal_strategy_; 82 scoped_ptr<ClientStatusLogger> client_status_logger_; 83 }; 84 85 TEST_F(ClientStatusLoggerTest, LogStateChange) { 86 { 87 InSequence s; 88 EXPECT_CALL(signal_strategy_, GetLocalJid()) 89 .WillRepeatedly(Return(kClientJid)); 90 EXPECT_CALL(signal_strategy_, AddListener(_)); 91 EXPECT_CALL(signal_strategy_, GetNextId()); 92 EXPECT_CALL(signal_strategy_, SendStanzaPtr( 93 IsStateChange("connected", std::string()))) 94 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); 95 EXPECT_CALL(signal_strategy_, RemoveListener(_)) 96 .WillOnce(QuitMainMessageLoop(&message_loop_)) 97 .RetiresOnSaturation(); 98 } 99 client_status_logger_->LogSessionStateChange(ConnectionToHost::CONNECTED, 100 protocol::OK); 101 102 // Setting the state to CONNECTED causes the log to be sent. Setting the 103 // state to DISCONNECTED causes |signal_strategy_| to be cleaned up, 104 // which removes the listener and terminates the test. 105 client_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED); 106 client_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED); 107 message_loop_.Run(); 108 } 109 110 TEST_F(ClientStatusLoggerTest, LogStateChangeError) { 111 { 112 InSequence s; 113 EXPECT_CALL(signal_strategy_, GetLocalJid()) 114 .WillRepeatedly(Return(kClientJid)); 115 EXPECT_CALL(signal_strategy_, AddListener(_)); 116 EXPECT_CALL(signal_strategy_, GetNextId()); 117 EXPECT_CALL(signal_strategy_, SendStanzaPtr( 118 IsStateChange("connection-failed", "host-is-offline"))) 119 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); 120 EXPECT_CALL(signal_strategy_, RemoveListener(_)) 121 .WillOnce(QuitMainMessageLoop(&message_loop_)) 122 .RetiresOnSaturation(); 123 } 124 client_status_logger_->LogSessionStateChange(ConnectionToHost::FAILED, 125 protocol::PEER_IS_OFFLINE); 126 127 client_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED); 128 client_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED); 129 message_loop_.Run(); 130 } 131 132 TEST_F(ClientStatusLoggerTest, LogStatistics) { 133 { 134 InSequence s; 135 EXPECT_CALL(signal_strategy_, GetLocalJid()) 136 .WillRepeatedly(Return(kClientJid)); 137 EXPECT_CALL(signal_strategy_, AddListener(_)); 138 EXPECT_CALL(signal_strategy_, GetNextId()); 139 EXPECT_CALL(signal_strategy_, SendStanzaPtr( 140 IsStatisticsLog())) 141 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); 142 EXPECT_CALL(signal_strategy_, RemoveListener(_)) 143 .WillOnce(QuitMainMessageLoop(&message_loop_)) 144 .RetiresOnSaturation(); 145 } 146 147 ChromotingStats stats; 148 client_status_logger_->LogStatistics(&stats); 149 150 client_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED); 151 client_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED); 152 message_loop_.Run(); 153 } 154 155 } // namespace remoting 156