source: wokkel/test/test_muc.py @ 148:75cf9e14b776

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

Redo room configuration.

  • The underlying request object now derives from generic.Request.
  • MUCClient.getConfiguration now returns a wokkel.data_form.Form.
  • MUCClient.configure now takes a simple dictionary of values.
File size: 27.0 KB
RevLine 
[143]1# Copyright (c) Ralph Meijer.
[107]2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.muc}
6"""
7
[141]8from datetime import datetime
9from dateutil.tz import tzutc
10
[107]11from zope.interface import verify
12
13from twisted.trial import unittest
[145]14from twisted.internet import defer, task
[107]15from twisted.words.xish import domish, xpath
16from twisted.words.protocols.jabber.jid import JID
[145]17from twisted.words.protocols.jabber.error import StanzaError
18from twisted.words.protocols.jabber.xmlstream import TimeoutError, toResponse
[107]19
[135]20from wokkel import data_form, iwokkel, muc
21from wokkel.generic import parseXml
[148]22from wokkel.test.helpers import TestableStreamManager
[107]23
24
[130]25NS_MUC_ADMIN = 'http://jabber.org/protocol/muc#admin'
[107]26
27def calledAsync(fn):
28    """
29    Function wrapper that fires a deferred upon calling the given function.
30    """
31    d = defer.Deferred()
32
33    def func(*args, **kwargs):
34        try:
35            result = fn(*args, **kwargs)
36        except:
37            d.errback()
38        else:
39            d.callback(result)
40
41    return d, func
42
[145]43
44
45class MUCClientTest(unittest.TestCase):
[107]46    timeout = 2
47
48    def setUp(self):
[145]49        self.clock = task.Clock()
[147]50        self.sessionManager = TestableStreamManager(reactor=self.clock)
51        self.stub = self.sessionManager.stub
[145]52        self.protocol = muc.MUCClient(reactor=self.clock)
[147]53        self.protocol.setHandlerParent(self.sessionManager)
54
[144]55        self.roomIdentifier = 'test'
56        self.service  = 'conference.example.org'
57        self.nick = 'Nick'
[107]58
[144]59        self.occupantJID = JID(tuple=(self.roomIdentifier,
60                                      self.service,
61                                      self.nick))
62        self.roomJID = self.occupantJID.userhostJID()
63        self.userJID = JID('test@example.org/Testing')
[112]64
[129]65
[113]66    def _createRoom(self):
[130]67        """
68        A helper method to create a test room.
[117]69        """
[113]70        # create a room
[144]71        room = muc.Room(self.roomIdentifier,
72                        self.service,
73                        self.nick)
74        self.protocol._addRoom(room)
[113]75
76
[107]77    def test_interface(self):
78        """
79        Do instances of L{muc.MUCClient} provide L{iwokkel.IMUCClient}?
80        """
81        verify.verifyObject(iwokkel.IMUCClient, self.protocol)
82
83
[113]84    def test_userJoinedRoom(self):
[130]85        """
[144]86        Joins by others to a room we're in are passed to userJoinedRoom
[109]87        """
[135]88        xml = """
89            <presence to='%s' from='%s'>
90              <x xmlns='http://jabber.org/protocol/muc#user'>
91                <item affiliation='member' role='participant'/>
92              </x>
93            </presence>
[144]94        """ % (self.userJID.full(), self.occupantJID.full())
[113]95
96        # create a room
97        self._createRoom()
98
[135]99        def userJoinedRoom(room, user):
[144]100            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
[135]101                              'Wrong room name')
[132]102            self.assertTrue(room.inRoster(user), 'User not in roster')
[129]103
[135]104        d, self.protocol.userJoinedRoom = calledAsync(userJoinedRoom)
105        self.stub.send(parseXml(xml))
[109]106        return d
107
108
[145]109    def test_receivedSubject(self):
110        """
111        Subject received from a room we're in are passed to receivedSubject.
112        """
113        xml = u"""
114            <message to='%s' from='%s' type='groupchat'>
115              <subject>test</subject>
116            </message>
117        """ % (self.userJID, self.occupantJID)
118
119        self._createRoom()
120
121        # add user to room
122        user = muc.User(self.nick)
123        room = self.protocol._getRoom(self.roomJID)
124        room.addUser(user)
125
126        def receivedSubject(room, user, subject):
127            self.assertEquals('test', subject, "Wrong group chat message")
128            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
129                              'Wrong room name')
130            self.assertEquals(self.nick, user.nick)
131
132        d, self.protocol.receivedSubject = calledAsync(receivedSubject)
133        self.stub.send(parseXml(xml))
134        return d
135
136
[144]137    def test_receivedGroupChat(self):
[130]138        """
[144]139        Messages received from a room we're in are passed to receivedGroupChat.
[109]140        """
[144]141        xml = u"""
[135]142            <message to='test@test.com' from='%s' type='groupchat'>
143              <body>test</body>
144            </message>
[144]145        """ % (self.occupantJID)
[113]146
147        self._createRoom()
148
[144]149        def receivedGroupChat(room, user, message):
[141]150            self.assertEquals('test', message.body, "Wrong group chat message")
[144]151            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
[135]152                              'Wrong room name')
[129]153
[144]154        d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
[135]155        self.stub.send(parseXml(xml))
[109]156        return d
157
[108]158
[144]159    def test_receivedGroupChatRoom(self):
[142]160        """
[144]161        Messages received from the room itself have C{user} set to C{None}.
[142]162        """
[144]163        xml = u"""
[142]164            <message to='test@test.com' from='%s' type='groupchat'>
165              <body>test</body>
166            </message>
[144]167        """ % (self.roomJID)
[142]168
169        self._createRoom()
170
[144]171        def receivedGroupChat(room, user, message):
172            self.assertIdentical(None, user)
[142]173
[144]174        d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
[142]175        self.stub.send(parseXml(xml))
176        return d
177
178
[145]179    def test_join(self):
[107]180        """
[144]181        Joining a room waits for confirmation, deferred fires room.
[107]182        """
[129]183
[107]184        def cb(room):
[144]185            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
[107]186
[144]187        d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
[107]188        d.addCallback(cb)
189
[145]190        element = self.stub.output[-1]
191        self.assertEquals('presence', element.name, "Need to be presence")
192        self.assertNotIdentical(None, element.x, 'No muc x element')
[108]193
[129]194        # send back user presence, they joined
[135]195        xml = """
196            <presence from='%s@%s/%s'>
197              <x xmlns='http://jabber.org/protocol/muc#user'>
198                <item affiliation='member' role='participant'/>
199              </x>
200            </presence>
[144]201        """ % (self.roomIdentifier, self.service, self.nick)
[135]202        self.stub.send(parseXml(xml))
[108]203        return d
204
205
[146]206    def test_joinHistory(self):
207        """
208        Passing a history parameter sends a 'maxstanzas' history limit.
209        """
210
211        def cb(room):
212            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
213
214        d = self.protocol.join(self.service, self.roomIdentifier, self.nick,
215                               history=10)
216        d.addCallback(cb)
217
218        element = self.stub.output[-1]
219        query = "/*/x[@xmlns='%s']/history[@xmlns='%s']" % (muc.NS_MUC,
220                                                            muc.NS_MUC)
221        result = xpath.queryForNodes(query, element)
222        history = result[0]
223        self.assertEquals('10', history.getAttribute('maxstanzas'))
224
225        # send back user presence, they joined
226        xml = """
227            <presence from='%s@%s/%s'>
228              <x xmlns='http://jabber.org/protocol/muc#user'>
229                <item affiliation='member' role='participant'/>
230              </x>
231            </presence>
232        """ % (self.roomIdentifier, self.service, self.nick)
233        self.stub.send(parseXml(xml))
234        return d
235
236
[145]237    def test_joinForbidden(self):
[130]238        """
[145]239        A forbidden error in response to a join errbacks with L{StanzaError}.
[108]240        """
241
242        def cb(error):
[145]243            self.assertEquals('forbidden', error.condition,
[135]244                              'Wrong muc condition')
[129]245
[144]246        d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
[145]247        self.assertFailure(d, StanzaError)
248        d.addCallback(cb)
[129]249
[135]250        # send back error, forbidden
[144]251        xml = u"""
[135]252            <presence from='%s' type='error'>
253              <error type='auth'>
254                <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
255              </error>
256            </presence>
[144]257        """ % (self.occupantJID)
[135]258        self.stub.send(parseXml(xml))
[129]259        return d
[109]260
[125]261
[145]262    def test_joinForbiddenFromRoomJID(self):
263        """
264        An error response to a join sent from the room JID should errback.
265
266        Some service implementations send error stanzas from the room JID
267        instead of the JID the join presence was sent to.
268        """
269
270        d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
271        self.assertFailure(d, StanzaError)
272
273        # send back error, forbidden
274        xml = u"""
275            <presence from='%s' type='error'>
276              <error type='auth'>
277                <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
278              </error>
279            </presence>
280        """ % (self.roomJID)
281        self.stub.send(parseXml(xml))
282        return d
283
284
285    def test_joinBadJID(self):
[130]286        """
[135]287        Client joining a room and getting a jid-malformed error.
[125]288        """
289
290        def cb(error):
[145]291            self.assertEquals('jid-malformed', error.condition,
[135]292                              'Wrong muc condition')
[129]293
[144]294        d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
[145]295        self.assertFailure(d, StanzaError)
296        d.addCallback(cb)
[129]297
[135]298        # send back error, bad JID
[144]299        xml = u"""
[135]300            <presence from='%s' type='error'>
301              <error type='modify'>
302                <jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
303              </error>
304            </presence>
[144]305        """ % (self.occupantJID)
[135]306        self.stub.send(parseXml(xml))
[129]307        return d
[125]308
309
[145]310    def test_joinTimeout(self):
311        """
312        After not receiving a response to a join, errback with L{TimeoutError}.
313        """
314
315        d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
316        self.assertFailure(d, TimeoutError)
317        self.clock.advance(muc.DEFER_TIMEOUT)
318        return d
319
320
321    def test_leave(self):
[130]322        """
323        Client leaves a room
[117]324        """
[112]325        def cb(left):
[135]326            self.assertTrue(left, 'did not leave room')
[112]327
[130]328        self._createRoom()
[145]329        d = self.protocol.leave(self.roomJID)
[112]330        d.addCallback(cb)
331
[145]332        element = self.stub.output[-1]
[129]333
[145]334        self.assertEquals('unavailable', element['type'],
[135]335                          'Unavailable is not being sent')
[129]336
[144]337        xml = u"""
338            <presence to='%s' from='%s' type='unavailable'/>
339        """ % (self.userJID, self.occupantJID)
[135]340        self.stub.send(parseXml(xml))
[112]341        return d
[129]342
[110]343
[145]344    def test_userLeftRoom(self):
[130]345        """
[145]346        Unavailable presence from a participant removes it from the room.
[118]347        """
348
[144]349        xml = u"""
[135]350            <presence to='%s' from='%s' type='unavailable'/>
[144]351        """ % (self.userJID, self.occupantJID)
[118]352
353        # create a room
354        self._createRoom()
[135]355
[118]356        # add user to room
[144]357        user = muc.User(self.nick)
[145]358        room = self.protocol._getRoom(self.roomJID)
[131]359        room.addUser(user)
[118]360
[145]361        def userLeftRoom(room, user):
[144]362            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
[135]363                              'Wrong room name')
364            self.assertFalse(room.inRoster(user), 'User in roster')
[129]365
[145]366        d, self.protocol.userLeftRoom = calledAsync(userLeftRoom)
[135]367        self.stub.send(parseXml(xml))
[118]368        return d
[129]369
[118]370
[110]371    def test_ban(self):
[130]372        """
373        Ban an entity in a room.
[117]374        """
[135]375        banned = JID('ban@jabber.org/TroubleMaker')
376
[112]377        def cb(banned):
[135]378            self.assertTrue(banned, 'Did not ban user')
[129]379
[144]380        d = self.protocol.ban(self.occupantJID, banned, reason='Spam',
381                              sender=self.userJID)
[112]382        d.addCallback(cb)
383
384        iq = self.stub.output[-1]
[129]385
[135]386        self.assertTrue(xpath.matches(
[144]387                u"/iq[@type='set' and @to='%s']/query/item"
388                    "[@affiliation='outcast']" % (self.roomJID,),
[135]389                iq),
390            'Wrong ban stanza')
[112]391
392        response = toResponse(iq, 'result')
393        self.stub.send(response)
394
395        return d
396
[110]397
398    def test_kick(self):
[130]399        """
400        Kick an entity from a room.
[117]401        """
[135]402        nick = 'TroubleMaker'
[131]403
[112]404        def cb(kicked):
[135]405            self.assertTrue(kicked, 'Did not kick user')
[112]406
[144]407        d = self.protocol.kick(self.occupantJID, nick, reason='Spam',
408                               sender=self.userJID)
[112]409        d.addCallback(cb)
410
411        iq = self.stub.output[-1]
[129]412
[135]413        self.assertTrue(xpath.matches(
[144]414                u"/iq[@type='set' and @to='%s']/query/item"
415                    "[@affiliation='none']" % (self.roomJID,),
[135]416                iq),
417            'Wrong kick stanza')
[112]418
419        response = toResponse(iq, 'result')
420        self.stub.send(response)
421
422        return d
423
[110]424
425    def test_password(self):
[130]426        """
427        Sending a password via presence to a password protected room.
[110]428        """
[129]429
[144]430        self.protocol.password(self.occupantJID, 'secret')
[129]431
[145]432        element = self.stub.output[-1]
[129]433
[135]434        self.assertTrue(xpath.matches(
[144]435                u"/presence[@to='%s']/x/password"
436                    "[text()='secret']" % (self.occupantJID,),
[145]437                element),
[135]438            'Wrong presence stanza')
[112]439
[110]440
[145]441    def test_receivedHistory(self):
[130]442        """
443        Receiving history on room join.
[112]444        """
[144]445        xml = u"""
[135]446            <message to='test@test.com' from='%s' type='groupchat'>
447              <body>test</body>
448              <delay xmlns='urn:xmpp:delay' stamp="2002-10-13T23:58:37Z"
449                                            from="%s"/>
450            </message>
[144]451        """ % (self.occupantJID, self.userJID)
[129]452
[113]453        self._createRoom()
454
[129]455
[145]456        def receivedHistory(room, user, message):
[141]457            self.assertEquals('test', message.body, "wrong message body")
458            stamp = datetime(2002, 10, 13, 23, 58, 37, tzinfo=tzutc())
459            self.assertEquals(stamp, message.delay.stamp,
460                             'Does not have a history stamp')
[112]461
[145]462        d, self.protocol.receivedHistory = calledAsync(receivedHistory)
[135]463        self.stub.send(parseXml(xml))
[112]464        return d
[110]465
466
467    def test_oneToOneChat(self):
[130]468        """
469        Converting a one to one chat to a multi-user chat.
[110]470        """
471        archive = []
472        thread = "e0ffe42b28561960c6b12b944a092794b9683a38"
473        # create messages
[145]474        element = domish.Element((None, 'message'))
475        element['to'] = 'testing@example.com'
476        element['type'] = 'chat'
477        element.addElement('body', None, 'test')
478        element.addElement('thread', None, thread)
[110]479
[145]480        archive.append({'stanza': element,
[141]481                        'timestamp': datetime(2002, 10, 13, 23, 58, 37,
482                                              tzinfo=tzutc())})
[110]483
[145]484        element = domish.Element((None, 'message'))
485        element['to'] = 'testing2@example.com'
486        element['type'] = 'chat'
487        element.addElement('body', None, 'yo')
488        element.addElement('thread', None, thread)
[110]489
[145]490        archive.append({'stanza': element,
[141]491                        'timestamp': datetime(2002, 10, 13, 23, 58, 43,
492                                              tzinfo=tzutc())})
[110]493
[144]494        self.protocol.history(self.occupantJID, archive)
[110]495
496
497        while len(self.stub.output)>0:
[145]498            element = self.stub.output.pop()
[110]499            # check for delay element
[145]500            self.assertEquals('message', element.name, 'Wrong stanza')
501            self.assertTrue(xpath.matches("/message/delay", element),
502                            'Invalid history stanza')
[129]503
[110]504
505    def test_invite(self):
[117]506        """
[130]507        Invite a user to a room
508        """
[144]509        invitee = JID('other@example.org')
[112]510
[144]511        self.protocol.invite(self.roomJID, invitee, u'This is a test')
[112]512
[144]513        message = self.stub.output[-1]
[112]514
[144]515        self.assertEquals('message', message.name)
516        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
517        self.assertEquals(muc.NS_MUC_USER, message.x.uri)
518        self.assertEquals(muc.NS_MUC_USER, message.x.invite.uri)
519        self.assertEquals(invitee.full(), message.x.invite.getAttribute('to'))
520        self.assertEquals(muc.NS_MUC_USER, message.x.invite.reason.uri)
521        self.assertEquals(u'This is a test', unicode(message.x.invite.reason))
[112]522
[110]523
[144]524    def test_groupChat(self):
[130]525        """
526        Send private messages to muc entities.
[112]527        """
[144]528        self.protocol.groupChat(self.roomJID, u'This is a test')
[112]529
[144]530        message = self.stub.output[-1]
[112]531
[144]532        self.assertEquals('message', message.name)
533        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
534        self.assertEquals('groupchat', message.getAttribute('type'))
535        self.assertEquals(u'This is a test', unicode(message.body))
[112]536
[144]537
538    def test_chat(self):
539        """
540        Send private messages to muc entities.
541        """
542        otherOccupantJID = JID(self.occupantJID.userhost()+'/OtherNick')
543
544        self.protocol.chat(otherOccupantJID, u'This is a test')
545
546        message = self.stub.output[-1]
547
548        self.assertEquals('message', message.name)
549        self.assertEquals(otherOccupantJID.full(), message.getAttribute('to'))
550        self.assertEquals('chat', message.getAttribute('type'))
551        self.assertEquals(u'This is a test', unicode(message.body))
[112]552
[110]553
554    def test_register(self):
[130]555        """
[135]556        Client registering with a room.
[111]557
[135]558        http://xmpp.org/extensions/xep-0045.html#register
[111]559        """
[129]560
[144]561        # FIXME: this doesn't really test the registration
562
[111]563        def cb(iq):
564            # check for a result
[136]565            self.assertEquals('result', iq['type'], 'We did not get a result')
[129]566
[144]567        d = self.protocol.register(self.roomJID)
[111]568        d.addCallback(cb)
569
570        iq = self.stub.output[-1]
[135]571        query = "/iq/query[@xmlns='%s']" % muc.NS_REQUEST
572        self.assertTrue(xpath.matches(query, iq), 'Invalid iq register request')
[129]573
[111]574        response = toResponse(iq, 'result')
575        self.stub.send(response)
576        return d
[110]577
[129]578
[110]579    def test_voice(self):
[130]580        """
581        Client requesting voice for a room.
[111]582        """
[144]583        self.protocol.voice(self.occupantJID)
[110]584
585        m = self.stub.output[-1]
[129]586
[135]587        query = ("/message/x[@type='submit']/field/value"
588                    "[text()='%s']") % muc.NS_MUC_REQUEST
589        self.assertTrue(xpath.matches(query, m), 'Invalid voice message stanza')
[110]590
591
[148]592    def test_configure(self):
[130]593        """
594        Default configure and changing the room name.
[111]595        """
[109]596
[111]597        def cb(iq):
[136]598            self.assertEquals('result', iq['type'], 'Not a result')
[129]599
[148]600        values = {'muc#roomconfig_roomname': self.roomIdentifier}
[111]601
[148]602        d = self.protocol.configure(self.roomJID, values)
[111]603        d.addCallback(cb)
[109]604
[111]605        iq = self.stub.output[-1]
[148]606
607        self.assertEquals('set', iq.getAttribute('type'))
608        self.assertEquals(self.roomJID.full(), iq.getAttribute('to'))
609
610        query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
611        nodes = xpath.queryForNodes(query, iq)
612        self.assertNotIdentical(None, nodes, 'Bad configure request')
613
614        form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
615        self.assertNotIdentical(None, form, 'Missing configuration form')
616        self.assertEquals('submit', form.formType)
[129]617
[111]618        response = toResponse(iq, 'result')
619        self.stub.send(response)
620        return d
621
622
[148]623    def test_configureCancel(self):
624        """
625        Cancelling room configuration should send a cancel form.
626        """
627
628        d = self.protocol.configure(self.roomJID, None)
629
630        iq = self.stub.output[-1]
631
632        query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
633        nodes = xpath.queryForNodes(query, iq)
634
635        form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
636        self.assertNotIdentical(None, form, 'Missing configuration form')
637        self.assertEquals('cancel', form.formType)
638
639        response = toResponse(iq, 'result')
640        self.stub.send(response)
641        return d
642
643
644    def test_getConfiguration(self):
645        """
646        The response of a configure form request should extract the form.
647        """
648
649        def cb(form):
650            self.assertEquals('form', form.formType)
651
652        d = self.protocol.getConfiguration(self.roomJID)
653        d.addCallback(cb)
654
655        iq = self.stub.output[-1]
656
657        query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
658        nodes = xpath.queryForNodes(query, iq)
659        self.assertNotIdentical(None, nodes, 'Missing query element')
660
661        self.assertRaises(StopIteration, nodes[0].elements().next)
662
663        xml = u"""
664            <iq from='%s' id='%s' to='%s' type='result'>
665              <query xmlns='http://jabber.org/protocol/muc#owner'>
666                <x xmlns='jabber:x:data' type='form'>
667                  <field type='hidden'
668                         var='FORM_TYPE'>
669                    <value>http://jabber.org/protocol/muc#roomconfig</value>
670                  </field>
671                  <field label='Natural-Language Room Name'
672                         type='text-single'
673                         var='muc#roomconfig_roomname'/>
674                </x>
675              </query>
676            </iq>
677        """ % (self.roomJID, iq['id'], self.userJID)
678        self.stub.send(parseXml(xml))
679
680        return d
681
682
683    def test_getConfigurationNoOptions(self):
684        """
685        The response of a configure form request should extract the form.
686        """
687
688        def cb(form):
689            self.assertIdentical(None, form)
690
691        d = self.protocol.getConfiguration(self.roomJID)
692        d.addCallback(cb)
693
694        iq = self.stub.output[-1]
695
696        xml = u"""
697            <iq from='%s' id='%s' to='%s' type='result'>
698              <query xmlns='http://jabber.org/protocol/muc#owner'/>
699            </iq>
700        """ % (self.roomJID, iq['id'], self.userJID)
701        self.stub.send(parseXml(xml))
702
703        return d
704
705
[144]706    def test_destroy(self):
[130]707        """
708        Destroy a room.
[127]709        """
[147]710        d = self.protocol.destroy(self.occupantJID, reason='Time to leave',
711                                  alternate=JID('other@%s' % self.service),
712                                  password='secret')
[127]713
714        iq = self.stub.output[-1]
[147]715
716        query = ("/iq/query[@xmlns='%s']/destroy[@xmlns='%s']" %
717                 (muc.NS_MUC_OWNER, muc.NS_MUC_OWNER))
718
719        nodes = xpath.queryForNodes(query, iq)
720        self.assertNotIdentical(None, nodes, 'Bad configure request')
721        destroy = nodes[0]
722        self.assertEquals('Time to leave', unicode(destroy.reason))
[129]723
[127]724        response = toResponse(iq, 'result')
725        self.stub.send(response)
726        return d
727
728
[144]729    def test_subject(self):
730        """
731        Change subject of the room.
732        """
733        self.protocol.subject(self.roomJID, u'This is a test')
734
735        message = self.stub.output[-1]
736
737        self.assertEquals('message', message.name)
738        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
739        self.assertEquals('groupchat', message.getAttribute('type'))
740        self.assertEquals(u'This is a test', unicode(message.subject))
741
742
[145]743    def test_nick(self):
[130]744        """
745        Send a nick change to the server.
[117]746        """
[145]747        newNick = 'newNick'
[129]748
[117]749        self._createRoom()
750
751        def cb(room):
[144]752            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
[145]753            self.assertEquals(newNick, room.nick)
[117]754
[145]755        d = self.protocol.nick(self.roomJID, newNick)
[117]756        d.addCallback(cb)
757
[145]758        element = self.stub.output[-1]
759        self.assertEquals('presence', element.name, "Need to be presence")
760        self.assertNotIdentical(None, element.x, 'No muc x element')
[117]761
[135]762        # send back user presence, nick changed
[145]763        xml = u"""
764            <presence from='%s/%s'>
[135]765              <x xmlns='http://jabber.org/protocol/muc#user'>
766                <item affiliation='member' role='participant'/>
767              </x>
768            </presence>
[145]769        """ % (self.roomJID, newNick)
770        self.stub.send(parseXml(xml))
771        return d
772
773
774    def test_nickConflict(self):
775        """
776        If the server finds the new nick in conflict, the errback is called.
777        """
778        newNick = 'newNick'
779
780        self._createRoom()
781
782        d = self.protocol.nick(self.roomJID, newNick)
783        self.assertFailure(d, StanzaError)
784
785        element = self.stub.output[-1]
786        self.assertEquals('presence', element.name, "Need to be presence")
787        self.assertNotIdentical(None, element.x, 'No muc x element')
788
789        # send back user presence, nick changed
790        xml = u"""
791            <presence from='%s/%s' type='error'>
792                <x xmlns='http://jabber.org/protocol/muc'/>
793                <error type='cancel'>
794                  <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
795                </error>
796            </presence>
797        """ % (self.roomJID, newNick)
[135]798        self.stub.send(parseXml(xml))
[117]799        return d
800
[129]801
[125]802    def test_grantVoice(self):
[130]803        """
804        Test granting voice to a user.
[125]805
806        """
[135]807        nick = 'TroubleMaker'
[125]808        def cb(give_voice):
[135]809            self.assertTrue(give_voice, 'Did not give voice user')
[129]810
[145]811        d = self.protocol.grantVoice(self.occupantJID, nick,
812                                     sender=self.userJID)
[125]813        d.addCallback(cb)
814
815        iq = self.stub.output[-1]
[129]816
[144]817        query = (u"/iq[@type='set' and @to='%s']/query/item"
818                     "[@role='participant']") % self.roomJID
[135]819        self.assertTrue(xpath.matches(query, iq), 'Wrong voice stanza')
[125]820
821        response = toResponse(iq, 'result')
822        self.stub.send(response)
823        return d
824
[126]825
[145]826    def test_status(self):
[130]827        """
828        Change status
[126]829        """
830        self._createRoom()
[145]831        room = self.protocol._getRoom(self.roomJID)
[144]832        user = muc.User(self.nick)
[131]833        room.addUser(user)
[126]834
835        def cb(room):
[144]836            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
837            user = room.getUser(self.nick)
[132]838            self.assertNotIdentical(None, user, 'User not found')
[136]839            self.assertEquals('testing MUC', user.status, 'Wrong status')
840            self.assertEquals('xa', user.show, 'Wrong show')
[129]841
[145]842        d = self.protocol.status(self.roomJID, 'xa', 'testing MUC')
[126]843        d.addCallback(cb)
844
[145]845        element = self.stub.output[-1]
[126]846
[145]847        self.assertEquals('presence', element.name, "Need to be presence")
848        self.assertTrue(getattr(element, 'x', None), 'No muc x element')
[126]849
[135]850        # send back user presence, status changed
[144]851        xml = u"""
[135]852            <presence from='%s'>
853              <x xmlns='http://jabber.org/protocol/muc#user'>
854                <item affiliation='member' role='participant'/>
855              </x>
856              <show>xa</show>
857              <status>testing MUC</status>
858            </presence>
[144]859        """ % self.occupantJID
[135]860        self.stub.send(parseXml(xml))
[129]861        return d
[130]862
863
864    def test_getMemberList(self):
865        def cb(room):
866            members = room.members
[136]867            self.assertEquals(1, len(members))
[130]868            user = members[0]
[136]869            self.assertEquals(JID(u'hag66@shakespeare.lit'), user.entity)
870            self.assertEquals(u'thirdwitch', user.nick)
871            self.assertEquals(u'participant', user.role)
[130]872
873        self._createRoom()
[144]874        d = self.protocol.getMemberList(self.roomJID)
[130]875        d.addCallback(cb)
876
877        iq = self.stub.output[-1]
878        query = iq.query
879        self.assertNotIdentical(None, query)
[136]880        self.assertEquals(NS_MUC_ADMIN, query.uri)
[130]881
882        response = toResponse(iq, 'result')
883        query = response.addElement((NS_MUC_ADMIN, 'query'))
884        item = query.addElement('item')
885        item['affiliation'] ='member'
886        item['jid'] = 'hag66@shakespeare.lit'
887        item['nick'] = 'thirdwitch'
888        item['role'] = 'participant'
889        self.stub.send(response)
890
891        return d
Note: See TracBrowser for help on using the repository browser.