• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sstream>
13 #include <string>
14 
15 #include "webrtc/libjingle/xmllite/xmlelement.h"
16 #include "webrtc/libjingle/xmpp/constants.h"
17 #include "webrtc/libjingle/xmpp/rostermodule.h"
18 #include "webrtc/libjingle/xmpp/util_unittest.h"
19 #include "webrtc/libjingle/xmpp/xmppengine.h"
20 #include "webrtc/base/gunit.h"
21 #include "webrtc/base/scoped_ptr.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
WriteString(std::ostream & os,const std::string & str)32 WriteString(std::ostream& os, const std::string& str) {
33   os<<str;
34 }
35 
36 static void
WriteSubscriptionState(std::ostream & os,XmppSubscriptionState state)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
WriteSubscriptionRequestType(std::ostream & os,XmppSubscriptionRequestType type)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
WritePresenceShow(std::ostream & os,XmppPresenceShow show)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
WritePresence(std::ostream & os,const XmppPresence * presence)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
WriteContact(std::ostream & os,const XmppRosterContact * contact)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:
XmppTestRosterHandler()153   XmppTestRosterHandler() {}
~XmppTestRosterHandler()154   virtual ~XmppTestRosterHandler() {}
155 
SubscriptionRequest(XmppRosterModule *,const Jid & requesting_jid,XmppSubscriptionRequestType type,const XmlElement * raw_xml)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
SubscriptionError(XmppRosterModule *,const Jid & from,const XmlElement * raw_xml)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 
RosterError(XmppRosterModule *,const XmlElement * raw_xml)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.
IncomingPresenceChanged(XmppRosterModule *,const XmppPresence * presence)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.
ContactChanged(XmppRosterModule * roster,const XmppRosterContact * old_contact,size_t index)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.
ContactsAdded(XmppRosterModule * roster,size_t index,size_t number)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.
ContactRemoved(XmppRosterModule *,const XmppRosterContact * removed_contact,size_t index)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 
Str()223   std::string Str() {
224     return ss_.str();
225   }
226 
StrClear()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:
RosterModuleTest()241   RosterModuleTest() {}
RunLogin(RosterModuleTest * obj,XmppEngine * engine,XmppTestHandler * handler)242   static void RunLogin(RosterModuleTest* obj, XmppEngine* engine,
243                        XmppTestHandler* handler) {
244     // Needs to be similar to XmppEngineTest::RunLogin
245   }
246 };
247 
TEST_F(RosterModuleTest,TestPresence)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   rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create());
254   presence->set_raw_xml(&presence_xml);
255   EXPECT_EQ(presence->connection_status(), XMPP_CONNECTION_STATUS_CONNECTING);
256 }
257 
TEST_F(RosterModuleTest,TestOutgoingPresence)258 TEST_F(RosterModuleTest, TestOutgoingPresence) {
259   std::stringstream dump;
260 
261   rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
262   XmppTestHandler handler(engine.get());
263   XmppTestRosterHandler roster_handler;
264 
265   rtc::scoped_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!&lt;&gt;&amp;</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   rtc::scoped_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 
TEST_F(RosterModuleTest,TestIncomingPresence)383 TEST_F(RosterModuleTest, TestIncomingPresence) {
384   rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
385   XmppTestHandler handler(engine.get());
386   XmppTestRosterHandler roster_handler;
387 
388   rtc::scoped_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 
TEST_F(RosterModuleTest,TestPresenceSubscription)515 TEST_F(RosterModuleTest, TestPresenceSubscription) {
516   rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
517   XmppTestHandler handler(engine.get());
518   XmppTestRosterHandler roster_handler;
519 
520   rtc::scoped_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 
TEST_F(RosterModuleTest,TestRosterReceive)578 TEST_F(RosterModuleTest, TestRosterReceive) {
579   rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create());
580   XmppTestHandler handler(engine.get());
581   XmppTestRosterHandler roster_handler;
582 
583   rtc::scoped_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   rtc::scoped_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 }
833