source: wokkel/test/test_muc.py @ 125:edb21c02197b

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

docstrings, tests and bug fixes

File size: 14.8 KB
Line 
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
16from wokkel import data_form, iwokkel, muc, shim, disco
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()
51        self.test_room = 'test'
52        self.test_srv  = 'conference.example.org'
53        self.test_nick = 'Nick'
54
55        self.room_jid = JID(self.test_room+'@'+self.test_srv+'/'+self.test_nick)
56
57        self.user_jid = JID('test@jabber.org/Testing')
58
59    def _createRoom(self):
60        """A helper method to create a test room.
61        """
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
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
74    def test_userJoinedRoom(self):
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.name==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        """The client receives a groupchat message from an entity in the room.
101        """
102        m = muc.GroupChat('test@test.com',body='test')
103        m['from'] = self.room_jid.full()
104
105        self._createRoom()
106
107        def groupChat(room, user, message):
108            self.failUnless(message=='test', "Wrong group chat message")
109            self.failUnless(room.name==self.test_room, 'Wrong room name')
110                           
111       
112        d, self.protocol.receivedGroupChat = calledAsync(groupChat)
113        self.stub.send(m)
114        return d
115
116
117    def test_discoServerSupport(self):
118        """Disco support from client to server.
119        """
120        test_srv = 'shakespeare.lit'
121
122        def cb(query):
123            # check namespace
124            self.failUnless(query.uri==disco.NS_INFO, 'Wrong namespace')
125           
126
127        d = self.protocol.disco(test_srv)
128        d.addCallback(cb)
129
130        iq = self.stub.output[-1]
131       
132        # send back a response
133        response = toResponse(iq, 'result')
134        response.addElement('query', disco.NS_INFO)
135        # need to add information to response
136        response.query.addChild(disco.DiscoFeature(muc.NS_MUC))
137        response.query.addChild(disco.DiscoIdentity(category='conference',
138                                                    name='Macbeth Chat Service',
139                                                    type='text'))
140       
141        self.stub.send(response)
142        return d
143       
144
145       
146    def test_joinRoom(self):
147        """Joining a room
148        """
149       
150        def cb(room):
151            self.assertEquals(self.test_room, room.name)
152
153        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
154        d.addCallback(cb)
155
156        prs = self.stub.output[-1]
157        self.failUnless(prs.name=='presence', "Need to be presence")
158        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
159
160        # send back user presence, they joined       
161        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+self.test_nick)
162        self.stub.send(response)
163        return d
164
165   
166
167    def test_joinRoomForbidden(self):
168        """Client joining a room and getting a forbidden error.
169        """
170
171        def cb(error):
172           
173            self.failUnless(error.value.mucCondition=='forbidden','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('auth',
186                                                        'forbidden'
187                                                        ),
188                                     frm=self.room_jid.full())
189        self.stub.send(response)
190        return d       
191
192
193    def test_joinRoomBadJid(self):
194        """Client joining a room and getting a forbidden error.
195        """
196
197        def cb(error):
198           
199            self.failUnless(error.value.mucCondition=='jid-malformed','Wrong muc condition')
200
201           
202           
203        d = self.protocol.join(self.test_srv, self.test_room, self.test_nick)
204        d.addBoth(cb)
205
206        prs = self.stub.output[-1]
207        self.failUnless(prs.name=='presence', "Need to be presence")
208        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
209        # send back user presence, they joined
210       
211        response = muc.PresenceError(error=muc.MUCError('modify',
212                                                        'jid-malformed'
213                                                        ),
214                                     frm=self.room_jid.full())
215        self.stub.send(response)
216        return d       
217
218
219
220    def test_partRoom(self):
221        """Client leaves a room
222        """
223        def cb(left):
224            self.failUnless(left, 'did not leave room')
225
226
227        d = self.protocol.leave(self.room_jid)
228        d.addCallback(cb)
229
230        prs = self.stub.output[-1]
231       
232        self.failUnless(prs['type']=='unavailable', 'Unavailable is not being sent')
233       
234        response = prs
235        response['from'] = response['to']
236        response['to'] = 'test@jabber.org'
237
238        self.stub.send(response)
239        return d
240       
241
242    def test_userPartsRoom(self):
243        """An entity leaves the room, a presence of type unavailable is received by the client.
244        """
245
246        p = muc.UnavailableUserPresence()
247        p['to'] = self.user_jid.full()
248        p['from'] = self.room_jid.full()
249
250        # create a room
251        self._createRoom()
252        # add user to room
253        u = muc.User(self.room_jid.resource)
254
255        room = self.protocol._getRoom(self.room_jid)
256        room.addUser(u)
257
258        def userPresence(room, user):
259            self.failUnless(room.name==self.test_room, 'Wrong room name')
260            self.failUnless(room.inRoster(user)==False, 'User in roster')
261                           
262        d, self.protocol.userLeftRoom = calledAsync(userPresence)
263        self.stub.send(p)
264        return d
265       
266
267    def test_ban(self):
268        """Ban an entity in a room.
269        """
270        banned = JID('ban@jabber.org/TroubleMakger')
271        def cb(banned):
272            self.failUnless(banned, 'Did not ban user')
273
274           
275        d = self.protocol.ban(self.room_jid, banned, self.user_jid, reason='Spam')
276        d.addCallback(cb)
277
278        iq = self.stub.output[-1]
279       
280        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='outcast']" % (self.room_jid.userhost(),), iq), 'Wrong ban stanza')
281
282        response = toResponse(iq, 'result')
283
284        self.stub.send(response)
285
286        return d
287
288
289    def test_kick(self):
290        """Kick an entity from a room.
291        """
292        kicked = JID('kick@jabber.org/TroubleMakger')
293        def cb(kicked):
294            self.failUnless(kicked, 'Did not kick user')
295
296           
297        d = self.protocol.kick(self.room_jid, kicked, self.user_jid, reason='Spam')
298        d.addCallback(cb)
299
300        iq = self.stub.output[-1]
301       
302        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@affiliation='none']" % (self.room_jid.userhost(),), iq), 'Wrong kick stanza')
303
304        response = toResponse(iq, 'result')
305
306        self.stub.send(response)
307
308        return d
309
310       
311
312    def test_password(self):
313        """Sending a password via presence to a password protected room.
314        """
315       
316        self.protocol.password(self.room_jid, 'secret')
317       
318        prs = self.stub.output[-1]
319       
320        self.failUnless(xpath.matches("/presence[@to='%s']/x/password[text()='secret']" % (self.room_jid.full(),), prs), 'Wrong presence stanza')
321
322
323    def test_history(self):
324        """Receiving history on room join.
325        """
326        m = muc.HistoryMessage(self.room_jid.userhost(), self.protocol._makeTimeStamp(), body='test')
327        m['from'] = self.room_jid.full()
328       
329        self._createRoom()
330
331        def roomHistory(room, user, body, stamp, frm=None):
332            self.failUnless(body=='test', "wrong message body")
333            self.failUnless(stamp, 'Does not have a history stamp')
334                   
335
336        d, self.protocol.receivedHistory = calledAsync(roomHistory)
337        self.stub.send(m)
338        return d
339
340
341    def test_oneToOneChat(self):
342        """Converting a one to one chat to a multi-user chat.
343        """
344        archive = []
345        thread = "e0ffe42b28561960c6b12b944a092794b9683a38"
346        # create messages
347        msg = domish.Element((None, 'message'))
348        msg['to'] = 'testing@example.com'
349        msg['type'] = 'chat'
350        msg.addElement('body', None, 'test')
351        msg.addElement('thread', None, thread)
352
353        archive.append(msg)
354
355        msg = domish.Element((None, 'message'))
356        msg['to'] = 'testing2@example.com'
357        msg['type'] = 'chat'
358        msg.addElement('body', None, 'yo')
359        msg.addElement('thread', None, thread)
360
361        archive.append(msg)
362
363        self.protocol.history(self.room_jid.userhost(), archive)
364
365
366        while len(self.stub.output)>0:
367            m = self.stub.output.pop()
368            # check for delay element
369            self.failUnless(m.name=='message', 'Wrong stanza')
370            self.failUnless(xpath.matches("/message/delay", m), 'Invalid history stanza')
371       
372
373    def test_invite(self):
374        """Invite a user to a room
375        """
376        other_jid = 'test@jabber.org'
377
378        self.protocol.invite(other_jid, 'This is a test')
379
380        msg = self.stub.output[-1]
381
382        self.failUnless(xpath.matches("/message[@to='%s']/x/invite/reason" % (other_jid,), msg), 'Wrong message type')
383
384
385       
386    def test_privateMessage(self):
387        """Send private messages to muc entities.
388        """
389        other_nick = self.room_jid.userhost()+'/OtherNick'
390
391        self.protocol.chat(other_nick, 'This is a test')
392
393        msg = self.stub.output[-1]
394
395        self.failUnless(xpath.matches("/message[@type='chat' and @to='%s']/body" % (other_nick,), msg), 'Wrong message type')
396
397
398    def test_register(self):
399        """Client registering with a room. http://xmpp.org/extensions/xep-0045.html#register
400
401        """
402       
403        def cb(iq):
404            # check for a result
405            self.failUnless(iq['type']=='result', 'We did not get a result')
406       
407        d = self.protocol.register(self.room_jid.userhost())
408        d.addCallback(cb)
409
410        iq = self.stub.output[-1]
411        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']" % (muc.NS_REQUEST), iq), 'Invalid iq register request')
412       
413        response = toResponse(iq, 'result')
414       
415        self.stub.send(response)
416        return d
417
418    def test_voice(self):
419        """ Client requesting voice for a room.
420        """
421        self.protocol.voice(self.room_jid.userhost())
422
423        m = self.stub.output[-1]
424       
425        self.failUnless(xpath.matches("/message/x[@type='submit']/field/value[text()='%s']" % (muc.NS_MUC_REQUEST,), m), 'Invalid voice message stanza')
426
427
428    def test_roomConfigure(self):
429        """ Default configure and changing the room name.
430        """
431
432        def cb(iq):
433            self.failUnless(iq['type']=='result', 'Not a result')
434           
435
436        fields = []
437
438        fields.append(data_form.Field(label='Natural-Language Room Name',
439                                      var='muc#roomconfig_roomname',
440                                      value=self.test_room))
441       
442        d = self.protocol.configure(self.room_jid.userhost(), fields)
443        d.addCallback(cb)
444
445        iq = self.stub.output[-1]
446        self.failUnless(xpath.matches("/iq/query[@xmlns='%s']/x"% (muc.NS_MUC_OWNER,), iq), 'Bad configure request')
447       
448        response = toResponse(iq, 'result')
449        self.stub.send(response)
450        return d
451
452
453    def test_nickChange(self):
454        """Send a nick change to the server.
455        """
456        test_nick = 'newNick'
457       
458        self._createRoom()
459
460        def cb(room):
461            self.assertEquals(self.test_room, room.name)
462            self.assertEquals(test_nick, room.nick)
463
464        d = self.protocol.nick(self.room_jid, test_nick)
465        d.addCallback(cb)
466
467        prs = self.stub.output[-1]
468        self.failUnless(prs.name=='presence', "Need to be presence")
469        self.failUnless(getattr(prs, 'x', None), 'No muc x element')
470
471        # send back user presence, they joined       
472        response = muc.UserPresence(frm=self.test_room+'@'+self.test_srv+'/'+test_nick)
473       
474        self.stub.send(response)
475        return d
476
477    def test_grantVoice(self):
478        """Test granting voice to a user.
479
480        """
481        give_voice = JID('ban@jabber.org/TroubleMakger')
482        def cb(give_voice):
483            self.failUnless(give_voice, 'Did not give voice user')
484
485           
486        d = self.protocol.grantVoice(self.user_jid, self.room_jid, give_voice)
487        d.addCallback(cb)
488
489        iq = self.stub.output[-1]
490       
491        self.failUnless(xpath.matches("/iq[@type='set' and @to='%s']/query/item[@role='participant']" % (self.room_jid.userhost(),), iq), 'Wrong voice stanza')
492
493        response = toResponse(iq, 'result')
494
495        self.stub.send(response)
496
497        return d
498
499       
Note: See TracBrowser for help on using the repository browser.