1 /* 2 * Copyright 2011 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <string> 12 13 #include "webrtc/libjingle/xmllite/qname.h" 14 #include "webrtc/libjingle/xmllite/xmlelement.h" 15 #include "webrtc/libjingle/xmpp/constants.h" 16 #include "webrtc/libjingle/xmpp/fakexmppclient.h" 17 #include "webrtc/libjingle/xmpp/iqtask.h" 18 #include "webrtc/libjingle/xmpp/jid.h" 19 #include "webrtc/libjingle/xmpp/pubsubtasks.h" 20 #include "webrtc/base/faketaskrunner.h" 21 #include "webrtc/base/gunit.h" 22 #include "webrtc/base/sigslot.h" 23 24 struct HandledPubSubItem { 25 std::string itemid; 26 std::string payload; 27 }; 28 29 class TestPubSubTasksListener : public sigslot::has_slots<> { 30 public: 31 TestPubSubTasksListener() : result_count(0), error_count(0) {} 32 33 void OnReceiveUpdate(buzz::PubSubReceiveTask* task, 34 const std::vector<buzz::PubSubItem>& items) { 35 OnItems(items); 36 } 37 38 void OnRequestResult(buzz::PubSubRequestTask* task, 39 const std::vector<buzz::PubSubItem>& items) { 40 OnItems(items); 41 } 42 43 void OnItems(const std::vector<buzz::PubSubItem>& items) { 44 for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin(); 45 item != items.end(); ++item) { 46 HandledPubSubItem handled_item; 47 handled_item.itemid = item->itemid; 48 if (item->elem->FirstElement() != NULL) { 49 handled_item.payload = item->elem->FirstElement()->Str(); 50 } 51 this->items.push_back(handled_item); 52 } 53 } 54 55 void OnPublishResult(buzz::PubSubPublishTask* task) { 56 ++result_count; 57 } 58 59 void OnRetractResult(buzz::PubSubRetractTask* task) { 60 ++result_count; 61 } 62 63 void OnError(buzz::IqTask* task, const buzz::XmlElement* stanza) { 64 ++error_count; 65 } 66 67 std::vector<HandledPubSubItem> items; 68 int result_count; 69 int error_count; 70 }; 71 72 class PubSubTasksTest : public testing::Test { 73 public: 74 PubSubTasksTest() : 75 pubsubjid("room (at) domain.com"), 76 node("topic"), 77 itemid("key") { 78 runner.reset(new rtc::FakeTaskRunner()); 79 client = new buzz::FakeXmppClient(runner.get()); 80 listener.reset(new TestPubSubTasksListener()); 81 } 82 83 rtc::scoped_ptr<rtc::FakeTaskRunner> runner; 84 // Client deleted by deleting runner. 85 buzz::FakeXmppClient* client; 86 rtc::scoped_ptr<TestPubSubTasksListener> listener; 87 buzz::Jid pubsubjid; 88 std::string node; 89 std::string itemid; 90 }; 91 92 TEST_F(PubSubTasksTest, TestRequest) { 93 buzz::PubSubRequestTask* task = 94 new buzz::PubSubRequestTask(client, pubsubjid, node); 95 task->SignalResult.connect( 96 listener.get(), &TestPubSubTasksListener::OnRequestResult); 97 task->Start(); 98 99 std::string expected_iq = 100 "<cli:iq type=\"get\" to=\"room (at) domain.com\" id=\"0\" " 101 "xmlns:cli=\"jabber:client\">" 102 "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" 103 "<pub:items node=\"topic\"/>" 104 "</pub:pubsub>" 105 "</cli:iq>"; 106 107 ASSERT_EQ(1U, client->sent_stanzas().size()); 108 EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); 109 110 std::string result_iq = 111 "<iq xmlns='jabber:client' id='0' type='result' from='room (at) domain.com'>" 112 " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" 113 " <items node='topic'>" 114 " <item id='key0'>" 115 " <value0/>" 116 " </item>" 117 " <item id='key1'>" 118 " <value1/>" 119 " </item>" 120 " </items>" 121 " </pubsub>" 122 "</iq>"; 123 124 client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 125 126 ASSERT_EQ(2U, listener->items.size()); 127 EXPECT_EQ("key0", listener->items[0].itemid); 128 EXPECT_EQ("<pub:value0 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", 129 listener->items[0].payload); 130 EXPECT_EQ("key1", listener->items[1].itemid); 131 EXPECT_EQ("<pub:value1 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", 132 listener->items[1].payload); 133 } 134 135 TEST_F(PubSubTasksTest, TestRequestError) { 136 std::string result_iq = 137 "<iq xmlns='jabber:client' id='0' type='error' from='room (at) domain.com'>" 138 " <error type='auth'>" 139 " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 140 " </error>" 141 "</iq>"; 142 143 buzz::PubSubRequestTask* task = 144 new buzz::PubSubRequestTask(client, pubsubjid, node); 145 task->SignalResult.connect( 146 listener.get(), &TestPubSubTasksListener::OnRequestResult); 147 task->SignalError.connect( 148 listener.get(), &TestPubSubTasksListener::OnError); 149 task->Start(); 150 client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 151 152 EXPECT_EQ(0, listener->result_count); 153 EXPECT_EQ(1, listener->error_count); 154 } 155 156 TEST_F(PubSubTasksTest, TestReceive) { 157 std::string items_message = 158 "<message xmlns='jabber:client' from='room (at) domain.com'>" 159 " <event xmlns='http://jabber.org/protocol/pubsub#event'>" 160 " <items node='topic'>" 161 " <item id='key0'>" 162 " <value0/>" 163 " </item>" 164 " <item id='key1'>" 165 " <value1/>" 166 " </item>" 167 " </items>" 168 " </event>" 169 "</message>"; 170 171 buzz::PubSubReceiveTask* task = 172 new buzz::PubSubReceiveTask(client, pubsubjid, node); 173 task->SignalUpdate.connect( 174 listener.get(), &TestPubSubTasksListener::OnReceiveUpdate); 175 task->Start(); 176 client->HandleStanza(buzz::XmlElement::ForStr(items_message)); 177 178 ASSERT_EQ(2U, listener->items.size()); 179 EXPECT_EQ("key0", listener->items[0].itemid); 180 EXPECT_EQ( 181 "<eve:value0 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", 182 listener->items[0].payload); 183 EXPECT_EQ("key1", listener->items[1].itemid); 184 EXPECT_EQ( 185 "<eve:value1 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", 186 listener->items[1].payload); 187 } 188 189 TEST_F(PubSubTasksTest, TestPublish) { 190 buzz::XmlElement* payload = 191 new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); 192 std::string expected_iq = 193 "<cli:iq type=\"set\" to=\"room (at) domain.com\" id=\"0\" " 194 "xmlns:cli=\"jabber:client\">" 195 "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" 196 "<publish node=\"topic\">" 197 "<item id=\"key\">" 198 "<value/>" 199 "</item>" 200 "</publish>" 201 "</pubsub>" 202 "</cli:iq>"; 203 204 std::vector<buzz::XmlElement*> children; 205 children.push_back(payload); 206 buzz::PubSubPublishTask* task = 207 new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children); 208 task->SignalResult.connect( 209 listener.get(), &TestPubSubTasksListener::OnPublishResult); 210 task->Start(); 211 212 ASSERT_EQ(1U, client->sent_stanzas().size()); 213 EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); 214 215 std::string result_iq = 216 "<iq xmlns='jabber:client' id='0' type='result' from='room (at) domain.com'/>"; 217 218 client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 219 220 EXPECT_EQ(1, listener->result_count); 221 EXPECT_EQ(0, listener->error_count); 222 } 223 224 TEST_F(PubSubTasksTest, TestPublishError) { 225 buzz::XmlElement* payload = 226 new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); 227 228 std::vector<buzz::XmlElement*> children; 229 children.push_back(payload); 230 buzz::PubSubPublishTask* task = 231 new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children); 232 task->SignalResult.connect( 233 listener.get(), &TestPubSubTasksListener::OnPublishResult); 234 task->SignalError.connect( 235 listener.get(), &TestPubSubTasksListener::OnError); 236 task->Start(); 237 238 std::string result_iq = 239 "<iq xmlns='jabber:client' id='0' type='error' from='room (at) domain.com'>" 240 " <error type='auth'>" 241 " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 242 " </error>" 243 "</iq>"; 244 245 client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 246 247 EXPECT_EQ(0, listener->result_count); 248 EXPECT_EQ(1, listener->error_count); 249 } 250 251 TEST_F(PubSubTasksTest, TestRetract) { 252 buzz::PubSubRetractTask* task = 253 new buzz::PubSubRetractTask(client, pubsubjid, node, itemid); 254 task->SignalResult.connect( 255 listener.get(), &TestPubSubTasksListener::OnRetractResult); 256 task->SignalError.connect( 257 listener.get(), &TestPubSubTasksListener::OnError); 258 task->Start(); 259 260 std::string expected_iq = 261 "<cli:iq type=\"set\" to=\"room (at) domain.com\" id=\"0\" " 262 "xmlns:cli=\"jabber:client\">" 263 "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" 264 "<retract node=\"topic\" notify=\"true\">" 265 "<item id=\"key\"/>" 266 "</retract>" 267 "</pubsub>" 268 "</cli:iq>"; 269 270 ASSERT_EQ(1U, client->sent_stanzas().size()); 271 EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); 272 273 std::string result_iq = 274 "<iq xmlns='jabber:client' id='0' type='result' from='room (at) domain.com'/>"; 275 276 client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 277 278 EXPECT_EQ(1, listener->result_count); 279 EXPECT_EQ(0, listener->error_count); 280 } 281