source: wokkel/test/test_muc.py @ 132:1b19c49d30c2

wokkel-muc-client-support-24
Last change on this file since 132:1b19c49d30c2 was 132:1b19c49d30c2, checked in by Ralph Meijer <ralphm@…>, 11 years ago

More renames.

File size: 16.4 KB
Line 
1# Copyright (c) 2003-2009 Ralph Meijer
2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.muc}
6"""
7
8from zope.interface import verify
9
10from twisted.trial import unittest
11from twisted.internet import defer
12from twisted.words.xish import domish, xpath
13from twisted.words.protocols.jabber.jid import JID
14
15from wokkel import data_form, iwokkel, muc, disco
16from wokkel.test.helpers import XmlStreamStub
17
18from twisted.words.protocols.jabber.xmlstream import toResponse
19
20NS_MUC_ADMIN = 'http://jabber.org/protocol/muc#admin'
21
22def calledAsync(fn):
23    """
24    Function wrapper that fires a deferred upon calling the given function.
25    """
26    d = defer.Deferred()
27
28    def func(*args, **kwargs):
29        try:
30            result = fn(*args, **kwargs)
31        except:
32            d.errback()
33        else:
34            d.callback(result)
35
36    return d, func
37
38
39
40class MucClientTest(unittest.TestCase):
41    timeout = 2
42
43    def setUp(self):
44        self.stub = XmlStreamStub()
45        self.protocol = muc.MUCClient()
46        self.protocol.xmlstream = self.stub.xmlstream
47        self.protocol.connectionInitialized()
48        self.test_room = 'test'
49        self.test_srv  = 'conference.example.org'
50        self.test_nick = 'Nick'
51
52        self.room_jid = JID(self.test_room+'@'+self.test_srv+'/'+self.test_nick)
53
54        self.user_jid = JID('test@jabber.org/Testing')
55
56
57    def _createRoom(self):
58        """
59        A helper method to create a test room.
60        """
61        # create a room
62        self.current_room = muc.Room(self.test_room, self.test_srv, self.test_nick)
63        self.protocol._addRoom(self.current_room)
64
65
66    def test_interface(self):
67        """
68        Do instances of L{muc.MUCClient} provide L{iwokkel.IMUCClient}?
69        """
70        verify.verifyObject(iwokkel.IMUCClient, self.protocol)
71
72
73    def test_userJoinedRoom(self):
74        """
75        The client receives presence from an entity joining the room.
76
77        This tests the class L{muc.UserPresence} and the userJoinedRoom event method.
78
79        The test sends the user presence and tests if the event method is called.
80
81        """
82        p = muc.UserPresence()
83        p['to'] = self.user_jid.full()
84        p['from'] = self.room_jid.full()
85
86        # create a room
87        self._createRoom()
88
89        def userPresence(room, user):
90            self.assertEqual(self.test_room, room.roomIdentifier,
91                             'Wrong room name')
92            self.assertTrue(room.inRoster(user), 'User not in roster')
93
94
95        d, self.protocol.userJoinedRoom = calledAsync(userPresence)
96        self.stub.send(p)
97        return d
98
99
100    def test_groupChat(self):
101        """
102        The client receives a groupchat message from an entity in the room.
103        """
104        m = muc.GroupChat('test@test.com',body='test')
105        m['from'] = self.room_jid.full()
106
107        self._createRoom()
108
109        def groupChat(room, user, message):
110            self.failUnless(message=='test', "Wrong group chat message")
111            self.failUnless(room.roomIdentifier==self.test_room, 'Wrong room name')
112
113
114        d, self.protocol.receivedGroupChat = calledAsync(groupChat)
115        self.stub.send(m)
116        return d
117
118
119    def test_joinRoom(self):
120        """
121        Joining a room
122        """
123
124        def cb(room):
125            self.assertEqual(self.test_room, room.roomIdentifier)
126
127        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
128        d.addCallback(cb)
129
130        prs = self.stub.output[-1]
131        self.failUnless(prs.name=='presence', "Need to be presence")
132        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
133
134        # send back user presence, they joined
135        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+self.test_nick)
136        self.stub.send(response)
137        return d
138
139
140    def test_joinRoomForbidden(self):
141        """
142        Client joining a room and getting a forbidden error.
143        """
144
145        def cb(error):
146
147            self.failUnless(error.value.mucCondition=='forbidden','Wrong muc condition')
148
149
150
151        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
152        d.addBoth(cb)
153
154        prs = self.stub.output[-1]
155        self.failUnless(prs.name=='presence', "Need to be presence")
156        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
157        # send back user presence, they joined
158
159        response = muc.PresenceError(error=muc.MUCError('auth',
160                                                        'forbidden'
161                                                        ),
162                                     frm=self.room_jid.full())
163        self.stub.send(response)
164        return d
165
166
167    def test_joinRoomBadJid(self):
168        """
169        Client joining a room and getting a forbidden error.
170        """
171
172        def cb(error):
173
174            self.failUnless(error.value.mucCondition=='jid-malformed','Wrong muc condition')
175
176
177
178        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
179        d.addBoth(cb)
180
181        prs = self.stub.output[-1]
182        self.failUnless(prs.name=='presence', "Need to be presence")
183        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
184        # send back user presence, they joined
185
186        response = muc.PresenceError(error=muc.MUCError('modify',
187                                                        'jid-malformed'
188                                                        ),
189                                     frm=self.room_jid.full())
190        self.stub.send(response)
191        return d
192
193
194    def test_partRoom(self):
195        """
196        Client leaves a room
197        """
198        def cb(left):
199            self.failUnless(left, 'did not leave room')
200
201
202        self._createRoom()
203        d = self.protocol.leave(self.room_jid)
204        d.addCallback(cb)
205
206        prs = self.stub.output[-1]
207
208        self.failUnless(prs['type']=='unavailable', 'Unavailable is not being sent')
209
210        response = prs
211        response['from'] = response['to']
212        response['to'] = 'test@jabber.org'
213
214        self.stub.send(response)
215        return d
216
217
218    def test_userPartsRoom(self):
219        """
220        An entity leaves the room, a presence of type unavailable is received by the client.
221        """
222
223        p = muc.UnavailableUserPresence()
224        p['to'] = self.user_jid.full()
225        p['from'] = self.room_jid.full()
226
227        # create a room
228        self._createRoom()
229        # add user to room
230        user = muc.User(self.room_jid.resource)
231
232        room = self.protocol._getRoom(self.room_jid)
233        room.addUser(user)
234
235        def userPresence(room, user):
236            self.failUnless(room.roomIdentifier==self.test_room, 'Wrong room name')
237            self.failUnless(room.inRoster(user)==False, 'User in roster')
238
239        d, self.protocol.userLeftRoom = calledAsync(userPresence)
240        self.stub.send(p)
241        return d
242
243
244    def test_ban(self):
245        """
246        Ban an entity in a room.
247        """
248        banned = JID('ban@jabber.org/TroubleMakger')
249        def cb(banned):
250            self.failUnless(banned, 'Did not ban user')
251
252
253        d = self.protocol.ban(self.room_jid, banned, reason='Spam',
254                              sender=self.user_jid)
255        d.addCallback(cb)
256
257        iq = self.stub.output[-1]
258
259        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='outcast']" % (self.room_jid.userhost(),), iq), 'Wrong ban stanza')
260
261        response = toResponse(iq, 'result')
262
263        self.stub.send(response)
264
265        return d
266
267
268    def test_kick(self):
269        """
270        Kick an entity from a room.
271        """
272        nick = 'TroubleMakger'
273
274        def cb(kicked):
275            self.failUnless(kicked, 'Did not kick user')
276
277        d = self.protocol.kick(self.room_jid, nick, reason='Spam',
278                               sender=self.user_jid)
279        d.addCallback(cb)
280
281        iq = self.stub.output[-1]
282
283        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='none']" % (self.room_jid.userhost(),), iq), 'Wrong kick stanza')
284
285        response = toResponse(iq, 'result')
286
287        self.stub.send(response)
288
289        return d
290
291
292    def test_password(self):
293        """
294        Sending a password via presence to a password protected room.
295        """
296
297        self.protocol.password(self.room_jid, 'secret')
298
299        prs = self.stub.output[-1]
300
301        self.failUnless(xpath.matches("/presence[@to='%s']/x/password[text()='secret']" % (self.room_jid.full(),), prs), 'Wrong presence stanza')
302
303
304    def test_history(self):
305        """
306        Receiving history on room join.
307        """
308        m = muc.HistoryMessage(self.room_jid.userhost(), self.protocol._makeTimeStamp(), body='test')
309        m['from'] = self.room_jid.full()
310
311        self._createRoom()
312
313        def roomHistory(room, user, body, stamp, frm=None):
314            self.failUnless(body=='test', "wrong message body")
315            self.failUnless(stamp, 'Does not have a history stamp')
316
317
318        d, self.protocol.receivedHistory = calledAsync(roomHistory)
319        self.stub.send(m)
320        return d
321
322
323    def test_oneToOneChat(self):
324        """
325        Converting a one to one chat to a multi-user chat.
326        """
327        archive = []
328        thread = "e0ffe42b28561960c6b12b944a092794b9683a38"
329        # create messages
330        msg = domish.Element((None, 'message'))
331        msg['to'] = 'testing@example.com'
332        msg['type'] = 'chat'
333        msg.addElement('body', None, 'test')
334        msg.addElement('thread', None, thread)
335
336        archive.append({'stanza': msg, 'timestamp': '2002-10-13T23:58:37Z'})
337
338        msg = domish.Element((None, 'message'))
339        msg['to'] = 'testing2@example.com'
340        msg['type'] = 'chat'
341        msg.addElement('body', None, 'yo')
342        msg.addElement('thread', None, thread)
343
344        archive.append({'stanza': msg, 'timestamp': '2002-10-13T23:58:43Z'})
345
346        self.protocol.history(self.room_jid, archive)
347
348
349        while len(self.stub.output)>0:
350            m = self.stub.output.pop()
351            # check for delay element
352            self.failUnless(m.name=='message', 'Wrong stanza')
353            self.failUnless(xpath.matches("/message/delay", m), 'Invalid history stanza')
354
355
356    def test_invite(self):
357        """
358        Invite a user to a room
359        """
360        bareRoomJID = self.room_jid.userhostJID()
361        invitee = JID('test@jabber.org')
362
363        self.protocol.invite(bareRoomJID, 'This is a test', invitee)
364
365        msg = self.stub.output[-1]
366
367        query = u"/message[@to='%s']/x/invite/reason" % bareRoomJID
368        self.failUnless(xpath.matches(query, msg), 'Wrong message type')
369
370
371    def test_privateMessage(self):
372        """
373        Send private messages to muc entities.
374        """
375        other_nick = self.room_jid.userhost()+'/OtherNick'
376
377        self.protocol.chat(other_nick, 'This is a test')
378
379        msg = self.stub.output[-1]
380
381        self.failUnless(xpath.matches("/message[@type='chat' and @to='%s']/body" % (other_nick,), msg), 'Wrong message type')
382
383
384    def test_register(self):
385        """
386        Client registering with a room. http://xmpp.org/extensions/xep-0045.html#register
387
388        """
389
390        def cb(iq):
391            # check for a result
392            self.failUnless(iq['type']=='result', 'We did not get a result')
393
394        d = self.protocol.register(self.room_jid)
395        d.addCallback(cb)
396
397        iq = self.stub.output[-1]
398        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']" % (muc.NS_REQUEST), iq), 'Invalid iq register request')
399
400        response = toResponse(iq, 'result')
401
402        self.stub.send(response)
403        return d
404
405
406    def test_voice(self):
407        """
408        Client requesting voice for a room.
409        """
410        self.protocol.voice(self.room_jid)
411
412        m = self.stub.output[-1]
413
414        self.failUnless(xpath.matches("/message/x[@type='submit']/field/value[text()='%s']" % (muc.NS_MUC_REQUEST,), m), 'Invalid voice message stanza')
415
416
417    def test_roomConfigure(self):
418        """
419        Default configure and changing the room name.
420        """
421
422        def cb(iq):
423            self.failUnless(iq['type']=='result', 'Not a result')
424
425
426        fields = []
427
428        fields.append(data_form.Field(label='Natural-Language Room Name',
429                                      var='muc#roomconfig_roomname',
430                                      value=self.test_room))
431
432        d = self.protocol.configure(self.room_jid.userhost(), fields)
433        d.addCallback(cb)
434
435        iq = self.stub.output[-1]
436        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']/x"% (muc.NS_MUC_OWNER,), iq), 'Bad configure request')
437
438        response = toResponse(iq, 'result')
439        self.stub.send(response)
440        return d
441
442
443    def test_roomDestroy(self):
444        """
445        Destroy a room.
446        """
447
448        def cb(destroyed):
449            self.failUnless(destroyed==True, 'Room not destroyed.')
450
451        d = self.protocol.destroy(self.room_jid)
452        d.addCallback(cb)
453
454        iq = self.stub.output[-1]
455        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']/destroy"% (muc.NS_MUC_OWNER,), iq), 'Bad configure request')
456
457        response = toResponse(iq, 'result')
458        self.stub.send(response)
459        return d
460
461
462    def test_nickChange(self):
463        """
464        Send a nick change to the server.
465        """
466        test_nick = 'newNick'
467
468        self._createRoom()
469
470        def cb(room):
471            self.assertEqual(self.test_room, room.roomIdentifier)
472            self.assertEqual(test_nick, room.nick)
473
474        d = self.protocol.nick(self.room_jid, test_nick)
475        d.addCallback(cb)
476
477        prs = self.stub.output[-1]
478        self.failUnless(prs.name=='presence', "Need to be presence")
479        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
480
481        # send back user presence, they joined
482        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+test_nick)
483
484        self.stub.send(response)
485        return d
486
487
488    def test_grantVoice(self):
489        """
490        Test granting voice to a user.
491
492        """
493        nick = 'TroubleMakger'
494        def cb(give_voice):
495            self.failUnless(give_voice, 'Did not give voice user')
496
497
498        d = self.protocol.grantVoice(self.room_jid, nick, sender=self.user_jid)
499        d.addCallback(cb)
500
501        iq = self.stub.output[-1]
502
503        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@role='participant']" % (self.room_jid.userhost(),), iq), 'Wrong voice stanza')
504
505        response = toResponse(iq, 'result')
506
507        self.stub.send(response)
508
509        return d
510
511
512    def test_changeStatus(self):
513        """
514        Change status
515        """
516        self._createRoom()
517        room = self.protocol._getRoom(self.room_jid)
518        user = muc.User(self.room_jid.resource)
519        room.addUser(user)
520
521        def cb(room):
522            self.assertEqual(self.test_room, room.roomIdentifier)
523            user = room.getUser(self.room_jid.resource)
524            self.assertNotIdentical(None, user, 'User not found')
525            self.assertEqual('testing MUC', user.status, 'Wrong status')
526            self.assertEqual('xa', user.show, 'Wrong show')
527
528        d = self.protocol.status(self.room_jid, 'xa', 'testing MUC')
529        d.addCallback(cb)
530
531        prs = self.stub.output[-1]
532
533        self.assertEqual('presence', prs.name, "Need to be presence")
534        self.assertTrue(getattr(prs, 'x', None), 'No muc x element')
535
536        # send back user presence, they joined
537        response = muc.UserPresence(frm=self.room_jid.full())
538        response.addElement('show', None, 'xa')
539        response.addElement('status', None, 'testing MUC')
540        self.stub.send(response)
541        return d
542
543
544    def test_getMemberList(self):
545        def cb(room):
546            members = room.members
547            self.assertEqual(1, len(members))
548            user = members[0]
549            self.assertEqual(JID(u'hag66@shakespeare.lit'), user.entity)
550            self.assertEqual(u'thirdwitch', user.nick)
551            self.assertEqual(u'participant', user.role)
552
553        self._createRoom()
554        bareRoomJID = self.room_jid.userhostJID()
555        d = self.protocol.getMemberList(bareRoomJID)
556        d.addCallback(cb)
557
558        iq = self.stub.output[-1]
559        query = iq.query
560        self.assertNotIdentical(None, query)
561        self.assertEqual(NS_MUC_ADMIN, query.uri)
562
563        response = toResponse(iq, 'result')
564        query = response.addElement((NS_MUC_ADMIN, 'query'))
565        item = query.addElement('item')
566        item['affiliation'] ='member'
567        item['jid'] = 'hag66@shakespeare.lit'
568        item['nick'] = 'thirdwitch'
569        item['role'] = 'participant'
570        self.stub.send(response)
571
572        return d
573
574
Note: See TracBrowser for help on using the repository browser.