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