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 (at) 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: 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: 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 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 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 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 (at) 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 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