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 |