source: wokkel/test/test_muc.py @ 118:a70736af32c3

wokkel-muc-client-support-24
Last change on this file since 118:a70736af32c3 was 118:a70736af32c3, checked in by Christopher Zorn <tofu@…>, 14 years ago

add timeouts and a test for a user leaving a room

File size: 13.1 KB
RevLine 
[107]1# Copyright (c) 2003-2008 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 import error
14from twisted.words.protocols.jabber.jid import JID
15
[108]16from wokkel import data_form, iwokkel, muc, shim, disco
[107]17from wokkel.generic import parseXml
18from wokkel.test.helpers import XmlStreamStub
19
20try:
21    from twisted.words.protocols.jabber.xmlstream import toResponse
22except ImportError:
23    from wokkel.compat import toResponse
24
25
26def calledAsync(fn):
27    """
28    Function wrapper that fires a deferred upon calling the given function.
29    """
30    d = defer.Deferred()
31
32    def func(*args, **kwargs):
33        try:
34            result = fn(*args, **kwargs)
35        except:
36            d.errback()
37        else:
38            d.callback(result)
39
40    return d, func
41
42
43class MucClientTest(unittest.TestCase):
44    timeout = 2
45
46    def setUp(self):
47        self.stub = XmlStreamStub()
48        self.protocol = muc.MUCClient()
49        self.protocol.xmlstream = self.stub.xmlstream
50        self.protocol.connectionInitialized()
[110]51        self.test_room = 'test'
52        self.test_srv  = 'conference.example.org'
53        self.test_nick = 'Nick'
[107]54
[110]55        self.room_jid = JID(self.test_room+'@'+self.test_srv+'/'+self.test_nick)
[107]56
[112]57        self.user_jid = JID('test@jabber.org/Testing')
58
[113]59    def _createRoom(self):
[117]60        """A helper method to create a test room.
61        """
[113]62        # create a room
63        self.current_room = muc.Room(self.test_room, self.test_srv, self.test_nick)
64        self.protocol._setRoom(self.current_room)
65
66
[107]67    def test_interface(self):
68        """
69        Do instances of L{muc.MUCClient} provide L{iwokkel.IMUCClient}?
70        """
71        verify.verifyObject(iwokkel.IMUCClient, self.protocol)
72
73
[113]74    def test_userJoinedRoom(self):
[117]75        """The client receives presence from an entity joining the room.
[109]76        """
77        p = muc.UserPresence()
[113]78        p['to'] = self.user_jid.full()
79        p['from'] = self.room_jid.full()
80
81        # create a room
82        self._createRoom()
83
84        def userPresence(room, user):
85            self.failUnless(room.name==self.test_room, 'Wrong room name')
86            self.failUnless(room.inRoster(user), 'User not in roster')
87                           
[109]88       
[113]89        d, self.protocol.userJoinedRoom = calledAsync(userPresence)
[109]90        self.stub.send(p)
91        return d
92
93
94    def test_groupChat(self):
[117]95        """The client receives a groupchat message from an entity in the room.
[109]96        """
97        m = muc.GroupChat('test@test.com',body='test')
[113]98        m['from'] = self.room_jid.full()
99
100        self._createRoom()
101
102        def groupChat(room, user, message):
103            self.failUnless(message=='test', "Wrong group chat message")
104            self.failUnless(room.name==self.test_room, 'Wrong room name')
[109]105                           
106       
107        d, self.protocol.receivedGroupChat = calledAsync(groupChat)
108        self.stub.send(m)
109        return d
110
[108]111
112    def test_discoServerSupport(self):
[117]113        """Disco support from client to server.
[107]114        """
[108]115        test_srv = 'shakespeare.lit'
[107]116
[108]117        def cb(query):
118            # check namespace
119            self.failUnless(query.uri==disco.NS_INFO, 'Wrong namespace')
[107]120           
121
[108]122        d = self.protocol.disco(test_srv)
123        d.addCallback(cb)
124
125        iq = self.stub.output[-1]
126       
127        # send back a response
128        response = toResponse(iq, 'result')
129        response.addElement('query', disco.NS_INFO)
130        # need to add information to response
[116]131        response.query.addChild(disco.DiscoFeature(muc.NS_MUC))
[108]132        response.query.addChild(disco.DiscoIdentity(category='conference',
133                                                    name='Macbeth Chat Service',
134                                                    type='text'))
135       
136        self.stub.send(response)
[107]137        return d
[108]138       
[107]139
[108]140       
[107]141    def test_joinRoom(self):
[117]142        """Joining a room
[107]143        """
[110]144       
[107]145        def cb(room):
[110]146            self.assertEquals(self.test_room, room.name)
[107]147
[110]148        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
[107]149        d.addCallback(cb)
150
151        prs = self.stub.output[-1]
152        self.failUnless(prs.name=='presence', "Need to be presence")
153        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
[108]154
155        # send back user presence, they joined       
[110]156        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+self.test_nick)
[108]157        self.stub.send(response)
158        return d
159
160
161    def test_joinRoomForbidden(self):
[117]162        """Client joining a room and getting a forbidden error.
[108]163        """
164
165        def cb(error):
166            self.failUnless(isinstance(error.value,muc.PresenceError), 'Wrong type')
167            self.failUnless(error.value['type']=='error', 'Not an error returned')
168           
169           
[110]170        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
[108]171        d.addBoth(cb)
172
173        prs = self.stub.output[-1]
174        self.failUnless(prs.name=='presence', "Need to be presence")
175        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
[107]176        # send back user presence, they joined
177       
[108]178        response = muc.PresenceError(error=muc.MUCError('auth',
179                                                        'forbidden'
180                                                        ),
[110]181                                     frm=self.room_jid.full())
[107]182        self.stub.send(response)
[108]183        return d       
[109]184
[110]185    def test_partRoom(self):
[117]186        """Client leaves a room
187        """
[112]188        def cb(left):
189            self.failUnless(left, 'did not leave room')
190
191
192        d = self.protocol.leave(self.room_jid)
193        d.addCallback(cb)
194
195        prs = self.stub.output[-1]
196       
197        self.failUnless(prs['type']=='unavailable', 'Unavailable is not being sent')
198       
199        response = prs
200        response['from'] = response['to']
201        response['to'] = 'test@jabber.org'
202
203        self.stub.send(response)
204        return d
[110]205       
206
[118]207    def test_userPartsRoom(self):
208        """An entity leaves the room, a presence of type unavailable is received by the client.
209        """
210
211        p = muc.UnavailableUserPresence()
212        p['to'] = self.user_jid.full()
213        p['from'] = self.room_jid.full()
214
215        # create a room
216        self._createRoom()
217        # add user to room
218        u = muc.User(self.room_jid.resource)
219
220        room = self.protocol._getRoom(self.room_jid)
221        room.addUser(u)
222
223        def userPresence(room, user):
224            self.failUnless(room.name==self.test_room, 'Wrong room name')
225            self.failUnless(room.inRoster(user)==False, 'User in roster')
226                           
227        d, self.protocol.userLeftRoom = calledAsync(userPresence)
228        self.stub.send(p)
229        return d
230       
231
[110]232    def test_ban(self):
[117]233        """Ban an entity in a room.
234        """
[112]235        banned = JID('ban@jabber.org/TroubleMakger')
236        def cb(banned):
237            self.failUnless(banned, 'Did not ban user')
238
239           
240        d = self.protocol.ban(self.room_jid, banned, self.user_jid, reason='Spam')
241        d.addCallback(cb)
242
243        iq = self.stub.output[-1]
244       
245        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='outcast']" % (self.room_jid.userhost(),), iq), 'Wrong ban stanza')
246
247        response = toResponse(iq, 'result')
248
249        self.stub.send(response)
250
251        return d
252
[110]253
254    def test_kick(self):
[117]255        """Kick an entity from a room.
256        """
[112]257        kicked = JID('kick@jabber.org/TroubleMakger')
258        def cb(kicked):
259            self.failUnless(kicked, 'Did not kick user')
260
261           
262        d = self.protocol.kick(self.room_jid, kicked, self.user_jid, reason='Spam')
263        d.addCallback(cb)
264
265        iq = self.stub.output[-1]
266       
267        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='none']" % (self.room_jid.userhost(),), iq), 'Wrong kick stanza')
268
269        response = toResponse(iq, 'result')
270
271        self.stub.send(response)
272
273        return d
274
[110]275       
276
277    def test_password(self):
[117]278        """Sending a password via presence to a password protected room.
[110]279        """
280       
[112]281        self.protocol.password(self.room_jid, 'secret')
[110]282       
[112]283        prs = self.stub.output[-1]
284       
285        self.failUnless(xpath.matches("/presence[@to='%s']/x/password[text()='secret']" % (self.room_jid.full(),), prs), 'Wrong presence stanza')
286
[110]287
288    def test_history(self):
[117]289        """Receiving history on room join.
[112]290        """
291        m = muc.HistoryMessage(self.room_jid.userhost(), self.protocol._makeTimeStamp(), body='test')
[113]292        m['from'] = self.room_jid.full()
293       
294        self._createRoom()
295
296        def roomHistory(room, user, body, stamp, frm=None):
297            self.failUnless(body=='test', "wrong message body")
298            self.failUnless(stamp, 'Does not have a history stamp')
[112]299                   
300
301        d, self.protocol.receivedHistory = calledAsync(roomHistory)
302        self.stub.send(m)
303        return d
[110]304
305
306    def test_oneToOneChat(self):
[117]307        """Converting a one to one chat to a multi-user chat.
[110]308        """
309        archive = []
310        thread = "e0ffe42b28561960c6b12b944a092794b9683a38"
311        # create messages
312        msg = domish.Element((None, 'message'))
313        msg['to'] = 'testing@example.com'
314        msg['type'] = 'chat'
315        msg.addElement('body', None, 'test')
316        msg.addElement('thread', None, thread)
317
318        archive.append(msg)
319
320        msg = domish.Element((None, 'message'))
321        msg['to'] = 'testing2@example.com'
322        msg['type'] = 'chat'
323        msg.addElement('body', None, 'yo')
324        msg.addElement('thread', None, thread)
325
326        archive.append(msg)
327
328        self.protocol.history(self.room_jid.userhost(), archive)
329
330
331        while len(self.stub.output)>0:
332            m = self.stub.output.pop()
333            # check for delay element
334            self.failUnless(m.name=='message', 'Wrong stanza')
335            self.failUnless(xpath.matches("/message/delay", m), 'Invalid history stanza')
336       
337
338    def test_invite(self):
[117]339        """Invite a user to a room
340        """
[112]341        other_jid = 'test@jabber.org'
342
343        self.protocol.invite(other_jid, 'This is a test')
344
345        msg = self.stub.output[-1]
346
347        self.failUnless(xpath.matches("/message[@to='%s']/x/invite/reason" % (other_jid,), msg), 'Wrong message type')
348
[110]349
350       
351    def test_privateMessage(self):
[117]352        """Send private messages to muc entities.
[112]353        """
354        other_nick = self.room_jid.userhost()+'/OtherNick'
355
356        self.protocol.chat(other_nick, 'This is a test')
357
358        msg = self.stub.output[-1]
359
360        self.failUnless(xpath.matches("/message[@type='chat' and @to='%s']/body" % (other_nick,), msg), 'Wrong message type')
361
[110]362
363    def test_register(self):
[117]364        """Client registering with a room. http://xmpp.org/extensions/xep-0045.html#register
[111]365
366        """
367       
368        def cb(iq):
369            # check for a result
370            self.failUnless(iq['type']=='result', 'We did not get a result')
371       
372        d = self.protocol.register(self.room_jid.userhost())
373        d.addCallback(cb)
374
375        iq = self.stub.output[-1]
376        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']" % (muc.NS_REQUEST), iq), 'Invalid iq register request')
377       
378        response = toResponse(iq, 'result')
[116]379       
[111]380        self.stub.send(response)
381        return d
[110]382
383    def test_voice(self):
[117]384        """ Client requesting voice for a room.
[111]385        """
[110]386        self.protocol.voice(self.room_jid.userhost())
387
388        m = self.stub.output[-1]
[111]389       
[116]390        self.failUnless(xpath.matches("/message/x[@type='submit']/field/value[text()='%s']" % (muc.NS_MUC_REQUEST,), m), 'Invalid voice message stanza')
[110]391
392
[109]393    def test_roomConfigure(self):
[117]394        """ Default configure and changing the room name.
[111]395        """
[109]396
[111]397        def cb(iq):
398            self.failUnless(iq['type']=='result', 'Not a result')
399           
400
401        fields = []
402
403        fields.append(data_form.Field(label='Natural-Language Room Name',
404                                      var='muc#roomconfig_roomname',
405                                      value=self.test_room))
[109]406       
[111]407        d = self.protocol.configure(self.room_jid.userhost(), fields)
408        d.addCallback(cb)
[109]409
[111]410        iq = self.stub.output[-1]
[116]411        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']/x"% (muc.NS_MUC_OWNER,), iq), 'Bad configure request')
[111]412       
413        response = toResponse(iq, 'result')
414        self.stub.send(response)
415        return d
416
417
[117]418    def test_nickChange(self):
419        """Send a nick change to the server.
420        """
421        test_nick = 'newNick'
422       
423        self._createRoom()
424
425        def cb(room):
426            self.assertEquals(self.test_room, room.name)
427            self.assertEquals(test_nick, room.nick)
428
429        d = self.protocol.nick(self.room_jid, test_nick)
430        d.addCallback(cb)
431
432        prs = self.stub.output[-1]
433        self.failUnless(prs.name=='presence', "Need to be presence")
434        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
435
436        # send back user presence, they joined       
437        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+test_nick)
438       
439        self.stub.send(response)
440        return d
441
442       
Note: See TracBrowser for help on using the repository browser.