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 "remoting/host/fake_host_status_monitor.h"
9 #include "remoting/signaling/mock_signal_strategy.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/webrtc/libjingle/xmllite/xmlelement.h"
15 using buzz::XmlElement
;
18 using testing::DeleteArg
;
19 using testing::InSequence
;
20 using testing::Return
;
26 ACTION_P(QuitMainMessageLoop
, message_loop
) {
27 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
30 const char kJabberClientNamespace
[] = "jabber:client";
31 const char kChromotingNamespace
[] = "google:remoting";
32 const char kTestBotJid
[] = "remotingunittest@bot.talk.google.com";
33 const char kClientJid1
[] = "client@domain.com/1234";
34 const char kClientJid2
[] = "client@domain.com/5678";
35 const char kHostJid
[] = "host@domain.com/1234";
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")) ==
47 MATCHER_P(IsClientConnected
, connection_type
, "") {
48 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
51 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
52 if (log_stanza
->Name() != QName(kChromotingNamespace
, "log")) {
55 if (log_stanza
->NextChild()) {
58 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
59 if (!IsLogEntryForConnection(log_entry
, connection_type
)) {
62 if (log_entry
->NextChild()) {
68 MATCHER_P2(IsTwoClientsConnected
, connection_type1
, connection_type2
, "") {
69 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
72 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
73 if (log_stanza
->Name() != QName(kChromotingNamespace
, "log")) {
76 if (log_stanza
->NextChild()) {
79 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
80 if (!IsLogEntryForConnection(log_entry
, connection_type1
)) {
83 log_entry
= log_entry
->NextChild()->AsElement();
84 if (!IsLogEntryForConnection(log_entry
, connection_type2
)) {
87 if (log_entry
->NextChild()) {
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");
101 MATCHER(IsClientDisconnected
, "") {
102 if (arg
->Name() != QName(kJabberClientNamespace
, "iq")) {
105 buzz::XmlElement
* log_stanza
= arg
->FirstChild()->AsElement();
106 if (log_stanza
->Name() !=QName(kChromotingNamespace
, "log")) {
109 if (log_stanza
->NextChild()) {
112 buzz::XmlElement
* log_entry
= log_stanza
->FirstChild()->AsElement();
113 if (!IsLogEntryForDisconnection(log_entry
)) {
116 if (log_entry
->NextChild()) {
124 class HostStatusLoggerTest
: public testing::Test
{
126 HostStatusLoggerTest() {}
127 void SetUp() override
{
128 EXPECT_CALL(signal_strategy_
, AddListener(_
));
129 host_status_logger_
.reset(
130 new HostStatusLogger(host_status_monitor_
.AsWeakPtr(),
131 ServerLogEntry::ME2ME
,
134 EXPECT_CALL(signal_strategy_
, RemoveListener(_
));
138 base::MessageLoop message_loop_
;
139 MockSignalStrategy signal_strategy_
;
140 scoped_ptr
<HostStatusLogger
> host_status_logger_
;
141 FakeHostStatusMonitor host_status_monitor_
;
144 TEST_F(HostStatusLoggerTest
, SendNow
) {
147 EXPECT_CALL(signal_strategy_
, GetLocalJid())
148 .WillRepeatedly(Return(kHostJid
));
149 EXPECT_CALL(signal_strategy_
, AddListener(_
));
150 EXPECT_CALL(signal_strategy_
, GetNextId());
151 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(IsClientConnected("direct")))
152 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
153 EXPECT_CALL(signal_strategy_
, RemoveListener(_
))
154 .WillOnce(QuitMainMessageLoop(&message_loop_
))
155 .RetiresOnSaturation();
157 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
158 protocol::TransportRoute route
;
159 route
.type
= protocol::TransportRoute::DIRECT
;
160 host_status_logger_
->OnClientRouteChange(kClientJid1
, "video", route
);
161 host_status_logger_
->OnClientAuthenticated(kClientJid1
);
162 host_status_logger_
->OnClientConnected(kClientJid1
);
163 host_status_logger_
->SetSignalingStateForTest(
164 SignalStrategy::DISCONNECTED
);
168 TEST_F(HostStatusLoggerTest
, SendLater
) {
169 protocol::TransportRoute route
;
170 route
.type
= protocol::TransportRoute::DIRECT
;
171 host_status_logger_
->OnClientRouteChange(kClientJid1
, "video", route
);
172 host_status_logger_
->OnClientAuthenticated(kClientJid1
);
173 host_status_logger_
->OnClientConnected(kClientJid1
);
176 EXPECT_CALL(signal_strategy_
, GetLocalJid())
177 .WillRepeatedly(Return(kHostJid
));
178 EXPECT_CALL(signal_strategy_
, AddListener(_
));
179 EXPECT_CALL(signal_strategy_
, GetNextId());
180 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(IsClientConnected("direct")))
181 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
182 EXPECT_CALL(signal_strategy_
, RemoveListener(_
))
183 .WillOnce(QuitMainMessageLoop(&message_loop_
))
184 .RetiresOnSaturation();
186 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
187 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::DISCONNECTED
);
191 TEST_F(HostStatusLoggerTest
, SendTwoEntriesLater
) {
192 protocol::TransportRoute route1
;
193 route1
.type
= protocol::TransportRoute::DIRECT
;
194 host_status_logger_
->OnClientRouteChange(kClientJid1
, "video", route1
);
195 host_status_logger_
->OnClientAuthenticated(kClientJid1
);
196 host_status_logger_
->OnClientConnected(kClientJid1
);
197 protocol::TransportRoute route2
;
198 route2
.type
= protocol::TransportRoute::STUN
;
199 host_status_logger_
->OnClientRouteChange(kClientJid2
, "video", route2
);
200 host_status_logger_
->OnClientAuthenticated(kClientJid2
);
201 host_status_logger_
->OnClientConnected(kClientJid2
);
204 EXPECT_CALL(signal_strategy_
, GetLocalJid())
205 .WillRepeatedly(Return(kHostJid
));
206 EXPECT_CALL(signal_strategy_
, AddListener(_
));
207 EXPECT_CALL(signal_strategy_
, GetNextId());
208 EXPECT_CALL(signal_strategy_
,
209 SendStanzaPtr(IsTwoClientsConnected("direct", "stun")))
210 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
211 EXPECT_CALL(signal_strategy_
, RemoveListener(_
))
212 .WillOnce(QuitMainMessageLoop(&message_loop_
))
213 .RetiresOnSaturation();
215 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
216 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::DISCONNECTED
);
220 TEST_F(HostStatusLoggerTest
, HandleRouteChangeInUnusualOrder
) {
223 EXPECT_CALL(signal_strategy_
, GetLocalJid())
224 .WillRepeatedly(Return(kHostJid
));
225 EXPECT_CALL(signal_strategy_
, AddListener(_
));
226 EXPECT_CALL(signal_strategy_
, GetNextId());
227 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(IsClientConnected("direct")))
228 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
229 EXPECT_CALL(signal_strategy_
, GetNextId());
230 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(IsClientDisconnected()))
231 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
232 EXPECT_CALL(signal_strategy_
, GetNextId());
233 EXPECT_CALL(signal_strategy_
, SendStanzaPtr(IsClientConnected("stun")))
234 .WillOnce(DoAll(DeleteArg
<0>(), Return(true)));
235 EXPECT_CALL(signal_strategy_
, RemoveListener(_
))
236 .WillOnce(QuitMainMessageLoop(&message_loop_
))
237 .RetiresOnSaturation();
239 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::CONNECTED
);
240 protocol::TransportRoute route1
;
241 route1
.type
= protocol::TransportRoute::DIRECT
;
242 host_status_logger_
->OnClientRouteChange(kClientJid1
, "video", route1
);
243 host_status_logger_
->OnClientAuthenticated(kClientJid1
);
244 host_status_logger_
->OnClientConnected(kClientJid1
);
245 protocol::TransportRoute route2
;
246 route2
.type
= protocol::TransportRoute::STUN
;
247 host_status_logger_
->OnClientRouteChange(kClientJid2
, "video", route2
);
248 host_status_logger_
->OnClientDisconnected(kClientJid1
);
249 host_status_logger_
->OnClientAuthenticated(kClientJid2
);
250 host_status_logger_
->OnClientConnected(kClientJid2
);
251 host_status_logger_
->SetSignalingStateForTest(SignalStrategy::DISCONNECTED
);
255 } // namespace remoting