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.
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"
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 LogToServerTest
: public testing::Test
{
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
,
135 EXPECT_CALL(signal_strategy_
, RemoveListener(_
));
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_
;
146 TEST_F(LogToServerTest
, SendNow
) {
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();
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
);
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
);
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();
187 log_to_server_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
188 log_to_server_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
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
);
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();
216 log_to_server_
->OnSignalStrategyStateChange(SignalStrategy::CONNECTED
);
217 log_to_server_
->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED
);
221 TEST_F(LogToServerTest
, HandleRouteChangeInUnusualOrder
) {
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();
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
);
256 } // namespace remoting