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 |