Changeset 153:bf4b940f3547 for wokkel


Ignore:
Timestamp:
Sep 2, 2011, 9:56:49 AM (9 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
wokkel-muc-client-support-24
Message:

Improve UserPresence? parsing, clean up MUCClient, approach full test coverage.

  • Parse muc#user item elements from incoming presence.
  • Properly interpret status codes in muc#user extension; there can be more than one and they should be used as integers.
  • Give observers of responses to joins, leaves and nick changes a lower priority than the general presence observers inherited from PresenceProtocol?. This ensures that the Room/User? administration in MUCClient is processed before the deferred for these actions fire.
  • Use roomJID to create Room instances, instead of the separate roomIdentifier and server arguments. Also store this roomJID on the Room.
  • Change prototype for receivedSubject to include user argument.
  • Make several callback functions nested functions within the methods that use them, instead of method on the class itself.
Location:
wokkel
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • wokkel/iwokkel.py

    r152 r153  
    779779    """
    780780
    781     def receivedSubject(room, subject):
     781    def receivedSubject(room, user, subject):
    782782        """
    783783        A subject is received when you join a room and when the subject is changed. This
     
    786786        @param room: The room the subject was accepted for.
    787787        @type room: L{muc.Room}
     788
     789        @param user: The user that set the subject.
     790        @type  user: L{muc.User}
    788791
    789792        @param subject: The subject of the given room.
  • wokkel/muc.py

    r152 r153  
    356356    """
    357357
    358     statusCode = None
     358    affiliation = None
     359    role = None
     360    entity = None
     361    nick = None
     362
     363    statusCodes = None
    359364
    360365    childParsers = {(NS_MUC_USER, 'x'): '_childParser_mucUser'}
    361366
    362367    def _childParser_mucUser(self, element):
     368        statusCodes = set()
     369
    363370        for child in element.elements():
    364371            if child.uri != NS_MUC_USER:
    365372                continue
     373
    366374            elif child.name == 'status':
    367                 self.statusCode = child.getAttribute('code')
    368             # TODO: item, destroy
    369 
     375                try:
     376                    statusCode = int(child.getAttribute('code'))
     377                except (TypeError, ValueError):
     378                    continue
     379
     380                statusCodes.add(statusCode)
     381
     382            elif child.name == 'item':
     383                if child.hasAttribute('jid'):
     384                    self.entity = jid.JID(child['jid'])
     385
     386                self.nick = child.getAttribute('nick')
     387                self.affiliation = child.getAttribute('affiliation')
     388                self.role = child.getAttribute('role')
     389
     390                for reason in child.elements(NS_MUC_ADMIN, 'reason'):
     391                    self.reason = unicode(reason)
     392
     393            # TODO: destroy
     394
     395        if statusCodes:
     396            self.statusCodes = statusCodes
    370397
    371398
     
    496523        query = "/presence[@from='%s' or (@from='%s' and @type='error')]" % (
    497524                stanza.recipient.full(), stanza.recipient.userhost())
    498         self.xmlstream.addOnetimeObserver(query, onResponse, priority=1)
     525        self.xmlstream.addOnetimeObserver(query, onResponse, priority=-1)
    499526        self.xmlstream.send(stanza.toElement())
    500527        return d
     
    10411068    a client.
    10421069
    1043     @ivar roomIdentifier: The Room ID of the MUC room.
    1044     @type roomIdentifier: C{unicode}
    1045 
    1046     @ivar service: The server where the MUC room is located.
    1047     @type service: C{unicode}
     1070    @ivar roomJID: The Room JID of the MUC room.
     1071    @type roomJID: L{JID}
    10481072
    10491073    @ivar nick: The nick name for the client in this room.
     
    10541078
    10551079    @ivar occupantJID: The JID of the occupant in the room. Generated from
    1056         roomIdentifier, service, and nick.
     1080        roomJID and nick.
    10571081    @type occupantJID: L{jid.JID}
    10581082    """
    10591083
    10601084
    1061     def __init__(self, roomIdentifier, service, nick, state=None):
     1085    def __init__(self, roomJID, nick, state=None):
    10621086        """
    10631087        Initialize the room.
    10641088        """
    1065         self.roomIdentifier = roomIdentifier
    1066         self.service = service
     1089        self.roomJID = roomJID
    10671090        self.setNick(nick)
    10681091        self.state = state
     
    10741097
    10751098    def setNick(self, nick):
    1076         self.occupantJID = jid.internJID(u"%s@%s/%s" % (self.roomIdentifier,
    1077                                                         self.service,
    1078                                                         nick))
     1099        self.occupantJID = jid.internJID(u"%s/%s" % (self.roomJID, nick))
    10791100        self.nick = nick
    10801101
     
    11681189
    11691190
    1170     def _removeRoom(self, occupantJID):
     1191    def _removeRoom(self, roomJID):
    11711192        """
    11721193        Delete a room from the room collection.
    11731194        """
    1174         roomJID = occupantJID.userhostJID()
    11751195        if roomJID in self._rooms:
    11761196            del self._rooms[roomJID]
    11771197
    11781198
    1179     def unavailableReceived(self, presence):
    1180         """
    1181         Unavailable presence was received.
    1182 
    1183         If this was received from a MUC room occupant JID, that occupant has
    1184         left the room.
    1185         """
    1186 
    1187         occupantJID = presence.sender
    1188 
    1189         if occupantJID:
    1190             self._userLeavesRoom(occupantJID)
    1191 
    1192 
    1193     def errorReceived(self, presence):
    1194         """
    1195         Error presence was received.
    1196 
    1197         If this was received from a MUC room occupant JID, we conclude the
    1198         occupant has left the room.
    1199         """
    1200         occupantJID = presence.sender
    1201 
    1202         if occupantJID:
    1203             self._userLeavesRoom(occupantJID)
    1204 
    1205 
    1206     def _userLeavesRoom(self, occupantJID):
     1199    def _getRoomUser(self, stanza):
     1200        """
     1201        Lookup the room and user associated with the stanza's sender.
     1202        """
     1203        occupantJID = stanza.sender
     1204
     1205        if not occupantJID:
     1206            return None, None
     1207
    12071208        # when a user leaves a room we need to update it
    12081209        room = self._getRoom(occupantJID.userhostJID())
    12091210        if room is None:
    12101211            # not in the room yet
     1212            return None, None
     1213
     1214        # Check if user is in roster
     1215        nick = occupantJID.resource
     1216        user = room.getUser(nick)
     1217
     1218        return room, user
     1219
     1220
     1221    def unavailableReceived(self, presence):
     1222        """
     1223        Unavailable presence was received.
     1224
     1225        If this was received from a MUC room occupant JID, that occupant has
     1226        left the room.
     1227        """
     1228
     1229        room, user = self._getRoomUser(presence)
     1230
     1231        if room is None or user is None:
    12111232            return
    1212         # check if user is in roster
    1213         user = room.getUser(occupantJID.resource)
     1233
     1234        room.removeUser(user)
     1235        self.userLeftRoom(room, user)
     1236
     1237
     1238    def availableReceived(self, presence):
     1239        """
     1240        Available presence was received.
     1241        """
     1242
     1243        room, user = self._getRoomUser(presence)
     1244
     1245        if room is None:
     1246            return
     1247
    12141248        if user is None:
    1215             return
     1249            nick = presence.sender.resource
     1250            user = User(nick, presence.entity)
     1251
     1252        # Update user status
     1253        user.status = presence.status
     1254        user.show = presence.show
     1255
    12161256        if room.inRoster(user):
    1217             room.removeUser(user)
    1218             self.userLeftRoom(room, user)
    1219 
    1220 
    1221     def availableReceived(self, presence):
    1222         """
    1223         Available presence was received.
    1224         """
    1225 
    1226         occupantJID = presence.sender
    1227 
    1228         if not occupantJID:
    1229             return
    1230 
    1231         # grab room
    1232         room = self._getRoom(occupantJID.userhostJID())
    1233         if room is None:
    1234             # not in the room yet
    1235             return
    1236 
    1237         user = self._changeUserStatus(room, occupantJID, presence.status,
    1238                                       presence.show)
    1239 
    1240         if room.inRoster(user):
    1241             # we changed status or nick
    1242             if presence.statusCode:
    1243                 room.status = presence.statusCode # XXX
    1244             else:
    1245                 self.userUpdatedStatus(room, user, presence.show,
    1246                                        presence.status)
     1257            self.userUpdatedStatus(room, user, presence.show, presence.status)
    12471258        else:
    12481259            room.addUser(user)
     
    12571268        L{receivedGroupChat}, L{receivedHistory} or L{receivedHistory}.
    12581269        """
    1259         occupantJID = message.sender
    1260         if not occupantJID:
     1270        room, user = self._getRoomUser(message)
     1271
     1272        if room is None:
    12611273            return
    1262 
    1263         roomJID = occupantJID.userhostJID()
    1264 
    1265         room = self._getRoom(roomJID)
    1266         if room is None:
    1267             # not in the room yet
    1268             return
    1269 
    1270         if occupantJID.resource:
    1271             user = room.getUser(occupantJID.resource)
    1272         else:
    1273             # This message is from the room itself.
    1274             user = None
    12751274
    12761275        if message.subject:
     
    12821281
    12831282
    1284     def _joinedRoom(self, presence):
    1285         """
    1286         We have presence that says we joined a room.
    1287         """
    1288         roomJID = presence.sender.userhostJID()
    1289 
    1290         # change the state of the room
    1291         room = self._getRoom(roomJID)
    1292         room.state = 'joined'
    1293 
    1294         # grab status
    1295         if presence.statusCode:
    1296             room.status = presence.statusCode
    1297 
    1298         return room
    1299 
    1300 
    1301     def _leftRoom(self, presence):
    1302         """
    1303         We have presence that says we left a room.
    1304         """
    1305         occupantJID = presence.sender
    1306 
    1307         # change the state of the room
    1308         self._removeRoom(occupantJID)
    1309 
    1310         return True
    1311 
    1312 
    13131283    def userJoinedRoom(self, room, user):
    13141284        """
     
    13531323
    13541324
    1355     def receivedSubject(self, room, subject):
    1356         """
     1325    def receivedSubject(self, room, user, subject):
     1326        """
     1327        A (new) room subject has been received.
     1328
    13571329        This method will need to be modified inorder for clients to
    13581330        do something when this event occurs.
     
    14011373    def join(self, roomJID, nick, historyOptions=None,
    14021374                   password=None):
    1403         room = Room(roomJID.user, roomJID.host, nick, state='joining')
     1375        """
     1376        Join a MUC room by sending presence to it.
     1377
     1378        @param roomJID: The JID of the room the entity is joining.
     1379        @type roomJID: L{jid.JID}
     1380
     1381        @param nick: The nick name for the entitity joining the room.
     1382        @type nick: C{unicode}
     1383
     1384        @param historyOptions: Options for conversation history sent by the
     1385            room upon joining.
     1386        @type historyOptions: L{HistoryOptions}
     1387
     1388        @param password: Optional password for the room.
     1389        @type password: C{unicode}
     1390
     1391        @return: A deferred that fires with the room when the entity is in the
     1392            room, or with a failure if an error has occurred.
     1393        """
     1394        def cb(presence):
     1395            """
     1396            We have presence that says we joined a room.
     1397            """
     1398            room.state = 'joined'
     1399            return room
     1400
     1401        def eb(failure):
     1402            self._removeRoom(roomJID)
     1403            return failure
     1404
     1405        room = Room(roomJID, nick, state='joining')
    14041406        self._addRoom(room)
    14051407
    14061408        d = MUCClientProtocol.join(self, roomJID, nick, historyOptions,
    14071409                                         password)
    1408         d.addCallback(self._joinedRoom)
     1410        d.addCallbacks(cb, eb)
    14091411        return d
    1410 
    1411 
    1412     def _changeUserStatus(self, room, occupantJID, status, show):
    1413         """
    1414         Change the user status in a room.
    1415         """
    1416 
    1417         # check if user is in roster
    1418         user = room.getUser(occupantJID.resource)
    1419         if user is None: # create a user that does not exist
    1420             user = User(occupantJID.resource)
    1421 
    1422         if status is not None:
    1423             user.status = unicode(status)
    1424         if show is not None:
    1425             user.show = unicode(show)
    1426 
    1427         return user
    1428 
    1429 
    1430     def _changed(self, presence, occupantJID):
    1431         """
    1432         Callback for changing the nick and status.
    1433         """
    1434         room = self._getRoom(occupantJID.userhostJID())
    1435         self._changeUserStatus(room, occupantJID, presence.status, presence.show)
    1436 
    1437         return room
    14381412
    14391413
     
    14501424        @type nick: C{unicode}
    14511425        """
     1426        def cb(presence):
     1427            # Presence confirmation, change the nickname.
     1428            room.setNick(nick)
     1429            return room
     1430
    14521431        room = self._getRoom(roomJID)
    14531432
    1454         # Change the nickname
    1455         room.setNick(nick)
    1456 
    14571433        d = MUCClientProtocol.nick(self, roomJID, nick)
    1458         d.addCallback(self._changed, room.occupantJID)
     1434        d.addCallback(cb)
    14591435        return d
    14601436
     
    14691445        @type roomJID: L{jid.JID}
    14701446        """
     1447        def cb(presence):
     1448            self._removeRoom(roomJID)
     1449
    14711450        d = MUCClientProtocol.leave(self, roomJID)
    1472         d.addCallback(self._leftRoom)
     1451        d.addCallback(cb)
    14731452        return d
    14741453
     
    14921471        room = self._getRoom(roomJID)
    14931472        d = MUCClientProtocol.status(self, roomJID, show, status)
    1494         d.addCallback(self._changed, room.occupantJID)
     1473        d.addCallback(lambda _: room)
    14951474        return d
    14961475
  • wokkel/test/test_muc.py

    r152 r153  
    121121
    122122
     123class UserPresenceTest(unittest.TestCase):
     124    """
     125    Tests for L{muc.UserPresence}.
     126    """
     127
     128
     129    def test_toElementUnknownChild(self):
     130        """
     131        Unknown child elements are ignored.
     132        """
     133        xml = """
     134            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     135                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     136                      to='hag66@shakespeare.lit/pda'>
     137              <x xmlns='http://jabber.org/protocol/muc#user'>
     138                <child xmlns='myns'/>
     139              </x>
     140            </presence>
     141        """
     142
     143        element = parseXml(xml)
     144        presence = muc.UserPresence.fromElement(element)
     145
     146
     147    def test_toElementStatusOne(self):
     148        """
     149        Status codes are extracted.
     150        """
     151        xml = """
     152            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     153                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     154                      to='hag66@shakespeare.lit/pda'>
     155              <x xmlns='http://jabber.org/protocol/muc#user'>
     156                <item affiliation='member' role='participant'/>
     157                <status code='110'/>
     158              </x>
     159            </presence>
     160        """
     161
     162        element = parseXml(xml)
     163        presence = muc.UserPresence.fromElement(element)
     164
     165        self.assertIn(110, presence.statusCodes)
     166
     167
     168    def test_toElementStatusMultiple(self):
     169        """
     170        Multiple status codes are all extracted.
     171        """
     172        xml = """
     173            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     174                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     175                      to='hag66@shakespeare.lit/pda'>
     176              <x xmlns='http://jabber.org/protocol/muc#user'>
     177                <item affiliation='member' role='participant'/>
     178                <status code='100'/>
     179                <status code='110'/>
     180              </x>
     181            </presence>
     182        """
     183
     184        element = parseXml(xml)
     185        presence = muc.UserPresence.fromElement(element)
     186
     187        self.assertIn(110, presence.statusCodes)
     188        self.assertIn(100, presence.statusCodes)
     189
     190
     191    def test_toElementStatusEmpty(self):
     192        """
     193        Empty status elements are ignored.
     194        """
     195        xml = """
     196            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     197                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     198                      to='hag66@shakespeare.lit/pda'>
     199              <x xmlns='http://jabber.org/protocol/muc#user'>
     200                <item affiliation='member' role='participant'/>
     201                <status/>
     202              </x>
     203            </presence>
     204        """
     205
     206        element = parseXml(xml)
     207        presence = muc.UserPresence.fromElement(element)
     208
     209        self.assertIdentical(None, presence.statusCodes)
     210
     211
     212    def test_toElementStatusBad(self):
     213        """
     214        Bad status codes are ignored.
     215        """
     216        xml = """
     217            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     218                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     219                      to='hag66@shakespeare.lit/pda'>
     220              <x xmlns='http://jabber.org/protocol/muc#user'>
     221                <item affiliation='member' role='participant'/>
     222                <status code="badvalue"/>
     223              </x>
     224            </presence>
     225        """
     226
     227        element = parseXml(xml)
     228        presence = muc.UserPresence.fromElement(element)
     229
     230        self.assertIdentical(None, presence.statusCodes)
     231
     232
     233    def test_toElementStatusUnknown(self):
     234        """
     235        Unknown status codes are still recorded in C{statusCodes}.
     236        """
     237        xml = """
     238            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     239                      id='026B3509-2CCE-4D69-96D6-25F41FFDC408'
     240                      to='hag66@shakespeare.lit/pda'>
     241              <x xmlns='http://jabber.org/protocol/muc#user'>
     242                <item affiliation='member' role='participant'/>
     243                <status code="999"/>
     244              </x>
     245            </presence>
     246        """
     247
     248        element = parseXml(xml)
     249        presence = muc.UserPresence.fromElement(element)
     250
     251        self.assertIn(999, presence.statusCodes)
     252
     253
     254    def test_toElementItem(self):
     255        """
     256        Item attributes are parsed properly.
     257        """
     258        xml = """
     259            <presence from='coven@chat.shakespeare.lit/thirdwitch'
     260                      to='crone1@shakespeare.lit/desktop'>
     261              <x xmlns='http://jabber.org/protocol/muc#user'>
     262                <item affiliation='member'
     263                      jid='hag66@shakespeare.lit/pda'
     264                      role='participant'
     265                      nick='thirdwitch'/>
     266              </x>
     267            </presence>
     268        """
     269
     270        element = parseXml(xml)
     271        presence = muc.UserPresence.fromElement(element)
     272        self.assertEqual(u'member', presence.affiliation)
     273        self.assertEqual(u'participant', presence.role)
     274        self.assertEqual(JID('hag66@shakespeare.lit/pda'), presence.entity)
     275        self.assertEqual(u'thirdwitch', presence.nick)
     276
     277
    123278
    124279class MUCClientProtocolTest(unittest.TestCase):
     
    388543        self.assertNotIdentical(None, element.x, 'No muc x element')
    389544
    390         # send back user presence, nick changed
     545        # send back error presence, nick conflicted
    391546        xml = u"""
    392547            <presence from='%s/%s' type='error'>
     
    11201275        """
    11211276        # create a room
    1122         room = muc.Room(self.roomIdentifier,
    1123                         self.service,
    1124                         self.nick)
     1277        room = muc.Room(self.roomJID, self.nick)
    11251278        self.protocol._addRoom(room)
     1279        return room
    11261280
    11271281
     
    11311285        """
    11321286        verify.verifyObject(iwokkel.IMUCClient, self.protocol)
     1287
     1288
     1289    def _testPresence(self, sender='', available=True):
     1290        """
     1291        Helper for presence tests.
     1292        """
     1293        def userUpdatedStatus(room, user, show, status):
     1294            self.fail("Unexpected call to userUpdatedStatus")
     1295
     1296        def userJoinedRoom(room, user):
     1297            self.fail("Unexpected call to userJoinedRoom")
     1298
     1299        if available:
     1300            available = ""
     1301        else:
     1302            available = " type='unavailable'"
     1303
     1304        if sender:
     1305            sender = u" from='%s'" % sender
     1306
     1307        xml = u"""
     1308            <presence to='%s'%s%s>
     1309              <x xmlns='http://jabber.org/protocol/muc#user'>
     1310                <item affiliation='member' role='participant'/>
     1311              </x>
     1312            </presence>
     1313        """ % (self.userJID, sender, available)
     1314
     1315        self.protocol.userUpdatedStatus = userUpdatedStatus
     1316        self.protocol.userJoinedRoom = userJoinedRoom
     1317        self.stub.send(parseXml(xml))
     1318
     1319
     1320    def test_availableReceivedEmptySender(self):
     1321        """
     1322        Availability presence from empty sender is ignored.
     1323        """
     1324        self._testPresence(sender='')
     1325
     1326
     1327    def test_availableReceivedNotInRoom(self):
     1328        """
     1329        Availability presence from unknown entities is ignored.
     1330        """
     1331        otherOccupantJID = JID(self.occupantJID.userhost()+'/OtherNick')
     1332        self._testPresence(sender=otherOccupantJID)
     1333
     1334
     1335    def test_unavailableReceivedEmptySender(self):
     1336        """
     1337        Availability presence from empty sender is ignored.
     1338        """
     1339        self._testPresence(sender='', available=False)
     1340
     1341
     1342    def test_unavailableReceivedNotInRoom(self):
     1343        """
     1344        Availability presence from unknown entities is ignored.
     1345        """
     1346        otherOccupantJID = JID(self.occupantJID.userhost()+'/OtherNick')
     1347        self._testPresence(sender=otherOccupantJID, available=False)
     1348
     1349
     1350    def test_unavailableReceivedNotInRoster(self):
     1351        """
     1352        Availability presence from unknown entities is ignored.
     1353        """
     1354        room = self._createRoom()
     1355        user = muc.User(self.nick)
     1356        room.addUser(user)
     1357        otherOccupantJID = JID(self.occupantJID.userhost()+'/OtherNick')
     1358        self._testPresence(sender=otherOccupantJID, available=False)
    11331359
    11341360
     
    11491375
    11501376        def userJoinedRoom(room, user):
    1151             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1377            self.assertEquals(self.roomJID, room.roomJID,
    11521378                              'Wrong room name')
    11531379            self.assertTrue(room.inRoster(user), 'User not in roster')
     
    11771403        def receivedSubject(room, user, subject):
    11781404            self.assertEquals('test', subject, "Wrong group chat message")
    1179             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1405            self.assertEquals(self.roomJID, room.roomJID,
    11801406                              'Wrong room name')
    11811407            self.assertEquals(self.nick, user.nick)
     
    11841410        self.stub.send(parseXml(xml))
    11851411        return d
     1412
     1413
     1414    def test_receivedSubjectNotOverridden(self):
     1415        """
     1416        Not overriding receivedSubject is ok.
     1417        """
     1418        xml = u"""
     1419            <message to='%s' from='%s' type='groupchat'>
     1420              <subject>test</subject>
     1421            </message>
     1422        """ % (self.userJID, self.occupantJID)
     1423
     1424        self._createRoom()
     1425        self.stub.send(parseXml(xml))
    11861426
    11871427
     
    12001440        def receivedGroupChat(room, user, message):
    12011441            self.assertEquals('test', message.body, "Wrong group chat message")
    1202             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1442            self.assertEquals(self.roomJID, room.roomJID,
    12031443                              'Wrong room name')
    12041444
     
    12281468
    12291469
     1470    def test_receivedGroupChatNotInRoom(self):
     1471        """
     1472        Messages received from a room we're not in are ignored.
     1473        """
     1474        xml = u"""
     1475            <message to='test@test.com' from='%s' type='groupchat'>
     1476              <body>test</body>
     1477            </message>
     1478        """ % (self.occupantJID)
     1479
     1480        def receivedGroupChat(room, user, message):
     1481            self.fail("Unexpected call to receivedGroupChat")
     1482
     1483        self.protocol.receivedGroupChat = receivedGroupChat
     1484        self.stub.send(parseXml(xml))
     1485
     1486
     1487    def test_receivedGroupChatNotOverridden(self):
     1488        """
     1489        Not overriding receivedGroupChat is ok.
     1490        """
     1491        xml = u"""
     1492            <message to='test@test.com' from='%s' type='groupchat'>
     1493              <body>test</body>
     1494            </message>
     1495        """ % (self.occupantJID)
     1496
     1497        self._createRoom()
     1498        self.stub.send(parseXml(xml))
     1499
     1500
    12301501    def test_join(self):
    12311502        """
     
    12341505
    12351506        def cb(room):
    1236             self.assertEquals(self.roomIdentifier, room.roomIdentifier)
     1507            self.assertEqual(self.roomJID, room.roomJID)
     1508            self.assertTrue('joined', room.state)
    12371509
    12381510        d = self.protocol.join(self.roomJID, self.nick)
     
    12511523
    12521524
     1525    def test_joinForbidden(self):
     1526        """
     1527        A forbidden error in response to a join errbacks with L{StanzaError}.
     1528        """
     1529
     1530        def cb(error):
     1531            self.assertEquals('forbidden', error.condition,
     1532                              'Wrong muc condition')
     1533            self.assertIdentical(None, self.protocol._getRoom(self.roomJID))
     1534
     1535
     1536        d = self.protocol.join(self.roomJID, self.nick)
     1537        self.assertFailure(d, StanzaError)
     1538        d.addCallback(cb)
     1539
     1540        # send back error, forbidden
     1541        xml = u"""
     1542            <presence from='%s' type='error'>
     1543              <error type='auth'>
     1544                <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     1545              </error>
     1546            </presence>
     1547        """ % (self.occupantJID)
     1548        self.stub.send(parseXml(xml))
     1549        return d
     1550
     1551
    12531552    def test_userLeftRoom(self):
    12541553        """
     
    12691568
    12701569        def userLeftRoom(room, user):
    1271             self.assertEquals(self.roomIdentifier, room.roomIdentifier,
     1570            self.assertEquals(self.roomJID, room.roomJID,
    12721571                              'Wrong room name')
    12731572            self.assertFalse(room.inRoster(user), 'User in roster')
     
    13041603
    13051604
    1306     def test_nick(self):
    1307         """
    1308         Send a nick change to the server.
    1309         """
    1310         newNick = 'newNick'
     1605    def test_receivedHistoryNotOverridden(self):
     1606        """
     1607        Not overriding receivedHistory is ok.
     1608        """
     1609        xml = u"""
     1610            <message to='test@test.com' from='%s' type='groupchat'>
     1611              <body>test</body>
     1612              <delay xmlns='urn:xmpp:delay' stamp="2002-10-13T23:58:37Z"
     1613                                            from="%s"/>
     1614            </message>
     1615        """ % (self.occupantJID, self.userJID)
    13111616
    13121617        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
     1618        self.stub.send(parseXml(xml))
     1619
     1620
     1621    def test_nickConflict(self):
     1622        """
     1623        If the server finds the new nick in conflict, the errback is called.
     1624        """
     1625
     1626        def cb(failure, room):
     1627            user = room.getUser(otherNick)
     1628            self.assertNotIdentical(None, user)
     1629            self.assertEqual(otherJID, user.entity)
     1630
     1631        def joined(room):
     1632            d = self.protocol.nick(room.roomJID, otherNick)
     1633            self.assertFailure(d, StanzaError)
     1634            d.addCallback(cb, room)
     1635
     1636        otherJID = JID('other@example.org/Home')
     1637        otherNick = 'otherNick'
     1638
     1639        d = self.protocol.join(self.roomJID, self.nick)
     1640        d.addCallback(joined)
     1641
     1642        # Send back other partipant's presence.
     1643        xml = u"""
     1644            <presence from='%s/%s'>
     1645              <x xmlns='http://jabber.org/protocol/muc#user'>
     1646                <item affiliation='member' role='participant' jid='%s'/>
     1647              </x>
     1648            </presence>
     1649        """ % (self.roomJID, otherNick, otherJID)
     1650        self.stub.send(parseXml(xml))
     1651
     1652        # send back user presence, they joined
    13221653        xml = u"""
    13231654            <presence from='%s/%s'>
     
    13261657              </x>
    13271658            </presence>
     1659        """ % (self.roomJID, self.nick)
     1660        self.stub.send(parseXml(xml))
     1661
     1662        room = self.protocol._getRoom(self.roomJID)
     1663
     1664        # send back error presence, nick conflicted
     1665        xml = u"""
     1666            <presence from='%s/%s' type='error'>
     1667                <x xmlns='http://jabber.org/protocol/muc'/>
     1668                <error type='cancel'>
     1669                  <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
     1670                </error>
     1671            </presence>
     1672        """ % (self.roomJID, otherNick)
     1673        self.stub.send(parseXml(xml))
     1674        return d
     1675
     1676
     1677    def test_nick(self):
     1678        """
     1679        Send a nick change to the server.
     1680        """
     1681        newNick = 'newNick'
     1682
     1683        room = self._createRoom()
     1684
     1685        def joined(room):
     1686            self.assertEqual(self.roomJID, room.roomJID)
     1687            self.assertEqual(newNick, room.nick)
     1688            user = room.getUser(newNick)
     1689            self.assertNotIdentical(None, user)
     1690            self.assertEqual(newNick, user.nick)
     1691
     1692        d = self.protocol.nick(self.roomJID, newNick)
     1693        d.addCallback(joined)
     1694
     1695        # Nick should not have been changed, yet, as we haven't gotten
     1696        # confirmation, yet.
     1697
     1698        self.assertEquals(self.nick, room.nick)
     1699
     1700        # send back user presence, nick changed
     1701        xml = u"""
     1702            <presence from='%s/%s'>
     1703              <x xmlns='http://jabber.org/protocol/muc#user'>
     1704                <item affiliation='member' role='participant'/>
     1705              </x>
     1706            </presence>
    13281707        """ % (self.roomJID, newNick)
    1329         self.stub.send(parseXml(xml))
     1708
     1709        self.stub.send(parseXml(xml))
     1710        return d
     1711
     1712
     1713    def test_leave(self):
     1714        """
     1715        Client leaves a room
     1716        """
     1717        def joined(_):
     1718            return self.protocol.leave(self.roomJID)
     1719
     1720        def left(_):
     1721            self.assertIdentical(None, self.protocol._getRoom(self.roomJID))
     1722
     1723        # Join the room
     1724        d = self.protocol.join(self.roomJID, self.nick)
     1725        d.addCallback(joined)
     1726        d.addCallback(left)
     1727
     1728        # Receive presence back from the room: joined.
     1729        xml = u"""
     1730            <presence to='%s' from='%s'/>
     1731        """ % (self.userJID, self.occupantJID)
     1732        self.stub.send(parseXml(xml))
     1733
     1734        # Receive presence back from the room: left.
     1735        xml = u"""
     1736            <presence to='%s' from='%s' type='unavailable'/>
     1737        """ % (self.userJID, self.occupantJID)
     1738        self.stub.send(parseXml(xml))
     1739
    13301740        return d
    13311741
     
    13411751
    13421752        def statusChanged(room):
    1343             self.assertEquals(self.roomIdentifier, room.roomIdentifier)
     1753            self.assertEqual(self.roomJID, room.roomJID)
    13441754            user = room.getUser(self.nick)
    13451755            self.assertNotIdentical(None, user, 'User not found')
    1346             self.assertEquals('testing MUC', user.status, 'Wrong status')
    1347             self.assertEquals('xa', user.show, 'Wrong show')
     1756            self.assertEqual('testing MUC', user.status, 'Wrong status')
     1757            self.assertEqual('xa', user.show, 'Wrong show')
    13481758
    13491759        # Join the room
     
    13671777            </presence>
    13681778        """ % self.occupantJID
    1369         self.stub.send(parseXml(xml))
    1370 
    1371         return d
     1779
     1780        self.stub.send(parseXml(xml))
     1781        return d
     1782
     1783
     1784    def test_destroy(self):
     1785        """
     1786        Destroy a room.
     1787        """
     1788        def destroyed(_):
     1789            self.assertIdentical(None, self.protocol._getRoom(self.roomJID))
     1790
     1791        d = self.protocol.destroy(self.occupantJID, reason='Time to leave',
     1792                                  alternate=JID('other@%s' % self.service),
     1793                                  password='secret')
     1794        d.addCallback(destroyed)
     1795
     1796        iq = self.stub.output[-1]
     1797        response = toResponse(iq, 'result')
     1798        self.stub.send(response)
     1799        return d
Note: See TracChangeset for help on using the changeset viewer.