| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2004 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 <iostream> | |
| 12 #include <memory> | |
| 13 #include <sstream> | |
| 14 #include <string> | |
| 15 | |
| 16 #include "webrtc/libjingle/xmllite/xmlelement.h" | |
| 17 #include "webrtc/libjingle/xmpp/constants.h" | |
| 18 #include "webrtc/libjingle/xmpp/rostermodule.h" | |
| 19 #include "webrtc/libjingle/xmpp/util_unittest.h" | |
| 20 #include "webrtc/libjingle/xmpp/xmppengine.h" | |
| 21 #include "webrtc/base/gunit.h" | |
| 22 | |
| 23 #define TEST_OK(x) EXPECT_EQ((x),XMPP_RETURN_OK) | |
| 24 #define TEST_BADARGUMENT(x) EXPECT_EQ((x),XMPP_RETURN_BADARGUMENT) | |
| 25 | |
| 26 | |
| 27 namespace buzz { | |
| 28 | |
| 29 class RosterModuleTest; | |
| 30 | |
| 31 static void | |
| 32 WriteString(std::ostream& os, const std::string& str) { | |
| 33 os<<str; | |
| 34 } | |
| 35 | |
| 36 static void | |
| 37 WriteSubscriptionState(std::ostream& os, XmppSubscriptionState state) | |
| 38 { | |
| 39 switch (state) { | |
| 40 case XMPP_SUBSCRIPTION_NONE: | |
| 41 os<<"none"; | |
| 42 break; | |
| 43 case XMPP_SUBSCRIPTION_NONE_ASKED: | |
| 44 os<<"none_asked"; | |
| 45 break; | |
| 46 case XMPP_SUBSCRIPTION_TO: | |
| 47 os<<"to"; | |
| 48 break; | |
| 49 case XMPP_SUBSCRIPTION_FROM: | |
| 50 os<<"from"; | |
| 51 break; | |
| 52 case XMPP_SUBSCRIPTION_FROM_ASKED: | |
| 53 os<<"from_asked"; | |
| 54 break; | |
| 55 case XMPP_SUBSCRIPTION_BOTH: | |
| 56 os<<"both"; | |
| 57 break; | |
| 58 default: | |
| 59 os<<"unknown"; | |
| 60 break; | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 static void | |
| 65 WriteSubscriptionRequestType(std::ostream& os, | |
| 66 XmppSubscriptionRequestType type) { | |
| 67 switch(type) { | |
| 68 case XMPP_REQUEST_SUBSCRIBE: | |
| 69 os<<"subscribe"; | |
| 70 break; | |
| 71 case XMPP_REQUEST_UNSUBSCRIBE: | |
| 72 os<<"unsubscribe"; | |
| 73 break; | |
| 74 case XMPP_REQUEST_SUBSCRIBED: | |
| 75 os<<"subscribed"; | |
| 76 break; | |
| 77 case XMPP_REQUEST_UNSUBSCRIBED: | |
| 78 os<<"unsubscribe"; | |
| 79 break; | |
| 80 default: | |
| 81 os<<"unknown"; | |
| 82 break; | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 static void | |
| 87 WritePresenceShow(std::ostream& os, XmppPresenceShow show) { | |
| 88 switch(show) { | |
| 89 case XMPP_PRESENCE_AWAY: | |
| 90 os<<"away"; | |
| 91 break; | |
| 92 case XMPP_PRESENCE_CHAT: | |
| 93 os<<"chat"; | |
| 94 break; | |
| 95 case XMPP_PRESENCE_DND: | |
| 96 os<<"dnd"; | |
| 97 break; | |
| 98 case XMPP_PRESENCE_XA: | |
| 99 os<<"xa"; | |
| 100 break; | |
| 101 case XMPP_PRESENCE_DEFAULT: | |
| 102 os<<"[default]"; | |
| 103 break; | |
| 104 default: | |
| 105 os<<"[unknown]"; | |
| 106 break; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 static void | |
| 111 WritePresence(std::ostream& os, const XmppPresence* presence) { | |
| 112 if (presence == NULL) { | |
| 113 os<<"NULL"; | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 os<<"[Presence jid:"; | |
| 118 WriteString(os, presence->jid().Str()); | |
| 119 os<<" available:"<<presence->available(); | |
| 120 os<<" presence_show:"; | |
| 121 WritePresenceShow(os, presence->presence_show()); | |
| 122 os<<" priority:"<<presence->priority(); | |
| 123 os<<" status:"; | |
| 124 WriteString(os, presence->status()); | |
| 125 os<<"]"<<presence->raw_xml()->Str(); | |
| 126 } | |
| 127 | |
| 128 static void | |
| 129 WriteContact(std::ostream& os, const XmppRosterContact* contact) { | |
| 130 if (contact == NULL) { | |
| 131 os<<"NULL"; | |
| 132 return; | |
| 133 } | |
| 134 | |
| 135 os<<"[Contact jid:"; | |
| 136 WriteString(os, contact->jid().Str()); | |
| 137 os<<" name:"; | |
| 138 WriteString(os, contact->name()); | |
| 139 os<<" subscription_state:"; | |
| 140 WriteSubscriptionState(os, contact->subscription_state()); | |
| 141 os<<" groups:["; | |
| 142 for(size_t i=0; i < contact->GetGroupCount(); ++i) { | |
| 143 os<<(i==0?"":", "); | |
| 144 WriteString(os, contact->GetGroup(i)); | |
| 145 } | |
| 146 os<<"]]"<<contact->raw_xml()->Str(); | |
| 147 } | |
| 148 | |
| 149 //! This session handler saves all calls to a string. These are events and | |
| 150 //! data delivered form the engine to application code. | |
| 151 class XmppTestRosterHandler : public XmppRosterHandler { | |
| 152 public: | |
| 153 XmppTestRosterHandler() {} | |
| 154 virtual ~XmppTestRosterHandler() {} | |
| 155 | |
| 156 virtual void SubscriptionRequest(XmppRosterModule*, | |
| 157 const Jid& requesting_jid, | |
| 158 XmppSubscriptionRequestType type, | |
| 159 const XmlElement* raw_xml) { | |
| 160 ss_<<"[SubscriptionRequest Jid:" << requesting_jid.Str()<<" type:"; | |
| 161 WriteSubscriptionRequestType(ss_, type); | |
| 162 ss_<<"]"<<raw_xml->Str(); | |
| 163 } | |
| 164 | |
| 165 //! Some type of presence error has occured | |
| 166 virtual void SubscriptionError(XmppRosterModule*, | |
| 167 const Jid& from, | |
| 168 const XmlElement* raw_xml) { | |
| 169 ss_<<"[SubscriptionError from:"<<from.Str()<<"]"<<raw_xml->Str(); | |
| 170 } | |
| 171 | |
| 172 virtual void RosterError(XmppRosterModule*, | |
| 173 const XmlElement* raw_xml) { | |
| 174 ss_<<"[RosterError]"<<raw_xml->Str(); | |
| 175 } | |
| 176 | |
| 177 //! New presence information has come in | |
| 178 //! The user is notified with the presence object directly. This info is also | |
| 179 //! added to the store accessable from the engine. | |
| 180 virtual void IncomingPresenceChanged(XmppRosterModule*, | |
| 181 const XmppPresence* presence) { | |
| 182 ss_<<"[IncomingPresenceChanged presence:"; | |
| 183 WritePresence(ss_, presence); | |
| 184 ss_<<"]"; | |
| 185 } | |
| 186 | |
| 187 //! A contact has changed | |
| 188 //! This indicates that the data for a contact may have changed. No | |
| 189 //! contacts have been added or removed. | |
| 190 virtual void ContactChanged(XmppRosterModule* roster, | |
| 191 const XmppRosterContact* old_contact, | |
| 192 size_t index) { | |
| 193 ss_<<"[ContactChanged old_contact:"; | |
| 194 WriteContact(ss_, old_contact); | |
| 195 ss_<<" index:"<<index<<" new_contact:"; | |
| 196 WriteContact(ss_, roster->GetRosterContact(index)); | |
| 197 ss_<<"]"; | |
| 198 } | |
| 199 | |
| 200 //! A set of contacts have been added | |
| 201 //! These contacts may have been added in response to the original roster | |
| 202 //! request or due to a "roster push" from the server. | |
| 203 virtual void ContactsAdded(XmppRosterModule* roster, | |
| 204 size_t index, size_t number) { | |
| 205 ss_<<"[ContactsAdded index:"<<index<<" number:"<<number; | |
| 206 for (size_t i = 0; i < number; ++i) { | |
| 207 ss_<<" "<<(index+i)<<":"; | |
| 208 WriteContact(ss_, roster->GetRosterContact(index+i)); | |
| 209 } | |
| 210 ss_<<"]"; | |
| 211 } | |
| 212 | |
| 213 //! A contact has been removed | |
| 214 //! This contact has been removed form the list. | |
| 215 virtual void ContactRemoved(XmppRosterModule*, | |
| 216 const XmppRosterContact* removed_contact, | |
| 217 size_t index) { | |
| 218 ss_<<"[ContactRemoved old_contact:"; | |
| 219 WriteContact(ss_, removed_contact); | |
| 220 ss_<<" index:"<<index<<"]"; | |
| 221 } | |
| 222 | |
| 223 std::string Str() { | |
| 224 return ss_.str(); | |
| 225 } | |
| 226 | |
| 227 std::string StrClear() { | |
| 228 std::string result = ss_.str(); | |
| 229 ss_.str(""); | |
| 230 return result; | |
| 231 } | |
| 232 | |
| 233 private: | |
| 234 std::stringstream ss_; | |
| 235 }; | |
| 236 | |
| 237 //! This is the class that holds all of the unit test code for the | |
| 238 //! roster module | |
| 239 class RosterModuleTest : public testing::Test { | |
| 240 public: | |
| 241 RosterModuleTest() {} | |
| 242 static void RunLogin(RosterModuleTest* obj, XmppEngine* engine, | |
| 243 XmppTestHandler* handler) { | |
| 244 // Needs to be similar to XmppEngineTest::RunLogin | |
| 245 } | |
| 246 }; | |
| 247 | |
| 248 TEST_F(RosterModuleTest, TestPresence) { | |
| 249 XmlElement* status = new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS); | |
| 250 status->AddAttr(QN_STATUS, STR_PSTN_CONFERENCE_STATUS_CONNECTING); | |
| 251 XmlElement presence_xml(QN_PRESENCE); | |
| 252 presence_xml.AddElement(status); | |
| 253 std::unique_ptr<XmppPresence> presence(XmppPresence::Create()); | |
| 254 presence->set_raw_xml(&presence_xml); | |
| 255 EXPECT_EQ(presence->connection_status(), XMPP_CONNECTION_STATUS_CONNECTING); | |
| 256 } | |
| 257 | |
| 258 TEST_F(RosterModuleTest, TestOutgoingPresence) { | |
| 259 std::stringstream dump; | |
| 260 | |
| 261 std::unique_ptr<XmppEngine> engine(XmppEngine::Create()); | |
| 262 XmppTestHandler handler(engine.get()); | |
| 263 XmppTestRosterHandler roster_handler; | |
| 264 | |
| 265 std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); | |
| 266 roster->set_roster_handler(&roster_handler); | |
| 267 | |
| 268 // Configure the roster module | |
| 269 roster->RegisterEngine(engine.get()); | |
| 270 | |
| 271 // Set up callbacks | |
| 272 engine->SetOutputHandler(&handler); | |
| 273 engine->AddStanzaHandler(&handler); | |
| 274 engine->SetSessionHandler(&handler); | |
| 275 | |
| 276 // Set up minimal login info | |
| 277 engine->SetUser(Jid("david@my-server")); | |
| 278 // engine->SetPassword("david"); | |
| 279 | |
| 280 // Do the whole login handshake | |
| 281 RunLogin(this, engine.get(), &handler); | |
| 282 EXPECT_EQ("", handler.OutputActivity()); | |
| 283 | |
| 284 // Set some presence and broadcast it | |
| 285 TEST_OK(roster->outgoing_presence()-> | |
| 286 set_available(XMPP_PRESENCE_AVAILABLE)); | |
| 287 TEST_OK(roster->outgoing_presence()->set_priority(-37)); | |
| 288 TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_DND)); | |
| 289 TEST_OK(roster->outgoing_presence()-> | |
| 290 set_status("I'm off to the races!<>&")); | |
| 291 TEST_OK(roster->BroadcastPresence()); | |
| 292 | |
| 293 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 294 EXPECT_EQ(handler.OutputActivity(), | |
| 295 "<presence>" | |
| 296 "<priority>-37</priority>" | |
| 297 "<show>dnd</show>" | |
| 298 "<status>I'm off to the races!<>&</status>" | |
| 299 "</presence>"); | |
| 300 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 301 | |
| 302 // Try some more | |
| 303 TEST_OK(roster->outgoing_presence()-> | |
| 304 set_available(XMPP_PRESENCE_UNAVAILABLE)); | |
| 305 TEST_OK(roster->outgoing_presence()->set_priority(0)); | |
| 306 TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_XA)); | |
| 307 TEST_OK(roster->outgoing_presence()->set_status("Gone fishin'")); | |
| 308 TEST_OK(roster->BroadcastPresence()); | |
| 309 | |
| 310 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 311 EXPECT_EQ(handler.OutputActivity(), | |
| 312 "<presence type=\"unavailable\">" | |
| 313 "<show>xa</show>" | |
| 314 "<status>Gone fishin'</status>" | |
| 315 "</presence>"); | |
| 316 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 317 | |
| 318 // Okay -- we are back on | |
| 319 TEST_OK(roster->outgoing_presence()-> | |
| 320 set_available(XMPP_PRESENCE_AVAILABLE)); | |
| 321 TEST_BADARGUMENT(roster->outgoing_presence()->set_priority(128)); | |
| 322 TEST_OK(roster->outgoing_presence()-> | |
| 323 set_presence_show(XMPP_PRESENCE_DEFAULT)); | |
| 324 TEST_OK(roster->outgoing_presence()->set_status("Cookin' wit gas")); | |
| 325 TEST_OK(roster->BroadcastPresence()); | |
| 326 | |
| 327 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 328 EXPECT_EQ(handler.OutputActivity(), | |
| 329 "<presence>" | |
| 330 "<status>Cookin' wit gas</status>" | |
| 331 "</presence>"); | |
| 332 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 333 | |
| 334 // Set it via XML | |
| 335 XmlElement presence_input(QN_PRESENCE); | |
| 336 presence_input.AddAttr(QN_TYPE, "unavailable"); | |
| 337 presence_input.AddElement(new XmlElement(QN_PRIORITY)); | |
| 338 presence_input.AddText("42", 1); | |
| 339 presence_input.AddElement(new XmlElement(QN_STATUS)); | |
| 340 presence_input.AddAttr(QN_XML_LANG, "es", 1); | |
| 341 presence_input.AddText("Hola Amigos!", 1); | |
| 342 presence_input.AddElement(new XmlElement(QN_STATUS)); | |
| 343 presence_input.AddText("Hey there, friend!", 1); | |
| 344 TEST_OK(roster->outgoing_presence()->set_raw_xml(&presence_input)); | |
| 345 TEST_OK(roster->BroadcastPresence()); | |
| 346 | |
| 347 WritePresence(dump, roster->outgoing_presence()); | |
| 348 EXPECT_EQ(dump.str(), | |
| 349 "[Presence jid: available:0 presence_show:[default] " | |
| 350 "priority:42 status:Hey there, friend!]" | |
| 351 "<cli:presence type=\"unavailable\" xmlns:cli=\"jabber:client\">" | |
| 352 "<cli:priority>42</cli:priority>" | |
| 353 "<cli:status xml:lang=\"es\">Hola Amigos!</cli:status>" | |
| 354 "<cli:status>Hey there, friend!</cli:status>" | |
| 355 "</cli:presence>"); | |
| 356 dump.str(""); | |
| 357 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 358 EXPECT_EQ(handler.OutputActivity(), | |
| 359 "<presence type=\"unavailable\">" | |
| 360 "<priority>42</priority>" | |
| 361 "<status xml:lang=\"es\">Hola Amigos!</status>" | |
| 362 "<status>Hey there, friend!</status>" | |
| 363 "</presence>"); | |
| 364 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 365 | |
| 366 // Construct a directed presence | |
| 367 std::unique_ptr<XmppPresence> directed_presence(XmppPresence::Create()); | |
| 368 TEST_OK(directed_presence->set_available(XMPP_PRESENCE_AVAILABLE)); | |
| 369 TEST_OK(directed_presence->set_priority(120)); | |
| 370 TEST_OK(directed_presence->set_status("*very* available")); | |
| 371 TEST_OK(roster->SendDirectedPresence(directed_presence.get(), | |
| 372 Jid("myhoney@honey.net"))); | |
| 373 | |
| 374 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 375 EXPECT_EQ(handler.OutputActivity(), | |
| 376 "<presence to=\"myhoney@honey.net\">" | |
| 377 "<priority>120</priority>" | |
| 378 "<status>*very* available</status>" | |
| 379 "</presence>"); | |
| 380 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 381 } | |
| 382 | |
| 383 TEST_F(RosterModuleTest, TestIncomingPresence) { | |
| 384 std::unique_ptr<XmppEngine> engine(XmppEngine::Create()); | |
| 385 XmppTestHandler handler(engine.get()); | |
| 386 XmppTestRosterHandler roster_handler; | |
| 387 | |
| 388 std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); | |
| 389 roster->set_roster_handler(&roster_handler); | |
| 390 | |
| 391 // Configure the roster module | |
| 392 roster->RegisterEngine(engine.get()); | |
| 393 | |
| 394 // Set up callbacks | |
| 395 engine->SetOutputHandler(&handler); | |
| 396 engine->AddStanzaHandler(&handler); | |
| 397 engine->SetSessionHandler(&handler); | |
| 398 | |
| 399 // Set up minimal login info | |
| 400 engine->SetUser(Jid("david@my-server")); | |
| 401 // engine->SetPassword("david"); | |
| 402 | |
| 403 // Do the whole login handshake | |
| 404 RunLogin(this, engine.get(), &handler); | |
| 405 EXPECT_EQ("", handler.OutputActivity()); | |
| 406 | |
| 407 // Load up with a bunch of data | |
| 408 std::string input; | |
| 409 input = "<presence from='maude@example.net/studio' " | |
| 410 "to='david@my-server/test'/>" | |
| 411 "<presence from='walter@example.net/home' " | |
| 412 "to='david@my-server/test'>" | |
| 413 "<priority>-10</priority>" | |
| 414 "<show>xa</show>" | |
| 415 "<status>Off bowling</status>" | |
| 416 "</presence>" | |
| 417 "<presence from='walter@example.net/alley' " | |
| 418 "to='david@my-server/test'>" | |
| 419 "<priority>20</priority>" | |
| 420 "<status>Looking for toes...</status>" | |
| 421 "</presence>" | |
| 422 "<presence from='donny@example.net/alley' " | |
| 423 "to='david@my-server/test'>" | |
| 424 "<priority>10</priority>" | |
| 425 "<status>Throwing rocks</status>" | |
| 426 "</presence>"; | |
| 427 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 428 | |
| 429 EXPECT_EQ(roster_handler.StrClear(), | |
| 430 "[IncomingPresenceChanged " | |
| 431 "presence:[Presence jid:maude@example.net/studio available:1 " | |
| 432 "presence_show:[default] priority:0 status:]" | |
| 433 "<cli:presence from=\"maude@example.net/studio\" " | |
| 434 "to=\"david@my-server/test\" " | |
| 435 "xmlns:cli=\"jabber:client\"/>]" | |
| 436 "[IncomingPresenceChanged " | |
| 437 "presence:[Presence jid:walter@example.net/home available:1 " | |
| 438 "presence_show:xa priority:-10 status:Off bowling]" | |
| 439 "<cli:presence from=\"walter@example.net/home\" " | |
| 440 "to=\"david@my-server/test\" " | |
| 441 "xmlns:cli=\"jabber:client\">" | |
| 442 "<cli:priority>-10</cli:priority>" | |
| 443 "<cli:show>xa</cli:show>" | |
| 444 "<cli:status>Off bowling</cli:status>" | |
| 445 "</cli:presence>]" | |
| 446 "[IncomingPresenceChanged " | |
| 447 "presence:[Presence jid:walter@example.net/alley available:1 " | |
| 448 "presence_show:[default] " | |
| 449 "priority:20 status:Looking for toes...]" | |
| 450 "<cli:presence from=\"walter@example.net/alley\" " | |
| 451 "to=\"david@my-server/test\" " | |
| 452 "xmlns:cli=\"jabber:client\">" | |
| 453 "<cli:priority>20</cli:priority>" | |
| 454 "<cli:status>Looking for toes...</cli:status>" | |
| 455 "</cli:presence>]" | |
| 456 "[IncomingPresenceChanged " | |
| 457 "presence:[Presence jid:donny@example.net/alley available:1 " | |
| 458 "presence_show:[default] priority:10 status:Throwing rocks]" | |
| 459 "<cli:presence from=\"donny@example.net/alley\" " | |
| 460 "to=\"david@my-server/test\" " | |
| 461 "xmlns:cli=\"jabber:client\">" | |
| 462 "<cli:priority>10</cli:priority>" | |
| 463 "<cli:status>Throwing rocks</cli:status>" | |
| 464 "</cli:presence>]"); | |
| 465 EXPECT_EQ(handler.OutputActivity(), ""); | |
| 466 handler.SessionActivity(); // Ignore the session output | |
| 467 | |
| 468 // Now look at the data structure we've built | |
| 469 EXPECT_EQ(roster->GetIncomingPresenceCount(), static_cast<size_t>(4)); | |
| 470 EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("maude@example.net")), | |
| 471 static_cast<size_t>(1)); | |
| 472 EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("walter@example.net")), | |
| 473 static_cast<size_t>(2)); | |
| 474 | |
| 475 const XmppPresence * presence; | |
| 476 presence = roster->GetIncomingPresenceForJid(Jid("walter@example.net"), 1); | |
| 477 | |
| 478 std::stringstream dump; | |
| 479 WritePresence(dump, presence); | |
| 480 EXPECT_EQ(dump.str(), | |
| 481 "[Presence jid:walter@example.net/alley available:1 " | |
| 482 "presence_show:[default] priority:20 status:Looking for toes...]" | |
| 483 "<cli:presence from=\"walter@example.net/alley\" " | |
| 484 "to=\"david@my-server/test\" " | |
| 485 "xmlns:cli=\"jabber:client\">" | |
| 486 "<cli:priority>20</cli:priority>" | |
| 487 "<cli:status>Looking for toes...</cli:status>" | |
| 488 "</cli:presence>"); | |
| 489 dump.str(""); | |
| 490 | |
| 491 // Maude took off... | |
| 492 input = "<presence from='maude@example.net/studio' " | |
| 493 "to='david@my-server/test' " | |
| 494 "type='unavailable'>" | |
| 495 "<status>Stealing my rug back</status>" | |
| 496 "<priority>-10</priority>" | |
| 497 "</presence>"; | |
| 498 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 499 | |
| 500 EXPECT_EQ(roster_handler.StrClear(), | |
| 501 "[IncomingPresenceChanged " | |
| 502 "presence:[Presence jid:maude@example.net/studio available:0 " | |
| 503 "presence_show:[default] priority:-10 " | |
| 504 "status:Stealing my rug back]" | |
| 505 "<cli:presence from=\"maude@example.net/studio\" " | |
| 506 "to=\"david@my-server/test\" type=\"unavailable\" " | |
| 507 "xmlns:cli=\"jabber:client\">" | |
| 508 "<cli:status>Stealing my rug back</cli:status>" | |
| 509 "<cli:priority>-10</cli:priority>" | |
| 510 "</cli:presence>]"); | |
| 511 EXPECT_EQ(handler.OutputActivity(), ""); | |
| 512 handler.SessionActivity(); // Ignore the session output | |
| 513 } | |
| 514 | |
| 515 TEST_F(RosterModuleTest, TestPresenceSubscription) { | |
| 516 std::unique_ptr<XmppEngine> engine(XmppEngine::Create()); | |
| 517 XmppTestHandler handler(engine.get()); | |
| 518 XmppTestRosterHandler roster_handler; | |
| 519 | |
| 520 std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); | |
| 521 roster->set_roster_handler(&roster_handler); | |
| 522 | |
| 523 // Configure the roster module | |
| 524 roster->RegisterEngine(engine.get()); | |
| 525 | |
| 526 // Set up callbacks | |
| 527 engine->SetOutputHandler(&handler); | |
| 528 engine->AddStanzaHandler(&handler); | |
| 529 engine->SetSessionHandler(&handler); | |
| 530 | |
| 531 // Set up minimal login info | |
| 532 engine->SetUser(Jid("david@my-server")); | |
| 533 // engine->SetPassword("david"); | |
| 534 | |
| 535 // Do the whole login handshake | |
| 536 RunLogin(this, engine.get(), &handler); | |
| 537 EXPECT_EQ("", handler.OutputActivity()); | |
| 538 | |
| 539 // Test incoming requests | |
| 540 std::string input; | |
| 541 input = | |
| 542 "<presence from='maude@example.net' type='subscribe'/>" | |
| 543 "<presence from='maude@example.net' type='unsubscribe'/>" | |
| 544 "<presence from='maude@example.net' type='subscribed'/>" | |
| 545 "<presence from='maude@example.net' type='unsubscribed'/>"; | |
| 546 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 547 | |
| 548 EXPECT_EQ(roster_handler.StrClear(), | |
| 549 "[SubscriptionRequest Jid:maude@example.net type:subscribe]" | |
| 550 "<cli:presence from=\"maude@example.net\" type=\"subscribe\" " | |
| 551 "xmlns:cli=\"jabber:client\"/>" | |
| 552 "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]" | |
| 553 "<cli:presence from=\"maude@example.net\" type=\"unsubscribe\" " | |
| 554 "xmlns:cli=\"jabber:client\"/>" | |
| 555 "[SubscriptionRequest Jid:maude@example.net type:subscribed]" | |
| 556 "<cli:presence from=\"maude@example.net\" type=\"subscribed\" " | |
| 557 "xmlns:cli=\"jabber:client\"/>" | |
| 558 "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]" | |
| 559 "<cli:presence from=\"maude@example.net\" type=\"unsubscribed\" " | |
| 560 "xmlns:cli=\"jabber:client\"/>"); | |
| 561 EXPECT_EQ(handler.OutputActivity(), ""); | |
| 562 handler.SessionActivity(); // Ignore the session output | |
| 563 | |
| 564 TEST_OK(roster->RequestSubscription(Jid("maude@example.net"))); | |
| 565 TEST_OK(roster->CancelSubscription(Jid("maude@example.net"))); | |
| 566 TEST_OK(roster->ApproveSubscriber(Jid("maude@example.net"))); | |
| 567 TEST_OK(roster->CancelSubscriber(Jid("maude@example.net"))); | |
| 568 | |
| 569 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 570 EXPECT_EQ(handler.OutputActivity(), | |
| 571 "<presence to=\"maude@example.net\" type=\"subscribe\"/>" | |
| 572 "<presence to=\"maude@example.net\" type=\"unsubscribe\"/>" | |
| 573 "<presence to=\"maude@example.net\" type=\"subscribed\"/>" | |
| 574 "<presence to=\"maude@example.net\" type=\"unsubscribed\"/>"); | |
| 575 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 576 } | |
| 577 | |
| 578 TEST_F(RosterModuleTest, TestRosterReceive) { | |
| 579 std::unique_ptr<XmppEngine> engine(XmppEngine::Create()); | |
| 580 XmppTestHandler handler(engine.get()); | |
| 581 XmppTestRosterHandler roster_handler; | |
| 582 | |
| 583 std::unique_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); | |
| 584 roster->set_roster_handler(&roster_handler); | |
| 585 | |
| 586 // Configure the roster module | |
| 587 roster->RegisterEngine(engine.get()); | |
| 588 | |
| 589 // Set up callbacks | |
| 590 engine->SetOutputHandler(&handler); | |
| 591 engine->AddStanzaHandler(&handler); | |
| 592 engine->SetSessionHandler(&handler); | |
| 593 | |
| 594 // Set up minimal login info | |
| 595 engine->SetUser(Jid("david@my-server")); | |
| 596 // engine->SetPassword("david"); | |
| 597 | |
| 598 // Do the whole login handshake | |
| 599 RunLogin(this, engine.get(), &handler); | |
| 600 EXPECT_EQ("", handler.OutputActivity()); | |
| 601 | |
| 602 // Request a roster update | |
| 603 TEST_OK(roster->RequestRosterUpdate()); | |
| 604 | |
| 605 EXPECT_EQ(roster_handler.StrClear(),""); | |
| 606 EXPECT_EQ(handler.OutputActivity(), | |
| 607 "<iq type=\"get\" id=\"2\">" | |
| 608 "<query xmlns=\"jabber:iq:roster\"/>" | |
| 609 "</iq>"); | |
| 610 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 611 | |
| 612 // Prime the roster with a starting set | |
| 613 std::string input = | |
| 614 "<iq to='david@myserver/test' type='result' id='2'>" | |
| 615 "<query xmlns='jabber:iq:roster'>" | |
| 616 "<item jid='maude@example.net' " | |
| 617 "name='Maude Lebowski' " | |
| 618 "subscription='none' " | |
| 619 "ask='subscribe'>" | |
| 620 "<group>Business Partners</group>" | |
| 621 "</item>" | |
| 622 "<item jid='walter@example.net' " | |
| 623 "name='Walter Sobchak' " | |
| 624 "subscription='both'>" | |
| 625 "<group>Friends</group>" | |
| 626 "<group>Bowling Team</group>" | |
| 627 "<group>Bowling League</group>" | |
| 628 "</item>" | |
| 629 "<item jid='donny@example.net' " | |
| 630 "name='Donny' " | |
| 631 "subscription='both'>" | |
| 632 "<group>Friends</group>" | |
| 633 "<group>Bowling Team</group>" | |
| 634 "<group>Bowling League</group>" | |
| 635 "</item>" | |
| 636 "<item jid='jeffrey@example.net' " | |
| 637 "name='The Big Lebowski' " | |
| 638 "subscription='to'>" | |
| 639 "<group>Business Partners</group>" | |
| 640 "</item>" | |
| 641 "<item jid='jesus@example.net' " | |
| 642 "name='Jesus Quintana' " | |
| 643 "subscription='from'>" | |
| 644 "<group>Bowling League</group>" | |
| 645 "</item>" | |
| 646 "</query>" | |
| 647 "</iq>"; | |
| 648 | |
| 649 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 650 | |
| 651 EXPECT_EQ(roster_handler.StrClear(), | |
| 652 "[ContactsAdded index:0 number:5 " | |
| 653 "0:[Contact jid:maude@example.net name:Maude Lebowski " | |
| 654 "subscription_state:none_asked " | |
| 655 "groups:[Business Partners]]" | |
| 656 "<ros:item jid=\"maude@example.net\" name=\"Maude Lebowski\" " | |
| 657 "subscription=\"none\" ask=\"subscribe\" " | |
| 658 "xmlns:ros=\"jabber:iq:roster\">" | |
| 659 "<ros:group>Business Partners</ros:group>" | |
| 660 "</ros:item> " | |
| 661 "1:[Contact jid:walter@example.net name:Walter Sobchak " | |
| 662 "subscription_state:both " | |
| 663 "groups:[Friends, Bowling Team, Bowling League]]" | |
| 664 "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " | |
| 665 "subscription=\"both\" " | |
| 666 "xmlns:ros=\"jabber:iq:roster\">" | |
| 667 "<ros:group>Friends</ros:group>" | |
| 668 "<ros:group>Bowling Team</ros:group>" | |
| 669 "<ros:group>Bowling League</ros:group>" | |
| 670 "</ros:item> " | |
| 671 "2:[Contact jid:donny@example.net name:Donny " | |
| 672 "subscription_state:both " | |
| 673 "groups:[Friends, Bowling Team, Bowling League]]" | |
| 674 "<ros:item jid=\"donny@example.net\" name=\"Donny\" " | |
| 675 "subscription=\"both\" " | |
| 676 "xmlns:ros=\"jabber:iq:roster\">" | |
| 677 "<ros:group>Friends</ros:group>" | |
| 678 "<ros:group>Bowling Team</ros:group>" | |
| 679 "<ros:group>Bowling League</ros:group>" | |
| 680 "</ros:item> " | |
| 681 "3:[Contact jid:jeffrey@example.net name:The Big Lebowski " | |
| 682 "subscription_state:to " | |
| 683 "groups:[Business Partners]]" | |
| 684 "<ros:item jid=\"jeffrey@example.net\" name=\"The Big Lebowski\" " | |
| 685 "subscription=\"to\" " | |
| 686 "xmlns:ros=\"jabber:iq:roster\">" | |
| 687 "<ros:group>Business Partners</ros:group>" | |
| 688 "</ros:item> " | |
| 689 "4:[Contact jid:jesus@example.net name:Jesus Quintana " | |
| 690 "subscription_state:from groups:[Bowling League]]" | |
| 691 "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" " | |
| 692 "subscription=\"from\" xmlns:ros=\"jabber:iq:roster\">" | |
| 693 "<ros:group>Bowling League</ros:group>" | |
| 694 "</ros:item>]"); | |
| 695 EXPECT_EQ(handler.OutputActivity(), ""); | |
| 696 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 697 | |
| 698 // Request that someone be added | |
| 699 std::unique_ptr<XmppRosterContact> contact(XmppRosterContact::Create()); | |
| 700 TEST_OK(contact->set_jid(Jid("brandt@example.net"))); | |
| 701 TEST_OK(contact->set_name("Brandt")); | |
| 702 TEST_OK(contact->AddGroup("Business Partners")); | |
| 703 TEST_OK(contact->AddGroup("Watchers")); | |
| 704 TEST_OK(contact->AddGroup("Friends")); | |
| 705 TEST_OK(contact->RemoveGroup("Friends")); // Maybe not... | |
| 706 TEST_OK(roster->RequestRosterChange(contact.get())); | |
| 707 | |
| 708 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 709 EXPECT_EQ(handler.OutputActivity(), | |
| 710 "<iq type=\"set\" id=\"3\">" | |
| 711 "<query xmlns=\"jabber:iq:roster\">" | |
| 712 "<item jid=\"brandt@example.net\" " | |
| 713 "name=\"Brandt\">" | |
| 714 "<group>Business Partners</group>" | |
| 715 "<group>Watchers</group>" | |
| 716 "</item>" | |
| 717 "</query>" | |
| 718 "</iq>"); | |
| 719 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 720 | |
| 721 // Get the push from the server | |
| 722 input = | |
| 723 "<iq type='result' to='david@my-server/test' id='3'/>" | |
| 724 "<iq type='set' id='server_1'>" | |
| 725 "<query xmlns='jabber:iq:roster'>" | |
| 726 "<item jid='brandt@example.net' " | |
| 727 "name='Brandt' " | |
| 728 "subscription='none'>" | |
| 729 "<group>Business Partners</group>" | |
| 730 "<group>Watchers</group>" | |
| 731 "</item>" | |
| 732 "</query>" | |
| 733 "</iq>"; | |
| 734 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 735 | |
| 736 EXPECT_EQ(roster_handler.StrClear(), | |
| 737 "[ContactsAdded index:5 number:1 " | |
| 738 "5:[Contact jid:brandt@example.net name:Brandt " | |
| 739 "subscription_state:none " | |
| 740 "groups:[Business Partners, Watchers]]" | |
| 741 "<ros:item jid=\"brandt@example.net\" name=\"Brandt\" " | |
| 742 "subscription=\"none\" " | |
| 743 "xmlns:ros=\"jabber:iq:roster\">" | |
| 744 "<ros:group>Business Partners</ros:group>" | |
| 745 "<ros:group>Watchers</ros:group>" | |
| 746 "</ros:item>]"); | |
| 747 EXPECT_EQ(handler.OutputActivity(), | |
| 748 "<iq type=\"result\" id=\"server_1\"/>"); | |
| 749 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 750 | |
| 751 // Get a contact update | |
| 752 input = | |
| 753 "<iq type='set' id='server_2'>" | |
| 754 "<query xmlns='jabber:iq:roster'>" | |
| 755 "<item jid='walter@example.net' " | |
| 756 "name='Walter Sobchak' " | |
| 757 "subscription='both'>" | |
| 758 "<group>Friends</group>" | |
| 759 "<group>Bowling Team</group>" | |
| 760 "<group>Bowling League</group>" | |
| 761 "<group>Not wrong, just an...</group>" | |
| 762 "</item>" | |
| 763 "</query>" | |
| 764 "</iq>"; | |
| 765 | |
| 766 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 767 | |
| 768 EXPECT_EQ(roster_handler.StrClear(), | |
| 769 "[ContactChanged " | |
| 770 "old_contact:[Contact jid:walter@example.net name:Walter Sobchak " | |
| 771 "subscription_state:both " | |
| 772 "groups:[Friends, Bowling Team, Bowling League]]" | |
| 773 "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " | |
| 774 "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">" | |
| 775 "<ros:group>Friends</ros:group>" | |
| 776 "<ros:group>Bowling Team</ros:group>" | |
| 777 "<ros:group>Bowling League</ros:group>" | |
| 778 "</ros:item> " | |
| 779 "index:1 " | |
| 780 "new_contact:[Contact jid:walter@example.net name:Walter Sobchak " | |
| 781 "subscription_state:both " | |
| 782 "groups:[Friends, Bowling Team, Bowling League, " | |
| 783 "Not wrong, just an...]]" | |
| 784 "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " | |
| 785 "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">" | |
| 786 "<ros:group>Friends</ros:group>" | |
| 787 "<ros:group>Bowling Team</ros:group>" | |
| 788 "<ros:group>Bowling League</ros:group>" | |
| 789 "<ros:group>Not wrong, just an...</ros:group>" | |
| 790 "</ros:item>]"); | |
| 791 EXPECT_EQ(handler.OutputActivity(), | |
| 792 "<iq type=\"result\" id=\"server_2\"/>"); | |
| 793 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 794 | |
| 795 // Remove a contact | |
| 796 TEST_OK(roster->RequestRosterRemove(Jid("jesus@example.net"))); | |
| 797 | |
| 798 EXPECT_EQ(roster_handler.StrClear(), ""); | |
| 799 EXPECT_EQ(handler.OutputActivity(), | |
| 800 "<iq type=\"set\" id=\"4\">" | |
| 801 "<query xmlns=\"jabber:iq:roster\" jid=\"jesus@example.net\" " | |
| 802 "subscription=\"remove\"/>" | |
| 803 "</iq>"); | |
| 804 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 805 | |
| 806 // Response from the server | |
| 807 input = | |
| 808 "<iq type='result' to='david@my-server/test' id='4'/>" | |
| 809 "<iq type='set' id='server_3'>" | |
| 810 "<query xmlns='jabber:iq:roster'>" | |
| 811 "<item jid='jesus@example.net' " | |
| 812 "subscription='remove'>" | |
| 813 "</item>" | |
| 814 "</query>" | |
| 815 "</iq>"; | |
| 816 TEST_OK(engine->HandleInput(input.c_str(), input.length())); | |
| 817 | |
| 818 EXPECT_EQ(roster_handler.StrClear(), | |
| 819 "[ContactRemoved " | |
| 820 "old_contact:[Contact jid:jesus@example.net name:Jesus Quintana " | |
| 821 "subscription_state:from groups:[Bowling League]]" | |
| 822 "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" " | |
| 823 "subscription=\"from\" " | |
| 824 "xmlns:ros=\"jabber:iq:roster\">" | |
| 825 "<ros:group>Bowling League</ros:group>" | |
| 826 "</ros:item> index:4]"); | |
| 827 EXPECT_EQ(handler.OutputActivity(), | |
| 828 "<iq type=\"result\" id=\"server_3\"/>"); | |
| 829 EXPECT_EQ(handler.SessionActivity(), ""); | |
| 830 } | |
| 831 | |
| 832 } | |
| OLD | NEW |