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/bind.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "remoting/jingle_glue/iq_sender.h"
10 #include "remoting/jingle_glue/mock_objects.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
14 #include "third_party/libjingle/source/talk/xmpp/constants.h"
15
16 using ::testing::_;
17 using ::testing::DeleteArg;
18 using ::testing::InvokeWithoutArgs;
19 using ::testing::NotNull;
20 using ::testing::Return;
21 using ::testing::SaveArg;
22
23 using ::buzz::QName;
24 using ::buzz::XmlElement;
25
26 namespace remoting {
27
28 namespace {
29
30 const char kStanzaId[] = "123";
31 const char kNamespace[] = "chromium:testns";
32 const char kNamespacePrefix[] = "tes";
33 const char kBodyTag[] = "test";
34 const char kType[] = "get";
35 const char kTo[] = "user@domain.com";
36
37 class MockCallback {
38 public:
39 MOCK_METHOD2(OnReply, void(IqRequest* request, const XmlElement* reply));
40 };
41
42 MATCHER_P(XmlEq, expected, "") {
43 return arg->Str() == expected->Str();
44 }
45
46 } // namespace
47
48 class IqSenderTest : public testing::Test {
49 public:
IqSenderTest()50 IqSenderTest() {
51 EXPECT_CALL(signal_strategy_, AddListener(NotNull()));
52 sender_.reset(new IqSender(&signal_strategy_));
53 EXPECT_CALL(signal_strategy_, RemoveListener(
54 static_cast<SignalStrategy::Listener*>(sender_.get())));
55 }
56
57 protected:
SendTestMessage()58 void SendTestMessage() {
59 scoped_ptr<XmlElement> iq_body(
60 new XmlElement(QName(kNamespace, kBodyTag)));
61 XmlElement* sent_stanza;
62 EXPECT_CALL(signal_strategy_, GetNextId())
63 .WillOnce(Return(kStanzaId));
64 EXPECT_CALL(signal_strategy_, SendStanzaPtr(_))
65 .WillOnce(DoAll(SaveArg<0>(&sent_stanza), Return(true)));
66 request_ = sender_->SendIq(kType, kTo, iq_body.Pass(), base::Bind(
67 &MockCallback::OnReply, base::Unretained(&callback_)));
68
69 std::string expected_xml_string =
70 base::StringPrintf(
71 "<cli:iq type=\"%s\" to=\"%s\" id=\"%s\" "
72 "xmlns:cli=\"jabber:client\">"
73 "<%s:%s xmlns:%s=\"%s\"/>"
74 "</cli:iq>",
75 kType, kTo, kStanzaId, kNamespacePrefix, kBodyTag,
76 kNamespacePrefix, kNamespace);
77 EXPECT_EQ(expected_xml_string, sent_stanza->Str());
78 delete sent_stanza;
79 }
80
81 base::MessageLoop message_loop_;
82 MockSignalStrategy signal_strategy_;
83 scoped_ptr<IqSender> sender_;
84 MockCallback callback_;
85 scoped_ptr<IqRequest> request_;
86 };
87
TEST_F(IqSenderTest,SendIq)88 TEST_F(IqSenderTest, SendIq) {
89 ASSERT_NO_FATAL_FAILURE({
90 SendTestMessage();
91 });
92
93 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
94 response->AddAttr(QName(std::string(), "type"), "result");
95 response->AddAttr(QName(std::string(), "id"), kStanzaId);
96 response->AddAttr(QName(std::string(), "from"), kTo);
97
98 XmlElement* result = new XmlElement(
99 QName("test:namespace", "response-body"));
100 response->AddElement(result);
101
102 EXPECT_TRUE(sender_->OnSignalStrategyIncomingStanza(response.get()));
103
104 EXPECT_CALL(callback_, OnReply(request_.get(), XmlEq(response.get())));
105 message_loop_.RunUntilIdle();
106 }
107
TEST_F(IqSenderTest,Timeout)108 TEST_F(IqSenderTest, Timeout) {
109 ASSERT_NO_FATAL_FAILURE({
110 SendTestMessage();
111 });
112
113 request_->SetTimeout(base::TimeDelta::FromMilliseconds(2));
114
115 EXPECT_CALL(callback_, OnReply(request_.get(), NULL))
116 .WillOnce(InvokeWithoutArgs(&message_loop_, &base::MessageLoop::Quit));
117 message_loop_.Run();
118 }
119
TEST_F(IqSenderTest,InvalidFrom)120 TEST_F(IqSenderTest, InvalidFrom) {
121 ASSERT_NO_FATAL_FAILURE({
122 SendTestMessage();
123 });
124
125 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
126 response->AddAttr(QName(std::string(), "type"), "result");
127 response->AddAttr(QName(std::string(), "id"), kStanzaId);
128 response->AddAttr(QName(std::string(), "from"), "different_user@domain.com");
129
130 XmlElement* result = new XmlElement(
131 QName("test:namespace", "response-body"));
132 response->AddElement(result);
133
134 EXPECT_CALL(callback_, OnReply(_, _))
135 .Times(0);
136 EXPECT_FALSE(sender_->OnSignalStrategyIncomingStanza(response.get()));
137 message_loop_.RunUntilIdle();
138 }
139
TEST_F(IqSenderTest,IdMatchingHack)140 TEST_F(IqSenderTest, IdMatchingHack) {
141 ASSERT_NO_FATAL_FAILURE({
142 SendTestMessage();
143 });
144
145 scoped_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
146 response->AddAttr(QName(std::string(), "type"), "result");
147 response->AddAttr(QName(std::string(), "id"), "DIFFERENT_ID");
148 response->AddAttr(QName(std::string(), "from"), kTo);
149
150 XmlElement* result = new XmlElement(
151 QName("test:namespace", "response-body"));
152 response->AddElement(result);
153
154 EXPECT_TRUE(sender_->OnSignalStrategyIncomingStanza(response.get()));
155
156 EXPECT_CALL(callback_, OnReply(request_.get(), XmlEq(response.get())));
157 message_loop_.RunUntilIdle();
158 }
159
160 } // namespace remoting
161