Ignore:
Timestamp:
Aug 18, 2011, 3:22:45 PM (11 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
wokkel-muc-client-support-24
Message:

Split protocol and room/user administration into two classes.

This introduces MUCClientProtocol, which only contains the protocol
implementation. The only state keeping there is remembering the Occupant JID
that was used to join a room, so you can use the Room JID everywhere.

The room and user owner administration that was intertwined with the protocol
is still in MUCClient that is a subclass of MUCClientProtocol. As this
record keeping barely had proper tests, the test coverage for this class is
sub-optimal for now.

This also fixes various test cases for the pure protocol support.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wokkel/test/test_muc.py

    r151 r152  
    1818from twisted.words.protocols.jabber.xmlstream import TimeoutError, toResponse
    1919
    20 from wokkel import data_form, iwokkel, muc
     20from wokkel import data_form, delay, iwokkel, muc
    2121from wokkel.generic import parseXml
    2222from wokkel.test.helpers import TestableStreamManager
     
    4343
    4444
    45 class MUCClientTest(unittest.TestCase):
    46     timeout = 2
     45class GroupChatTest(unittest.TestCase):
     46    """
     47    Tests for {muc.GroupChat}.
     48    """
     49
     50
     51    def test_toElementDelay(self):
     52        """
     53        If the delay attribute is set, toElement has it rendered.
     54        """
     55        message = muc.GroupChat()
     56        message.delay = delay.Delay(stamp=datetime(2002, 10, 13, 23, 58, 37,
     57                                                   tzinfo=tzutc()))
     58
     59        element = message.toElement()
     60
     61        query = "/message/delay[@xmlns='%s']" % (delay.NS_DELAY,)
     62        nodes = xpath.queryForNodes(query, element)
     63        self.assertNotIdentical(None, nodes, "Missing delay element")
     64
     65
     66    def test_toElementDelayLegacy(self):
     67        """
     68        If legacy delay is requested, the legacy format is rendered.
     69        """
     70        message = muc.GroupChat()
     71        message.delay = delay.Delay(stamp=datetime(2002, 10, 13, 23, 58, 37,
     72                                                   tzinfo=tzutc()))
     73
     74        element = message.toElement(legacyDelay=True)
     75
     76        query = "/message/x[@xmlns='%s']" % (delay.NS_JABBER_DELAY,)
     77        nodes = xpath.queryForNodes(query, element)
     78        self.assertNotIdentical(None, nodes, "Missing legacy delay element")
     79
     80
     81
     82class HistoryOptionsTest(unittest.TestCase):
     83    """
     84    Tests for L{muc.HistoryOptionsTest}.
     85    """
     86
     87    def test_toElement(self):
     88        """
     89        toElement renders the history element in the right namespace.
     90        """
     91        history = muc.HistoryOptions()
     92
     93        element = history.toElement()
     94
     95        self.assertEqual(muc.NS_MUC, element.uri)
     96        self.assertEqual('history', element.name)
     97
     98
     99    def test_toElementMaxStanzas(self):
     100        """
     101        If C{maxStanzas} is set, the element has the attribute C{'maxstanzas'}.
     102        """
     103        history = muc.HistoryOptions(maxStanzas=10)
     104
     105        element = history.toElement()
     106
     107        self.assertEqual(u'10', element.getAttribute('maxstanzas'))
     108
     109
     110    def test_toElementSince(self):
     111        """
     112        If C{since} is set, the attribute C{'since'} has a rendered timestamp.
     113        """
     114        history = muc.HistoryOptions(since=datetime(2002, 10, 13, 23, 58, 37,
     115                                                   tzinfo=tzutc()))
     116
     117        element = history.toElement()
     118
     119        self.assertEqual(u'2002-10-13T23:58:37Z',
     120                         element.getAttribute('since'))
     121
     122
     123
     124class MUCClientProtocolTest(unittest.TestCase):
     125    """
     126    Tests for L{muc.MUCClientProtocol}.
     127    """
    47128
    48129    def setUp(self):
     
    50131        self.sessionManager = TestableStreamManager(reactor=self.clock)
    51132        self.stub = self.sessionManager.stub
    52         self.protocol = muc.MUCClient(reactor=self.clock)
     133        self.protocol = muc.MUCClientProtocol(reactor=self.clock)
    53134        self.protocol.setHandlerParent(self.sessionManager)
    54135
     
    64145
    65146
    66     def _createRoom(self):
    67         """
    68         A helper method to create a test room.
    69         """
    70         # create a room
    71         room = muc.Room(self.roomIdentifier,
    72                         self.service,
    73                         self.nick)
    74         self.protocol._addRoom(room)
    75 
    76 
    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 
    84     def test_userJoinedRoom(self):
    85         """
    86         Joins by others to a room we're in are passed to userJoinedRoom
    87         """
    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>
    94         """ % (self.userJID.full(), self.occupantJID.full())
    95 
    96         # create a room
    97         self._createRoom()
    98 
    99         def userJoinedRoom(room, user):
    100             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
    101                               'Wrong room name')
    102             self.assertTrue(room.inRoster(user), 'User not in roster')
    103 
    104         d, self.protocol.userJoinedRoom = calledAsync(userJoinedRoom)
    105         self.stub.send(parseXml(xml))
    106         return d
    107 
    108 
    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 
    137     def test_receivedGroupChat(self):
    138         """
    139         Messages received from a room we're in are passed to receivedGroupChat.
     147    def test_initNoReactor(self):
     148        """
     149        If no reactor is passed, the default reactor is used.
     150        """
     151        protocol = muc.MUCClientProtocol()
     152        from twisted.internet import reactor
     153        self.assertEqual(reactor, protocol._reactor)
     154
     155
     156    def test_groupChatReceived(self):
     157        """
     158        Messages of type groupchat are parsed and passed to L{groupChatReceived}.
    140159        """
    141160        xml = u"""
     
    145164        """ % (self.occupantJID)
    146165
    147         self._createRoom()
    148 
    149         def receivedGroupChat(room, user, message):
     166        def groupChatReceived(message):
    150167            self.assertEquals('test', message.body, "Wrong group chat message")
    151             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
    152                               'Wrong room name')
    153 
    154         d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
    155         self.stub.send(parseXml(xml))
    156         return d
    157 
    158 
    159     def test_receivedGroupChatRoom(self):
    160         """
    161         Messages received from the room itself have C{user} set to C{None}.
     168            self.assertEquals(self.roomIdentifier, message.sender.user,
     169                              'Wrong room identifier')
     170
     171        d, self.protocol.groupChatReceived = calledAsync(groupChatReceived)
     172        self.stub.send(parseXml(xml))
     173        return d
     174
     175
     176    def test_groupChatReceivedNotOverridden(self):
     177        """
     178        If L{groupChatReceived} has not been overridden, no errors should occur.
    162179        """
    163180        xml = u"""
     
    165182              <body>test</body>
    166183            </message>
    167         """ % (self.roomJID)
    168 
    169         self._createRoom()
    170 
    171         def receivedGroupChat(room, user, message):
    172             self.assertIdentical(None, user)
    173 
    174         d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
    175         self.stub.send(parseXml(xml))
    176         return d
     184        """ % (self.occupantJID)
     185
     186        self.stub.send(parseXml(xml))
    177187
    178188
    179189    def test_join(self):
    180190        """
    181         Joining a room waits for confirmation, deferred fires room.
    182         """
    183 
    184         def cb(room):
    185             self.assertEquals(self.roomIdentifier, room.roomIdentifier)
    186 
    187         d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
     191        Joining a room waits for confirmation, deferred fires user presence.
     192        """
     193
     194        def cb(presence):
     195            self.assertEquals(self.occupantJID, presence.sender)
     196
     197        # Join the room
     198        d = self.protocol.join(self.roomJID, self.nick)
    188199        d.addCallback(cb)
    189200
    190201        element = self.stub.output[-1]
     202
    191203        self.assertEquals('presence', element.name, "Need to be presence")
    192204        self.assertNotIdentical(None, element.x, 'No muc x element')
     
    206218    def test_joinHistory(self):
    207219        """
    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)
     220        Passing a history parameter sends a 'maxStanzas' history limit.
     221        """
     222
     223        historyOptions = muc.HistoryOptions(maxStanzas=10)
     224        d = self.protocol.join(self.roomJID, self.nick,
     225                               historyOptions)
    217226
    218227        element = self.stub.output[-1]
     
    244253                              'Wrong muc condition')
    245254
    246         d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
     255        d = self.protocol.join(self.roomJID, self.nick)
    247256        self.assertFailure(d, StanzaError)
    248257        d.addCallback(cb)
     
    268277        """
    269278
    270         d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
     279        d = self.protocol.join(self.roomJID, self.nick)
    271280        self.assertFailure(d, StanzaError)
    272281
     
    292301                              'Wrong muc condition')
    293302
    294         d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
     303        d = self.protocol.join(self.roomJID, self.nick)
    295304        self.assertFailure(d, StanzaError)
    296305        d.addCallback(cb)
     
    313322        """
    314323
    315         d = self.protocol.join(self.service, self.roomIdentifier, self.nick)
     324        d = self.protocol.join(self.roomJID, self.nick)
    316325        self.assertFailure(d, TimeoutError)
    317326        self.clock.advance(muc.DEFER_TIMEOUT)
     
    319328
    320329
    321     def test_leave(self):
    322         """
    323         Client leaves a room
    324         """
    325         def cb(left):
    326             self.assertTrue(left, 'did not leave room')
    327 
    328         self._createRoom()
    329         d = self.protocol.leave(self.roomJID)
    330         d.addCallback(cb)
    331 
    332         element = self.stub.output[-1]
    333 
    334         self.assertEquals('unavailable', element['type'],
    335                           'Unavailable is not being sent')
    336 
    337         xml = u"""
    338             <presence to='%s' from='%s' type='unavailable'/>
    339         """ % (self.userJID, self.occupantJID)
    340         self.stub.send(parseXml(xml))
    341         return d
    342 
    343 
    344     def test_userLeftRoom(self):
    345         """
    346         Unavailable presence from a participant removes it from the room.
    347         """
    348 
    349         xml = u"""
    350             <presence to='%s' from='%s' type='unavailable'/>
    351         """ % (self.userJID, self.occupantJID)
    352 
    353         # create a room
    354         self._createRoom()
    355 
    356         # add user to room
    357         user = muc.User(self.nick)
    358         room = self.protocol._getRoom(self.roomJID)
    359         room.addUser(user)
    360 
    361         def userLeftRoom(room, user):
    362             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
    363                               'Wrong room name')
    364             self.assertFalse(room.inRoster(user), 'User in roster')
    365 
    366         d, self.protocol.userLeftRoom = calledAsync(userLeftRoom)
    367         self.stub.send(parseXml(xml))
    368         return d
    369 
    370 
    371     def test_ban(self):
    372         """
    373         Ban an entity in a room.
    374         """
    375         banned = JID('ban@jabber.org/TroubleMaker')
    376 
    377         def cb(banned):
    378             self.assertTrue(banned, 'Did not ban user')
    379 
    380         d = self.protocol.ban(self.roomJID, banned, reason='Spam',
    381                               sender=self.userJID)
    382         d.addCallback(cb)
    383 
    384         iq = self.stub.output[-1]
    385 
    386         self.assertTrue(xpath.matches(
    387                 u"/iq[@type='set' and @to='%s']/query/item"
    388                     "[@affiliation='outcast']" % (self.roomJID,),
    389                 iq),
    390             'Wrong ban stanza')
    391 
    392         response = toResponse(iq, 'result')
    393         self.stub.send(response)
    394 
    395         return d
    396 
    397 
    398     def test_kick(self):
    399         """
    400         Kick an entity from a room.
    401         """
    402         nick = 'TroubleMaker'
    403 
    404         def cb(kicked):
    405             self.assertTrue(kicked, 'Did not kick user')
    406 
    407         d = self.protocol.kick(self.roomJID, nick, reason='Spam',
    408                                sender=self.userJID)
    409         d.addCallback(cb)
    410 
    411         iq = self.stub.output[-1]
    412 
    413         self.assertTrue(xpath.matches(
    414                 u"/iq[@type='set' and @to='%s']/query/item"
    415                     "[@role='none']" % (self.roomJID,),
    416                 iq),
    417             'Wrong kick stanza')
    418 
    419         response = toResponse(iq, 'result')
    420         self.stub.send(response)
    421 
    422         return d
    423 
    424 
    425     def test_password(self):
     330    def test_joinPassword(self):
    426331        """
    427332        Sending a password via presence to a password protected room.
    428333        """
    429334
    430         self.protocol.password(self.occupantJID, 'secret')
     335        self.protocol.join(self.roomJID, self.nick, password='secret')
    431336
    432337        element = self.stub.output[-1]
     
    439344
    440345
    441     def test_receivedHistory(self):
    442         """
    443         Receiving history on room join.
    444         """
    445         xml = u"""
    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>
    451         """ % (self.occupantJID, self.userJID)
    452 
    453         self._createRoom()
    454 
    455 
    456         def receivedHistory(room, user, message):
    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')
    461 
    462         d, self.protocol.receivedHistory = calledAsync(receivedHistory)
    463         self.stub.send(parseXml(xml))
    464         return d
    465 
    466 
    467     def test_oneToOneChat(self):
     346    def test_nick(self):
     347        """
     348        Send a nick change to the server.
     349        """
     350        newNick = 'newNick'
     351
     352        def cb(presence):
     353            self.assertEquals(JID(tuple=(self.roomIdentifier,
     354                                         self.service,
     355                                         newNick)),
     356                              presence.sender)
     357
     358        d = self.protocol.nick(self.roomJID, newNick)
     359        d.addCallback(cb)
     360
     361        element = self.stub.output[-1]
     362        self.assertEquals('presence', element.name, "Need to be presence")
     363        self.assertNotIdentical(None, element.x, 'No muc x element')
     364
     365        # send back user presence, nick changed
     366        xml = u"""
     367            <presence from='%s/%s'>
     368              <x xmlns='http://jabber.org/protocol/muc#user'>
     369                <item affiliation='member' role='participant'/>
     370              </x>
     371            </presence>
     372        """ % (self.roomJID, newNick)
     373        self.stub.send(parseXml(xml))
     374        return d
     375
     376
     377    def test_nickConflict(self):
     378        """
     379        If the server finds the new nick in conflict, the errback is called.
     380        """
     381        newNick = 'newNick'
     382
     383        d = self.protocol.nick(self.roomJID, newNick)
     384        self.assertFailure(d, StanzaError)
     385
     386        element = self.stub.output[-1]
     387        self.assertEquals('presence', element.name, "Need to be presence")
     388        self.assertNotIdentical(None, element.x, 'No muc x element')
     389
     390        # send back user presence, nick changed
     391        xml = u"""
     392            <presence from='%s/%s' type='error'>
     393                <x xmlns='http://jabber.org/protocol/muc'/>
     394                <error type='cancel'>
     395                  <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     396                </error>
     397            </presence>
     398        """ % (self.roomJID, newNick)
     399        self.stub.send(parseXml(xml))
     400        return d
     401
     402
     403    def test_status(self):
     404        """
     405        Change status
     406        """
     407        def joined(_):
     408            d = self.protocol.status(self.roomJID, 'xa', 'testing MUC')
     409            d.addCallback(statusChanged)
     410            return d
     411
     412        def statusChanged(presence):
     413            self.assertEqual(self.occupantJID, presence.sender)
     414
     415        # Join the room
     416        d = self.protocol.join(self.roomJID, self.nick)
     417        d.addCallback(joined)
     418
     419        # Receive presence back from the room: joined.
     420        xml = u"""
     421            <presence to='%s' from='%s'/>
     422        """ % (self.userJID, self.occupantJID)
     423        self.stub.send(parseXml(xml))
     424
     425        # The presence for the status change should have been sent now.
     426        element = self.stub.output[-1]
     427
     428        self.assertEquals('presence', element.name, "Need to be presence")
     429        self.assertTrue(getattr(element, 'x', None), 'No muc x element')
     430
     431        # send back user presence, status changed
     432        xml = u"""
     433            <presence from='%s'>
     434              <x xmlns='http://jabber.org/protocol/muc#user'>
     435                <item affiliation='member' role='participant'/>
     436              </x>
     437              <show>xa</show>
     438              <status>testing MUC</status>
     439            </presence>
     440        """ % self.occupantJID
     441        self.stub.send(parseXml(xml))
     442
     443        return d
     444
     445
     446    def test_leave(self):
     447        """
     448        Client leaves a room
     449        """
     450        def joined(_):
     451            return self.protocol.leave(self.roomJID)
     452
     453        # Join the room
     454        d = self.protocol.join(self.roomJID, self.nick)
     455        d.addCallback(joined)
     456
     457        # Receive presence back from the room: joined.
     458        xml = u"""
     459            <presence to='%s' from='%s'/>
     460        """ % (self.userJID, self.occupantJID)
     461        self.stub.send(parseXml(xml))
     462
     463        # The presence for leaving the room should have been sent now.
     464        element = self.stub.output[-1]
     465
     466        self.assertEquals('unavailable', element['type'],
     467                          'Unavailable is not being sent')
     468
     469        # Receive presence back from the room: left.
     470        xml = u"""
     471            <presence to='%s' from='%s' type='unavailable'/>
     472        """ % (self.userJID, self.occupantJID)
     473        self.stub.send(parseXml(xml))
     474
     475        return d
     476
     477
     478    def test_groupChat(self):
     479        """
     480        Send private messages to muc entities.
     481        """
     482        self.protocol.groupChat(self.roomJID, u'This is a test')
     483
     484        message = self.stub.output[-1]
     485
     486        self.assertEquals('message', message.name)
     487        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
     488        self.assertEquals('groupchat', message.getAttribute('type'))
     489        self.assertEquals(u'This is a test', unicode(message.body))
     490
     491
     492    def test_chat(self):
     493        """
     494        Send private messages to muc entities.
     495        """
     496        otherOccupantJID = JID(self.occupantJID.userhost()+'/OtherNick')
     497
     498        self.protocol.chat(otherOccupantJID, u'This is a test')
     499
     500        message = self.stub.output[-1]
     501
     502        self.assertEquals('message', message.name)
     503        self.assertEquals(otherOccupantJID.full(), message.getAttribute('to'))
     504        self.assertEquals('chat', message.getAttribute('type'))
     505        self.assertEquals(u'This is a test', unicode(message.body))
     506
     507
     508    def test_subject(self):
     509        """
     510        Change subject of the room.
     511        """
     512        self.protocol.subject(self.roomJID, u'This is a test')
     513
     514        message = self.stub.output[-1]
     515
     516        self.assertEquals('message', message.name)
     517        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
     518        self.assertEquals('groupchat', message.getAttribute('type'))
     519        self.assertEquals(u'This is a test', unicode(message.subject))
     520
     521
     522    def test_invite(self):
     523        """
     524        Invite a user to a room
     525        """
     526        invitee = JID('other@example.org')
     527
     528        self.protocol.invite(self.roomJID, invitee, u'This is a test')
     529
     530        message = self.stub.output[-1]
     531
     532        self.assertEquals('message', message.name)
     533        self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
     534        self.assertEquals(muc.NS_MUC_USER, message.x.uri)
     535        self.assertEquals(muc.NS_MUC_USER, message.x.invite.uri)
     536        self.assertEquals(invitee.full(), message.x.invite.getAttribute('to'))
     537        self.assertEquals(muc.NS_MUC_USER, message.x.invite.reason.uri)
     538        self.assertEquals(u'This is a test', unicode(message.x.invite.reason))
     539
     540
     541    def test_getRegisterForm(self):
     542        """
     543        The response of a register form request should extract the form.
     544        """
     545
     546        def cb(form):
     547            self.assertEquals('form', form.formType)
     548
     549        d = self.protocol.getRegisterForm(self.roomJID)
     550        d.addCallback(cb)
     551
     552        iq = self.stub.output[-1]
     553
     554        query = "/iq/query[@xmlns='%s']" % (muc.NS_REGISTER)
     555        nodes = xpath.queryForNodes(query, iq)
     556        self.assertNotIdentical(None, nodes, 'Missing query element')
     557
     558        self.assertRaises(StopIteration, nodes[0].elements().next)
     559
     560        xml = u"""
     561            <iq from='%s' id='%s' to='%s' type='result'>
     562              <query xmlns='jabber:iq:register'>
     563                <x xmlns='jabber:x:data' type='form'>
     564                  <field type='hidden'
     565                         var='FORM_TYPE'>
     566                    <value>http://jabber.org/protocol/muc#register</value>
     567                  </field>
     568                  <field label='Desired Nickname'
     569                         type='text-single'
     570                         var='muc#register_roomnick'>
     571                    <required/>
     572                  </field>
     573                </x>
     574              </query>
     575            </iq>
     576        """ % (self.roomJID, iq['id'], self.userJID)
     577        self.stub.send(parseXml(xml))
     578
     579        return d
     580
     581
     582    def test_register(self):
     583        """
     584        Client registering with a room.
     585
     586        http://xmpp.org/extensions/xep-0045.html#register
     587        """
     588
     589        def cb(iq):
     590            # check for a result
     591            self.assertEquals('result', iq['type'], 'We did not get a result')
     592
     593        d = self.protocol.register(self.roomJID,
     594                                   {'muc#register_roomnick': 'thirdwitch'})
     595        d.addCallback(cb)
     596
     597        iq = self.stub.output[-1]
     598
     599        query = "/iq/query[@xmlns='%s']" % muc.NS_REGISTER
     600        nodes = xpath.queryForNodes(query, iq)
     601        self.assertNotIdentical(None, nodes, 'Invalid registration request')
     602
     603        form = data_form.findForm(nodes[0], muc.NS_MUC_REGISTER)
     604        self.assertNotIdentical(None, form, 'Missing registration form')
     605        self.assertEquals('submit', form.formType)
     606        self.assertIn('muc#register_roomnick', form.fields)
     607
     608
     609        response = toResponse(iq, 'result')
     610        self.stub.send(response)
     611        return d
     612
     613
     614    def test_voice(self):
     615        """
     616        Client requesting voice for a room.
     617        """
     618        self.protocol.voice(self.occupantJID)
     619
     620        m = self.stub.output[-1]
     621
     622        query = ("/message/x[@type='submit']/field/value"
     623                    "[text()='%s']") % muc.NS_MUC_REQUEST
     624        self.assertTrue(xpath.matches(query, m), 'Invalid voice message stanza')
     625
     626
     627    def test_history(self):
    468628        """
    469629        Converting a one to one chat to a multi-user chat.
     
    501661            self.assertTrue(xpath.matches("/message/delay", element),
    502662                            'Invalid history stanza')
    503 
    504 
    505     def test_invite(self):
    506         """
    507         Invite a user to a room
    508         """
    509         invitee = JID('other@example.org')
    510 
    511         self.protocol.invite(self.roomJID, invitee, u'This is a test')
    512 
    513         message = self.stub.output[-1]
    514 
    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))
    522 
    523 
    524     def test_groupChat(self):
    525         """
    526         Send private messages to muc entities.
    527         """
    528         self.protocol.groupChat(self.roomJID, u'This is a test')
    529 
    530         message = self.stub.output[-1]
    531 
    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))
    536 
    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))
    552 
    553 
    554     def test_register(self):
    555         """
    556         Client registering with a room.
    557 
    558         http://xmpp.org/extensions/xep-0045.html#register
    559         """
    560 
    561         def cb(iq):
    562             # check for a result
    563             self.assertEquals('result', iq['type'], 'We did not get a result')
    564 
    565         d = self.protocol.register(self.roomJID,
    566                                    {'muc#register_roomnick': 'thirdwitch'})
    567         d.addCallback(cb)
    568 
    569         iq = self.stub.output[-1]
    570 
    571         query = "/iq/query[@xmlns='%s']" % muc.NS_REGISTER
    572         nodes = xpath.queryForNodes(query, iq)
    573         self.assertNotIdentical(None, nodes, 'Invalid registration request')
    574 
    575         form = data_form.findForm(nodes[0], muc.NS_MUC_REGISTER)
    576         self.assertNotIdentical(None, form, 'Missing registration form')
    577         self.assertEquals('submit', form.formType)
    578         self.assertIn('muc#register_roomnick', form.fields)
    579 
    580 
    581         response = toResponse(iq, 'result')
    582         self.stub.send(response)
    583         return d
    584 
    585 
    586     def test_voice(self):
    587         """
    588         Client requesting voice for a room.
    589         """
    590         self.protocol.voice(self.occupantJID)
    591 
    592         m = self.stub.output[-1]
    593 
    594         query = ("/message/x[@type='submit']/field/value"
    595                     "[text()='%s']") % muc.NS_MUC_REQUEST
    596         self.assertTrue(xpath.matches(query, m), 'Invalid voice message stanza')
    597 
    598 
    599     def test_configure(self):
    600         """
    601         Default configure and changing the room name.
    602         """
    603 
    604         def cb(iq):
    605             self.assertEquals('result', iq['type'], 'Not a result')
    606 
    607         values = {'muc#roomconfig_roomname': self.roomIdentifier}
    608 
    609         d = self.protocol.configure(self.roomJID, values)
    610         d.addCallback(cb)
    611 
    612         iq = self.stub.output[-1]
    613 
    614         self.assertEquals('set', iq.getAttribute('type'))
    615         self.assertEquals(self.roomJID.full(), iq.getAttribute('to'))
    616 
    617         query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
    618         nodes = xpath.queryForNodes(query, iq)
    619         self.assertNotIdentical(None, nodes, 'Bad configure request')
    620 
    621         form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
    622         self.assertNotIdentical(None, form, 'Missing configuration form')
    623         self.assertEquals('submit', form.formType)
    624 
    625         response = toResponse(iq, 'result')
    626         self.stub.send(response)
    627         return d
    628 
    629 
    630     def test_configureCancel(self):
    631         """
    632         Cancelling room configuration should send a cancel form.
    633         """
    634 
    635         d = self.protocol.configure(self.roomJID, None)
    636 
    637         iq = self.stub.output[-1]
    638 
    639         query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
    640         nodes = xpath.queryForNodes(query, iq)
    641 
    642         form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
    643         self.assertNotIdentical(None, form, 'Missing configuration form')
    644         self.assertEquals('cancel', form.formType)
    645 
    646         response = toResponse(iq, 'result')
    647         self.stub.send(response)
    648         return d
    649663
    650664
     
    711725
    712726
    713     def test_destroy(self):
    714         """
    715         Destroy a room.
    716         """
    717         d = self.protocol.destroy(self.occupantJID, reason='Time to leave',
    718                                   alternate=JID('other@%s' % self.service),
    719                                   password='secret')
    720 
    721         iq = self.stub.output[-1]
    722 
    723         query = ("/iq/query[@xmlns='%s']/destroy[@xmlns='%s']" %
    724                  (muc.NS_MUC_OWNER, muc.NS_MUC_OWNER))
    725 
     727    def test_configure(self):
     728        """
     729        Default configure and changing the room name.
     730        """
     731
     732        def cb(iq):
     733            self.assertEquals('result', iq['type'], 'Not a result')
     734
     735        values = {'muc#roomconfig_roomname': self.roomIdentifier}
     736
     737        d = self.protocol.configure(self.roomJID, values)
     738        d.addCallback(cb)
     739
     740        iq = self.stub.output[-1]
     741
     742        self.assertEquals('set', iq.getAttribute('type'))
     743        self.assertEquals(self.roomJID.full(), iq.getAttribute('to'))
     744
     745        query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
    726746        nodes = xpath.queryForNodes(query, iq)
    727747        self.assertNotIdentical(None, nodes, 'Bad configure request')
    728         destroy = nodes[0]
    729         self.assertEquals('Time to leave', unicode(destroy.reason))
    730 
    731         response = toResponse(iq, 'result')
    732         self.stub.send(response)
    733         return d
    734 
    735 
    736     def test_subject(self):
    737         """
    738         Change subject of the room.
    739         """
    740         self.protocol.subject(self.roomJID, u'This is a test')
    741 
    742         message = self.stub.output[-1]
    743 
    744         self.assertEquals('message', message.name)
    745         self.assertEquals(self.roomJID.full(), message.getAttribute('to'))
    746         self.assertEquals('groupchat', message.getAttribute('type'))
    747         self.assertEquals(u'This is a test', unicode(message.subject))
    748 
    749 
    750     def test_nick(self):
    751         """
    752         Send a nick change to the server.
    753         """
    754         newNick = 'newNick'
    755 
    756         self._createRoom()
    757 
    758         def cb(room):
    759             self.assertEquals(self.roomIdentifier, room.roomIdentifier)
    760             self.assertEquals(newNick, room.nick)
    761 
    762         d = self.protocol.nick(self.roomJID, newNick)
    763         d.addCallback(cb)
    764 
    765         element = self.stub.output[-1]
    766         self.assertEquals('presence', element.name, "Need to be presence")
    767         self.assertNotIdentical(None, element.x, 'No muc x element')
    768 
    769         # send back user presence, nick changed
    770         xml = u"""
    771             <presence from='%s/%s'>
    772               <x xmlns='http://jabber.org/protocol/muc#user'>
    773                 <item affiliation='member' role='participant'/>
    774               </x>
    775             </presence>
    776         """ % (self.roomJID, newNick)
    777         self.stub.send(parseXml(xml))
    778         return d
    779 
    780 
    781     def test_nickConflict(self):
    782         """
    783         If the server finds the new nick in conflict, the errback is called.
    784         """
    785         newNick = 'newNick'
    786 
    787         self._createRoom()
    788 
    789         d = self.protocol.nick(self.roomJID, newNick)
    790         self.assertFailure(d, StanzaError)
    791 
    792         element = self.stub.output[-1]
    793         self.assertEquals('presence', element.name, "Need to be presence")
    794         self.assertNotIdentical(None, element.x, 'No muc x element')
    795 
    796         # send back user presence, nick changed
    797         xml = u"""
    798             <presence from='%s/%s' type='error'>
    799                 <x xmlns='http://jabber.org/protocol/muc'/>
    800                 <error type='cancel'>
    801                   <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
    802                 </error>
    803             </presence>
    804         """ % (self.roomJID, newNick)
    805         self.stub.send(parseXml(xml))
     748
     749        form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
     750        self.assertNotIdentical(None, form, 'Missing configuration form')
     751        self.assertEquals('submit', form.formType)
     752
     753        response = toResponse(iq, 'result')
     754        self.stub.send(response)
     755        return d
     756
     757
     758    def test_configureCancel(self):
     759        """
     760        Cancelling room configuration should send a cancel form.
     761        """
     762
     763        d = self.protocol.configure(self.roomJID, None)
     764
     765        iq = self.stub.output[-1]
     766
     767        query = "/iq/query[@xmlns='%s']" % (muc.NS_MUC_OWNER)
     768        nodes = xpath.queryForNodes(query, iq)
     769
     770        form = data_form.findForm(nodes[0], muc.NS_MUC_CONFIG)
     771        self.assertNotIdentical(None, form, 'Missing configuration form')
     772        self.assertEquals('cancel', form.formType)
     773
     774        response = toResponse(iq, 'result')
     775        self.stub.send(response)
     776        return d
     777
     778
     779    def test_getMemberList(self):
     780        """
     781        Retrieving the member list returns a list of L{muc.AdminItem}s
     782
     783        The request asks for the affiliation C{'member'}.
     784        """
     785        def cb(items):
     786            self.assertEquals(1, len(items))
     787            item = items[0]
     788            self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
     789            self.assertEquals(u'thirdwitch', item.nick)
     790            self.assertEquals(u'member', item.affiliation)
     791
     792        d = self.protocol.getMemberList(self.roomJID)
     793        d.addCallback(cb)
     794
     795        iq = self.stub.output[-1]
     796        self.assertEquals('get', iq.getAttribute('type'))
     797        query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
     798                                                              muc.NS_MUC_ADMIN)
     799        items = xpath.queryForNodes(query, iq)
     800        self.assertNotIdentical(None, items)
     801        self.assertEquals(1, len(items))
     802        self.assertEquals('member', items[0].getAttribute('affiliation'))
     803
     804        response = toResponse(iq, 'result')
     805        query = response.addElement((NS_MUC_ADMIN, 'query'))
     806        item = query.addElement('item')
     807        item['affiliation'] ='member'
     808        item['jid'] = 'hag66@shakespeare.lit'
     809        item['nick'] = 'thirdwitch'
     810        item['role'] = 'participant'
     811        self.stub.send(response)
     812
     813        return d
     814
     815
     816    def test_getAdminList(self):
     817        """
     818        Retrieving the admin list returns a list of L{muc.AdminItem}s
     819
     820        The request asks for the affiliation C{'admin'}.
     821        """
     822        d = self.protocol.getAdminList(self.roomJID)
     823
     824        iq = self.stub.output[-1]
     825        query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
     826                                                              muc.NS_MUC_ADMIN)
     827        items = xpath.queryForNodes(query, iq)
     828        self.assertEquals('admin', items[0].getAttribute('affiliation'))
     829
     830        response = toResponse(iq, 'result')
     831        query = response.addElement((NS_MUC_ADMIN, 'query'))
     832        self.stub.send(response)
     833
     834        return d
     835
     836
     837    def test_getBanList(self):
     838        """
     839        Retrieving the ban list returns a list of L{muc.AdminItem}s
     840
     841        The request asks for the affiliation C{'outcast'}.
     842        """
     843        def cb(items):
     844            self.assertEquals(1, len(items))
     845            item = items[0]
     846            self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
     847            self.assertEquals(u'outcast', item.affiliation)
     848            self.assertEquals(u'Trouble making', item.reason)
     849
     850        d = self.protocol.getBanList(self.roomJID)
     851        d.addCallback(cb)
     852
     853        iq = self.stub.output[-1]
     854        query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
     855                                                              muc.NS_MUC_ADMIN)
     856        items = xpath.queryForNodes(query, iq)
     857        self.assertEquals('outcast', items[0].getAttribute('affiliation'))
     858
     859        response = toResponse(iq, 'result')
     860        query = response.addElement((NS_MUC_ADMIN, 'query'))
     861        item = query.addElement('item')
     862        item['affiliation'] ='outcast'
     863        item['jid'] = 'hag66@shakespeare.lit'
     864        item.addElement('reason', content='Trouble making')
     865        self.stub.send(response)
     866
     867        return d
     868
     869
     870    def test_getOwnerList(self):
     871        """
     872        Retrieving the owner list returns a list of L{muc.AdminItem}s
     873
     874        The request asks for the affiliation C{'owner'}.
     875        """
     876        d = self.protocol.getOwnerList(self.roomJID)
     877
     878        iq = self.stub.output[-1]
     879        query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
     880                                                              muc.NS_MUC_ADMIN)
     881        items = xpath.queryForNodes(query, iq)
     882        self.assertEquals('owner', items[0].getAttribute('affiliation'))
     883
     884        response = toResponse(iq, 'result')
     885        query = response.addElement((NS_MUC_ADMIN, 'query'))
     886        self.stub.send(response)
     887
     888        return d
     889
     890
     891    def test_getModeratorList(self):
     892        """
     893        Retrieving the moderator returns a list of L{muc.AdminItem}s.
     894
     895        The request asks for the role C{'moderator'}.
     896        """
     897
     898        def cb(items):
     899            self.assertEquals(1, len(items))
     900            item = items[0]
     901            self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
     902            self.assertEquals(u'thirdwitch', item.nick)
     903            self.assertEquals(u'moderator', item.role)
     904
     905        d = self.protocol.getModeratorList(self.roomJID)
     906        d.addCallback(cb)
     907
     908        iq = self.stub.output[-1]
     909        self.assertEquals('get', iq.getAttribute('type'))
     910        query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
     911                                                              muc.NS_MUC_ADMIN)
     912        items = xpath.queryForNodes(query, iq)
     913        self.assertNotIdentical(None, items)
     914        self.assertEquals(1, len(items))
     915        self.assertEquals('moderator', items[0].getAttribute('role'))
     916
     917        response = toResponse(iq, 'result')
     918        query = response.addElement((NS_MUC_ADMIN, 'query'))
     919        item = query.addElement('item')
     920        item['affiliation'] ='member'
     921        item['jid'] = 'hag66@shakespeare.lit'
     922        item['nick'] = 'thirdwitch'
     923        item['role'] = 'moderator'
     924        self.stub.send(response)
     925
    806926        return d
    807927
     
    8941014
    8951015
     1016    def test_ban(self):
     1017        """
     1018        Ban an entity in a room.
     1019        """
     1020        banned = JID('ban@jabber.org/TroubleMaker')
     1021
     1022        def cb(banned):
     1023            self.assertTrue(banned, 'Did not ban user')
     1024
     1025        d = self.protocol.ban(self.roomJID, banned, reason='Spam',
     1026                              sender=self.userJID)
     1027        d.addCallback(cb)
     1028
     1029        iq = self.stub.output[-1]
     1030
     1031        self.assertTrue(xpath.matches(
     1032                u"/iq[@type='set' and @to='%s']/query/item"
     1033                    "[@affiliation='outcast']" % (self.roomJID,),
     1034                iq),
     1035            'Wrong ban stanza')
     1036
     1037        response = toResponse(iq, 'result')
     1038        self.stub.send(response)
     1039
     1040        return d
     1041
     1042
     1043    def test_kick(self):
     1044        """
     1045        Kick an entity from a room.
     1046        """
     1047        nick = 'TroubleMaker'
     1048
     1049        def cb(kicked):
     1050            self.assertTrue(kicked, 'Did not kick user')
     1051
     1052        d = self.protocol.kick(self.roomJID, nick, reason='Spam',
     1053                               sender=self.userJID)
     1054        d.addCallback(cb)
     1055
     1056        iq = self.stub.output[-1]
     1057
     1058        self.assertTrue(xpath.matches(
     1059                u"/iq[@type='set' and @to='%s']/query/item"
     1060                    "[@role='none']" % (self.roomJID,),
     1061                iq),
     1062            'Wrong kick stanza')
     1063
     1064        response = toResponse(iq, 'result')
     1065        self.stub.send(response)
     1066
     1067        return d
     1068
     1069
     1070    def test_destroy(self):
     1071        """
     1072        Destroy a room.
     1073        """
     1074        d = self.protocol.destroy(self.occupantJID, reason='Time to leave',
     1075                                  alternate=JID('other@%s' % self.service),
     1076                                  password='secret')
     1077
     1078        iq = self.stub.output[-1]
     1079
     1080        query = ("/iq/query[@xmlns='%s']/destroy[@xmlns='%s']" %
     1081                 (muc.NS_MUC_OWNER, muc.NS_MUC_OWNER))
     1082
     1083        nodes = xpath.queryForNodes(query, iq)
     1084        self.assertNotIdentical(None, nodes, 'Bad configure request')
     1085        destroy = nodes[0]
     1086        self.assertEquals('Time to leave', unicode(destroy.reason))
     1087
     1088        response = toResponse(iq, 'result')
     1089        self.stub.send(response)
     1090        return d
     1091
     1092
     1093
     1094class MUCClientTest(unittest.TestCase):
     1095    """
     1096    Tests for C{muc.MUCClient}.
     1097    """
     1098
     1099    def setUp(self):
     1100        self.clock = task.Clock()
     1101        self.sessionManager = TestableStreamManager(reactor=self.clock)
     1102        self.stub = self.sessionManager.stub
     1103        self.protocol = muc.MUCClient(reactor=self.clock)
     1104        self.protocol.setHandlerParent(self.sessionManager)
     1105
     1106        self.roomIdentifier = 'test'
     1107        self.service  = 'conference.example.org'
     1108        self.nick = 'Nick'
     1109
     1110        self.occupantJID = JID(tuple=(self.roomIdentifier,
     1111                                      self.service,
     1112                                      self.nick))
     1113        self.roomJID = self.occupantJID.userhostJID()
     1114        self.userJID = JID('test@example.org/Testing')
     1115
     1116
     1117    def _createRoom(self):
     1118        """
     1119        A helper method to create a test room.
     1120        """
     1121        # create a room
     1122        room = muc.Room(self.roomIdentifier,
     1123                        self.service,
     1124                        self.nick)
     1125        self.protocol._addRoom(room)
     1126
     1127
     1128    def test_interface(self):
     1129        """
     1130        Do instances of L{muc.MUCClient} provide L{iwokkel.IMUCClient}?
     1131        """
     1132        verify.verifyObject(iwokkel.IMUCClient, self.protocol)
     1133
     1134
     1135    def test_userJoinedRoom(self):
     1136        """
     1137        Joins by others to a room we're in are passed to userJoinedRoom
     1138        """
     1139        xml = """
     1140            <presence to='%s' from='%s'>
     1141              <x xmlns='http://jabber.org/protocol/muc#user'>
     1142                <item affiliation='member' role='participant'/>
     1143              </x>
     1144            </presence>
     1145        """ % (self.userJID.full(), self.occupantJID.full())
     1146
     1147        # create a room
     1148        self._createRoom()
     1149
     1150        def userJoinedRoom(room, user):
     1151            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1152                              'Wrong room name')
     1153            self.assertTrue(room.inRoster(user), 'User not in roster')
     1154
     1155        d, self.protocol.userJoinedRoom = calledAsync(userJoinedRoom)
     1156        self.stub.send(parseXml(xml))
     1157        return d
     1158
     1159
     1160    def test_receivedSubject(self):
     1161        """
     1162        Subject received from a room we're in are passed to receivedSubject.
     1163        """
     1164        xml = u"""
     1165            <message to='%s' from='%s' type='groupchat'>
     1166              <subject>test</subject>
     1167            </message>
     1168        """ % (self.userJID, self.occupantJID)
     1169
     1170        self._createRoom()
     1171
     1172        # add user to room
     1173        user = muc.User(self.nick)
     1174        room = self.protocol._getRoom(self.roomJID)
     1175        room.addUser(user)
     1176
     1177        def receivedSubject(room, user, subject):
     1178            self.assertEquals('test', subject, "Wrong group chat message")
     1179            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1180                              'Wrong room name')
     1181            self.assertEquals(self.nick, user.nick)
     1182
     1183        d, self.protocol.receivedSubject = calledAsync(receivedSubject)
     1184        self.stub.send(parseXml(xml))
     1185        return d
     1186
     1187
     1188    def test_receivedGroupChat(self):
     1189        """
     1190        Messages received from a room we're in are passed to receivedGroupChat.
     1191        """
     1192        xml = u"""
     1193            <message to='test@test.com' from='%s' type='groupchat'>
     1194              <body>test</body>
     1195            </message>
     1196        """ % (self.occupantJID)
     1197
     1198        self._createRoom()
     1199
     1200        def receivedGroupChat(room, user, message):
     1201            self.assertEquals('test', message.body, "Wrong group chat message")
     1202            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1203                              'Wrong room name')
     1204
     1205        d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
     1206        self.stub.send(parseXml(xml))
     1207        return d
     1208
     1209
     1210    def test_receivedGroupChatRoom(self):
     1211        """
     1212        Messages received from the room itself have C{user} set to C{None}.
     1213        """
     1214        xml = u"""
     1215            <message to='test@test.com' from='%s' type='groupchat'>
     1216              <body>test</body>
     1217            </message>
     1218        """ % (self.roomJID)
     1219
     1220        self._createRoom()
     1221
     1222        def receivedGroupChat(room, user, message):
     1223            self.assertIdentical(None, user)
     1224
     1225        d, self.protocol.receivedGroupChat = calledAsync(receivedGroupChat)
     1226        self.stub.send(parseXml(xml))
     1227        return d
     1228
     1229
     1230    def test_join(self):
     1231        """
     1232        Joining a room waits for confirmation, deferred fires room.
     1233        """
     1234
     1235        def cb(room):
     1236            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
     1237
     1238        d = self.protocol.join(self.roomJID, self.nick)
     1239        d.addCallback(cb)
     1240
     1241        # send back user presence, they joined
     1242        xml = """
     1243            <presence from='%s@%s/%s'>
     1244              <x xmlns='http://jabber.org/protocol/muc#user'>
     1245                <item affiliation='member' role='participant'/>
     1246              </x>
     1247            </presence>
     1248        """ % (self.roomIdentifier, self.service, self.nick)
     1249        self.stub.send(parseXml(xml))
     1250        return d
     1251
     1252
     1253    def test_userLeftRoom(self):
     1254        """
     1255        Unavailable presence from a participant removes it from the room.
     1256        """
     1257
     1258        xml = u"""
     1259            <presence to='%s' from='%s' type='unavailable'/>
     1260        """ % (self.userJID, self.occupantJID)
     1261
     1262        # create a room
     1263        self._createRoom()
     1264
     1265        # add user to room
     1266        user = muc.User(self.nick)
     1267        room = self.protocol._getRoom(self.roomJID)
     1268        room.addUser(user)
     1269
     1270        def userLeftRoom(room, user):
     1271            self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1272                              'Wrong room name')
     1273            self.assertFalse(room.inRoster(user), 'User in roster')
     1274
     1275        d, self.protocol.userLeftRoom = calledAsync(userLeftRoom)
     1276        self.stub.send(parseXml(xml))
     1277        return d
     1278
     1279
     1280    def test_receivedHistory(self):
     1281        """
     1282        Receiving history on room join.
     1283        """
     1284        xml = u"""
     1285            <message to='test@test.com' from='%s' type='groupchat'>
     1286              <body>test</body>
     1287              <delay xmlns='urn:xmpp:delay' stamp="2002-10-13T23:58:37Z"
     1288                                            from="%s"/>
     1289            </message>
     1290        """ % (self.occupantJID, self.userJID)
     1291
     1292        self._createRoom()
     1293
     1294
     1295        def receivedHistory(room, user, message):
     1296            self.assertEquals('test', message.body, "wrong message body")
     1297            stamp = datetime(2002, 10, 13, 23, 58, 37, tzinfo=tzutc())
     1298            self.assertEquals(stamp, message.delay.stamp,
     1299                             'Does not have a history stamp')
     1300
     1301        d, self.protocol.receivedHistory = calledAsync(receivedHistory)
     1302        self.stub.send(parseXml(xml))
     1303        return d
     1304
     1305
     1306    def test_nick(self):
     1307        """
     1308        Send a nick change to the server.
     1309        """
     1310        newNick = 'newNick'
     1311
     1312        self._createRoom()
     1313
     1314        def cb(room):
     1315            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
     1316            self.assertEquals(newNick, room.nick)
     1317
     1318        d = self.protocol.nick(self.roomJID, newNick)
     1319        d.addCallback(cb)
     1320
     1321        # send back user presence, nick changed
     1322        xml = u"""
     1323            <presence from='%s/%s'>
     1324              <x xmlns='http://jabber.org/protocol/muc#user'>
     1325                <item affiliation='member' role='participant'/>
     1326              </x>
     1327            </presence>
     1328        """ % (self.roomJID, newNick)
     1329        self.stub.send(parseXml(xml))
     1330        return d
     1331
     1332
    8961333    def test_status(self):
    8971334        """
    8981335        Change status
    8991336        """
    900         self._createRoom()
    901         room = self.protocol._getRoom(self.roomJID)
    902         user = muc.User(self.nick)
    903         room.addUser(user)
    904 
    905         def cb(room):
     1337        def joined(_):
     1338            d = self.protocol.status(self.roomJID, 'xa', 'testing MUC')
     1339            d.addCallback(statusChanged)
     1340            return d
     1341
     1342        def statusChanged(room):
    9061343            self.assertEquals(self.roomIdentifier, room.roomIdentifier)
    9071344            user = room.getUser(self.nick)
     
    9101347            self.assertEquals('xa', user.show, 'Wrong show')
    9111348
    912         d = self.protocol.status(self.roomJID, 'xa', 'testing MUC')
    913         d.addCallback(cb)
    914 
    915         element = self.stub.output[-1]
    916 
    917         self.assertEquals('presence', element.name, "Need to be presence")
    918         self.assertTrue(getattr(element, 'x', None), 'No muc x element')
     1349        # Join the room
     1350        d = self.protocol.join(self.roomJID, self.nick)
     1351        d.addCallback(joined)
     1352
     1353        # Receive presence back from the room: joined.
     1354        xml = u"""
     1355            <presence to='%s' from='%s'/>
     1356        """ % (self.userJID, self.occupantJID)
     1357        self.stub.send(parseXml(xml))
    9191358
    9201359        # send back user presence, status changed
     
    9291368        """ % self.occupantJID
    9301369        self.stub.send(parseXml(xml))
    931         return d
    932 
    933 
    934     def test_getMemberList(self):
    935         """
    936         Retrieving the member list returns a list of L{muc.AdminItem}s
    937 
    938         The request asks for the affiliation C{'member'}.
    939         """
    940         def cb(items):
    941             self.assertEquals(1, len(items))
    942             item = items[0]
    943             self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
    944             self.assertEquals(u'thirdwitch', item.nick)
    945             self.assertEquals(u'member', item.affiliation)
    946 
    947         d = self.protocol.getMemberList(self.roomJID)
    948         d.addCallback(cb)
    949 
    950         iq = self.stub.output[-1]
    951         self.assertEquals('get', iq.getAttribute('type'))
    952         query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
    953                                                               muc.NS_MUC_ADMIN)
    954         items = xpath.queryForNodes(query, iq)
    955         self.assertNotIdentical(None, items)
    956         self.assertEquals(1, len(items))
    957         self.assertEquals('member', items[0].getAttribute('affiliation'))
    958 
    959         response = toResponse(iq, 'result')
    960         query = response.addElement((NS_MUC_ADMIN, 'query'))
    961         item = query.addElement('item')
    962         item['affiliation'] ='member'
    963         item['jid'] = 'hag66@shakespeare.lit'
    964         item['nick'] = 'thirdwitch'
    965         item['role'] = 'participant'
    966         self.stub.send(response)
    967 
    968         return d
    969 
    970 
    971     def test_getAdminList(self):
    972         """
    973         Retrieving the admin list returns a list of L{muc.AdminItem}s
    974 
    975         The request asks for the affiliation C{'admin'}.
    976         """
    977         d = self.protocol.getAdminList(self.roomJID)
    978 
    979         iq = self.stub.output[-1]
    980         query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
    981                                                               muc.NS_MUC_ADMIN)
    982         items = xpath.queryForNodes(query, iq)
    983         self.assertEquals('admin', items[0].getAttribute('affiliation'))
    984 
    985         response = toResponse(iq, 'result')
    986         query = response.addElement((NS_MUC_ADMIN, 'query'))
    987         self.stub.send(response)
    988 
    989         return d
    990 
    991 
    992     def test_getBanList(self):
    993         """
    994         Retrieving the ban list returns a list of L{muc.AdminItem}s
    995 
    996         The request asks for the affiliation C{'outcast'}.
    997         """
    998         def cb(items):
    999             self.assertEquals(1, len(items))
    1000             item = items[0]
    1001             self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
    1002             self.assertEquals(u'outcast', item.affiliation)
    1003             self.assertEquals(u'Trouble making', item.reason)
    1004 
    1005         d = self.protocol.getBanList(self.roomJID)
    1006         d.addCallback(cb)
    1007 
    1008         iq = self.stub.output[-1]
    1009         query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
    1010                                                               muc.NS_MUC_ADMIN)
    1011         items = xpath.queryForNodes(query, iq)
    1012         self.assertEquals('outcast', items[0].getAttribute('affiliation'))
    1013 
    1014         response = toResponse(iq, 'result')
    1015         query = response.addElement((NS_MUC_ADMIN, 'query'))
    1016         item = query.addElement('item')
    1017         item['affiliation'] ='outcast'
    1018         item['jid'] = 'hag66@shakespeare.lit'
    1019         item.addElement('reason', content='Trouble making')
    1020         self.stub.send(response)
    1021 
    1022         return d
    1023 
    1024 
    1025     def test_getOwnerList(self):
    1026         """
    1027         Retrieving the owner list returns a list of L{muc.AdminItem}s
    1028 
    1029         The request asks for the affiliation C{'owner'}.
    1030         """
    1031         d = self.protocol.getOwnerList(self.roomJID)
    1032 
    1033         iq = self.stub.output[-1]
    1034         query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
    1035                                                               muc.NS_MUC_ADMIN)
    1036         items = xpath.queryForNodes(query, iq)
    1037         self.assertEquals('owner', items[0].getAttribute('affiliation'))
    1038 
    1039         response = toResponse(iq, 'result')
    1040         query = response.addElement((NS_MUC_ADMIN, 'query'))
    1041         self.stub.send(response)
    1042 
    1043         return d
    1044 
    1045 
    1046     def test_getModeratorList(self):
    1047         """
    1048         Retrieving the moderator returns a list of L{muc.AdminItem}s.
    1049 
    1050         The request asks for the role C{'moderator'}.
    1051         """
    1052 
    1053         def cb(items):
    1054             self.assertEquals(1, len(items))
    1055             item = items[0]
    1056             self.assertEquals(JID(u'hag66@shakespeare.lit'), item.entity)
    1057             self.assertEquals(u'thirdwitch', item.nick)
    1058             self.assertEquals(u'moderator', item.role)
    1059 
    1060         d = self.protocol.getModeratorList(self.roomJID)
    1061         d.addCallback(cb)
    1062 
    1063         iq = self.stub.output[-1]
    1064         self.assertEquals('get', iq.getAttribute('type'))
    1065         query = "/iq/query[@xmlns='%s']/item[@xmlns='%s']" % (muc.NS_MUC_ADMIN,
    1066                                                               muc.NS_MUC_ADMIN)
    1067         items = xpath.queryForNodes(query, iq)
    1068         self.assertNotIdentical(None, items)
    1069         self.assertEquals(1, len(items))
    1070         self.assertEquals('moderator', items[0].getAttribute('role'))
    1071 
    1072         response = toResponse(iq, 'result')
    1073         query = response.addElement((NS_MUC_ADMIN, 'query'))
    1074         item = query.addElement('item')
    1075         item['affiliation'] ='member'
    1076         item['jid'] = 'hag66@shakespeare.lit'
    1077         item['nick'] = 'thirdwitch'
    1078         item['role'] = 'moderator'
    1079         self.stub.send(response)
    1080 
    1081         return d
     1370
     1371        return d
Note: See TracChangeset for help on using the changeset viewer.