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.
5 #include "remoting/host/host_status_logger.h"
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/libjingle/source/talk/xmllite/xmlelement.h"
16 using buzz::XmlElement
;
19 using testing::DeleteArg
;
20 using testing::InSequence
;
21 using testing::Return
;
27 ACTION_P(QuitMainMessageLoop
, message_loop
) {
28 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
31 const char kJabberClientNamespace
[] = "jabber:client";
32 const char kChromotingNamespace
[] = "google:remoting";
33 const char kTestBotJid
[] = "remotingunittest@bot.talk.google.com";
34 const char kClientJid1
[] = "client@domain.com/1234";
35 const char kClientJid2
[] = "client@domain.com/5678";
36 const char kHostJid
[] = "host@domain.com/1234";
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")) ==
48 MATCHER_P(IsClientConnected
, connection_type
, "") {
49 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
52 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
53 if (log_stanza
->Name() != QName(kChromotingNamespace
, "log")) {
56 if (log_stanza
->NextChild()) {
59 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
60 if (!IsLogEntryForConnection(log_entry
, connection_type
)) {
63 if (log_entry
->NextChild()) {
69 MATCHER_P2(IsTwoClientsConnected
, connection_type1
, connection_type2
, "") {
70 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
73 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
74 if (log_stanza
->Name() != QName(kChromotingNamespace
, "log")) {
77 if (log_stanza
->NextChild()) {
80 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
81 if (!IsLogEntryForConnection(log_entry
, connection_type1
)) {
84 log_entry
= log_entry
->NextChild()->AsElement();
85 if (!IsLogEntryForConnection(log_entry
, connection_type2
)) {
88 if (log_entry
->NextChild()) {
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");
102 MATCHER(IsClientDisconnected
, "") {
103 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
106 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
107 if (log_stanza
->Name() !=QName(kChromotingNamespace
, "log")) {
110 if (log_stanza
->NextChild()) {
113 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
114 if (!IsLogEntryForDisconnection(log_entry
)) {
117 if (log_entry
->NextChild()) {
125 class HostStatusLoggerTest
: public testing::Test
{
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
,
136 EXPECT_CALL(signal_strategy_
, RemoveListener(_
));
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_
;
147 TEST_F(HostStatusLoggerTest
, SendNow
) {
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();
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
);
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
);
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();
189 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
190 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::DISCONNECTED
);
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
);
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();
218 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
219 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::DISCONNECTED
);
223 TEST_F(HostStatusLoggerTest
, HandleRouteChangeInUnusualOrder
) {
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();
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
);
258 } // namespace remoting