source: wokkel/test/test_muc.py @ 131:d72d60360630

wokkel-muc-client-support-24
Last change on this file since 131:d72d60360630 was 131:d72d60360630, checked in by Ralph Meijer <ralphm@…>, 13 years ago

More renames, argument consistency.

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