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/jid.h" 18#include "webrtc/libjingle/xmpp/pubsubclient.h" 19#include "webrtc/base/faketaskrunner.h" 20#include "webrtc/base/gunit.h" 21#include "webrtc/base/sigslot.h" 22 23struct HandledPubSubItem { 24 std::string itemid; 25 std::string payload; 26}; 27 28class TestPubSubItemsListener : public sigslot::has_slots<> { 29 public: 30 TestPubSubItemsListener() : error_count(0) {} 31 32 void OnItems(buzz::PubSubClient*, 33 const std::vector<buzz::PubSubItem>& items) { 34 for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin(); 35 item != items.end(); ++item) { 36 HandledPubSubItem handled_item; 37 handled_item.itemid = item->itemid; 38 if (item->elem->FirstElement() != NULL) { 39 handled_item.payload = item->elem->FirstElement()->Str(); 40 } 41 this->items.push_back(handled_item); 42 } 43 } 44 45 void OnRequestError(buzz::PubSubClient* client, 46 const buzz::XmlElement* stanza) { 47 error_count++; 48 } 49 50 void OnPublishResult(buzz::PubSubClient* client, 51 const std::string& task_id, 52 const buzz::XmlElement* item) { 53 result_task_id = task_id; 54 } 55 56 void OnPublishError(buzz::PubSubClient* client, 57 const std::string& task_id, 58 const buzz::XmlElement* item, 59 const buzz::XmlElement* stanza) { 60 error_count++; 61 error_task_id = task_id; 62 } 63 64 void OnRetractResult(buzz::PubSubClient* client, 65 const std::string& task_id) { 66 result_task_id = task_id; 67 } 68 69 void OnRetractError(buzz::PubSubClient* client, 70 const std::string& task_id, 71 const buzz::XmlElement* stanza) { 72 error_count++; 73 error_task_id = task_id; 74 } 75 76 std::vector<HandledPubSubItem> items; 77 int error_count; 78 std::string error_task_id; 79 std::string result_task_id; 80}; 81 82class PubSubClientTest : public testing::Test { 83 public: 84 PubSubClientTest() : 85 pubsubjid("room@domain.com"), 86 node("topic"), 87 itemid("key") { 88 runner.reset(new rtc::FakeTaskRunner()); 89 xmpp_client = new buzz::FakeXmppClient(runner.get()); 90 client.reset(new buzz::PubSubClient(xmpp_client, pubsubjid, node)); 91 listener.reset(new TestPubSubItemsListener()); 92 client->SignalItems.connect( 93 listener.get(), &TestPubSubItemsListener::OnItems); 94 client->SignalRequestError.connect( 95 listener.get(), &TestPubSubItemsListener::OnRequestError); 96 client->SignalPublishResult.connect( 97 listener.get(), &TestPubSubItemsListener::OnPublishResult); 98 client->SignalPublishError.connect( 99 listener.get(), &TestPubSubItemsListener::OnPublishError); 100 client->SignalRetractResult.connect( 101 listener.get(), &TestPubSubItemsListener::OnRetractResult); 102 client->SignalRetractError.connect( 103 listener.get(), &TestPubSubItemsListener::OnRetractError); 104 } 105 106 rtc::scoped_ptr<rtc::FakeTaskRunner> runner; 107 // xmpp_client deleted by deleting runner. 108 buzz::FakeXmppClient* xmpp_client; 109 rtc::scoped_ptr<buzz::PubSubClient> client; 110 rtc::scoped_ptr<TestPubSubItemsListener> listener; 111 buzz::Jid pubsubjid; 112 std::string node; 113 std::string itemid; 114}; 115 116TEST_F(PubSubClientTest, TestRequest) { 117 client->RequestItems(); 118 119 std::string expected_iq = 120 "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" " 121 "xmlns:cli=\"jabber:client\">" 122 "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" 123 "<pub:items node=\"topic\"/>" 124 "</pub:pubsub>" 125 "</cli:iq>"; 126 127 ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); 128 EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); 129 130 std::string result_iq = 131 "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>" 132 " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" 133 " <items node='topic'>" 134 " <item id='key0'>" 135 " <value0a/>" 136 " </item>" 137 " <item id='key1'>" 138 " <value1a/>" 139 " </item>" 140 " </items>" 141 " </pubsub>" 142 "</iq>"; 143 144 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 145 ASSERT_EQ(2U, listener->items.size()); 146 EXPECT_EQ("key0", listener->items[0].itemid); 147 EXPECT_EQ("<pub:value0a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", 148 listener->items[0].payload); 149 EXPECT_EQ("key1", listener->items[1].itemid); 150 EXPECT_EQ("<pub:value1a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", 151 listener->items[1].payload); 152 153 std::string items_message = 154 "<message xmlns='jabber:client' from='room@domain.com'>" 155 " <event xmlns='http://jabber.org/protocol/pubsub#event'>" 156 " <items node='topic'>" 157 " <item id='key0'>" 158 " <value0b/>" 159 " </item>" 160 " <item id='key1'>" 161 " <value1b/>" 162 " </item>" 163 " </items>" 164 " </event>" 165 "</message>"; 166 167 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(items_message)); 168 ASSERT_EQ(4U, listener->items.size()); 169 EXPECT_EQ("key0", listener->items[2].itemid); 170 EXPECT_EQ("<eve:value0b" 171 " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", 172 listener->items[2].payload); 173 EXPECT_EQ("key1", listener->items[3].itemid); 174 EXPECT_EQ("<eve:value1b" 175 " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", 176 listener->items[3].payload); 177} 178 179TEST_F(PubSubClientTest, TestRequestError) { 180 std::string result_iq = 181 "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" 182 " <error type='auth'>" 183 " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 184 " </error>" 185 "</iq>"; 186 187 client->RequestItems(); 188 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 189 EXPECT_EQ(1, listener->error_count); 190} 191 192TEST_F(PubSubClientTest, TestPublish) { 193 buzz::XmlElement* payload = 194 new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); 195 196 std::string task_id; 197 client->PublishItem(itemid, payload, &task_id); 198 199 std::string expected_iq = 200 "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " 201 "xmlns:cli=\"jabber:client\">" 202 "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" 203 "<publish node=\"topic\">" 204 "<item id=\"key\">" 205 "<value/>" 206 "</item>" 207 "</publish>" 208 "</pubsub>" 209 "</cli:iq>"; 210 211 ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); 212 EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); 213 214 std::string result_iq = 215 "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; 216 217 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 218 EXPECT_EQ(task_id, listener->result_task_id); 219} 220 221TEST_F(PubSubClientTest, TestPublishError) { 222 buzz::XmlElement* payload = 223 new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); 224 225 std::string task_id; 226 client->PublishItem(itemid, payload, &task_id); 227 228 std::string result_iq = 229 "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" 230 " <error type='auth'>" 231 " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 232 " </error>" 233 "</iq>"; 234 235 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 236 EXPECT_EQ(1, listener->error_count); 237 EXPECT_EQ(task_id, listener->error_task_id); 238} 239 240TEST_F(PubSubClientTest, TestRetract) { 241 std::string task_id; 242 client->RetractItem(itemid, &task_id); 243 244 std::string expected_iq = 245 "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " 246 "xmlns:cli=\"jabber:client\">" 247 "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" 248 "<retract node=\"topic\" notify=\"true\">" 249 "<item id=\"key\"/>" 250 "</retract>" 251 "</pubsub>" 252 "</cli:iq>"; 253 254 ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); 255 EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); 256 257 std::string result_iq = 258 "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; 259 260 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 261 EXPECT_EQ(task_id, listener->result_task_id); 262} 263 264TEST_F(PubSubClientTest, TestRetractError) { 265 std::string task_id; 266 client->RetractItem(itemid, &task_id); 267 268 std::string result_iq = 269 "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" 270 " <error type='auth'>" 271 " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 272 " </error>" 273 "</iq>"; 274 275 xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); 276 EXPECT_EQ(1, listener->error_count); 277 EXPECT_EQ(task_id, listener->error_task_id); 278} 279