changeset 794:52c4b755aba6

test: make FakeClient profile dependent and add some tools to test MUC
author souliane <souliane@mailoo.org>
date Fri, 10 Jan 2014 18:15:02 +0100
parents cb2db0d85029
children 6625558371db
files src/test/constants.py src/test/helpers.py src/test/helpers_plugins.py src/test/test_helpers_plugins.py
diffstat 4 files changed, 338 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/test/constants.py	Fri Jan 10 18:19:34 2014 +0100
+++ b/src/test/constants.py	Fri Jan 10 18:15:02 2014 +0100
@@ -23,10 +23,14 @@
 
 class Const(object):
 
-    PROFILE = ['test_profile', 'test_profile2', 'test_profile3', 'test_profile4']
-    JID_STR = [u"test@example.org/SàT", u"sender@example.net/house", u"sender@example.net/work", u"test@server.net/res"]
+    PROFILE = ['test_profile', 'test_profile2', 'test_profile3', 'test_profile4', 'test_profile5']
+    JID_STR = [u"test@example.org/SàT", u"sender@example.net/house", u"sender@example.net/work", u"sender@server.net/res", u"xxx@server.net/res"]
     JID = [jid.JID(jid_s) for jid_s in JID_STR]
 
+    PROFILE_DICT = {}
+    for i in xrange(0, len(PROFILE)):
+        PROFILE_DICT[PROFILE[i]] = JID[i]
+
     MUC_STR = [u"room@chat.server.domain", u"sat_game@chat.server.domain"]
     MUC = [jid.JID(jid_s) for jid_s in MUC_STR]
 
--- a/src/test/helpers.py	Fri Jan 10 18:19:34 2014 +0100
+++ b/src/test/helpers.py	Fri Jan 10 18:15:02 2014 +0100
@@ -63,9 +63,12 @@
         self.init()
 
     def init(self):
-        """This can be called by tests that check for sent and stored messages"""
+        """This can be called by tests that check for sent and stored messages,
+        uses FakeClient or get/set some other data that need to be cleaned"""
         self.sent_messages = []
         self.stored_messages = []
+        self.plugins = {}
+        self.profiles = {}
 
     def delContact(self, to, profile_key):
         #TODO
@@ -81,6 +84,8 @@
         self.sendAndStoreMessage({"to": JID(to_s)})
 
     def sendAndStoreMessage(self, mess_data, skip_send=False, profile=None):
+        """Save the information to check later to whom messages have been sent and
+        if entries have been added to the history"""
         if not skip_send:
             self.sent_messages.append(mess_data["to"])
         self.stored_messages.append(mess_data["to"])
@@ -104,12 +109,50 @@
         return defer.succeed(jid_ if self.memory.hasServerFeature(feature, jid_, profile_key) else None)
 
     def getClientHostJid(self, profile_key):
-        return JID(Const.JID[0].host)
+        return Const.PROFILE_DICT[profile_key].host
+
+    def getClient(self, profile_key):
+        """Convenient method to get client from profile key
+        @return: client or None if it doesn't exist"""
+        profile = self.memory.getProfileName(profile_key)
+        if not profile:
+            return None
+        if profile not in self.profiles:
+            self.profiles[profile] = FakeClient(self, profile)
+            self.profiles[profile].client_initialized.callback(None)
+        return self.profiles[profile]
+
+    def getJidNStream(self, profile_key):
+        """Convenient method to get jid and stream from profile key
+        @return: tuple (jid, xmlstream) from profile, can be None"""
+        return (Const.PROFILE_DICT[profile_key], None)
+
+    def isConnected(self, profile):
+        return True
+
+    def getSentMessage(self, message_index, profile_index):
+        """Called by tests. FakeClient instances associated to each profile must have
+        been previously initialized with the method FakeSAT.getClient.
+        @return: XML representation of the <message_index>th sent message for given profile"""
+        return self.profiles[Const.PROFILE[profile_index]].xmlstream.sent[message_index]
+
+    def countSentMessages(self, profiles=Const.PROFILE):
+        """Called by tests. FakeClient instances associated to each profile must have
+        been previously initialized with the method FakeSAT.getClient.
+        @param profiles: list of profiles
+        @return: a list containing the number of sent messages for each of the specified profiles"""
+        result = []
+        for profile in profiles:
+            result.append(len(self.profiles[profile].xmlstream.sent))
+        return result
 
 
 class FakeBridge(object):
     """Class to simulate and test bridge calls"""
 
+    def __init__(self):
+        self.methods = {}
+
     def expectCall(self, name, *check_args, **check_kwargs):
         def checkCall(*args, **kwargs):
             if args != check_args or kwargs != check_kwargs:
@@ -128,6 +171,13 @@
     def addSignal(self, name, int_suffix, signature):
         pass
 
+    def addTestCallback(self, name, method):
+        """This can be used to register callbacks for bridge methods AND signals.
+        Contrary to expectCall, this will not check if the method or signal is
+        called/sent with the correct arguments, it will instead run the callback
+        of your choice."""
+        setattr(self, name, method)
+
 
 class FakeParams(Params):
     """Class to simulate and test params object. The methods of Params that could
@@ -168,6 +218,7 @@
         # manipulating basic stuff, the others should be overwritten when needed
         self.host = host
         self.params = FakeParams(host, None)
+        self.config = self.parseMainConf()
         self.init()
 
     def init(self):
@@ -218,11 +269,12 @@
 
 
 class FakeRosterProtocol(SatRosterProtocol):
+    """This class is used by FakeClient (one instance per profile)"""
 
     def __init__(self, host, parent):
         SatRosterProtocol.__init__(self, host)
         self.parent = parent
-        self.addItem(Const.JID[0])
+        self.addItem(parent.jid)
 
     def addItem(self, jid, *args, **kwargs):
         if not args and not kwargs:
@@ -237,15 +289,30 @@
         self.onRosterSet(roster_item)
 
 
-class FakeClient(object):
-    def __init__(self, host):
-        self.host = host
-        self.profile = 'test_profile'
-        self.jid = Const.JID[0]
-        self.roster = FakeRosterProtocol(host, self)
+class FakeXmlStream(object):
+    """This class is used by FakeClient (one instance per profile)"""
+
+    def __init__(self):
+        self.sent = []
 
     def send(self, obj):
-        pass
+        """Save the sent messages to compare them later"""
+        self.sent.append(obj.toXml())
+
+
+class FakeClient(object):
+    """Tests involving more than one profile need one instance of this class per profile"""
+
+    def __init__(self, host, profile=None):
+        self.host = host
+        self.profile = profile if profile else Const.PROFILE[0]
+        self.jid = Const.PROFILE_DICT[self.profile]
+        self.roster = FakeRosterProtocol(host, self)
+        self.client_initialized = defer.Deferred()
+        self.xmlstream = FakeXmlStream()
+
+    def send(self, obj):
+        self.xmlstream.send(obj)
 
 
 class SatTestCase(unittest.TestCase):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/helpers_plugins.py	Fri Jan 10 18:15:02 2014 +0100
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SAT: a jabber client
+# Copyright (C) 2009, 2010, 2011, 2012, 2013  Jérôme Poisson (goffi@goffi.org)
+# Copyright (C) 2013  Adrien Cossa (souliane@mailoo.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+""" Helpers class for plugin dependencies """
+
+from constants import Const
+from sat.plugins.plugin_xep_0045 import XEP_0045
+from twisted.internet import defer
+from wokkel.muc import Room, User
+
+
+class FakeMUCClient(object):
+    def __init__(self, plugin_parent):
+        self.plugin_parent = plugin_parent
+        self.host = plugin_parent.host
+        self.joined_rooms = {}
+
+    def join(self, roomJID, nick, profile):
+        roster = {}
+
+        # ask the other profiles to fill our roster
+        for i in xrange(0, len(Const.PROFILE)):
+            other_profile = Const.PROFILE[i]
+            if other_profile == profile:
+                continue
+            try:
+                other_room = self.plugin_parent.clients[other_profile].joined_rooms[roomJID.userhost()]
+                roster.setdefault(other_room.nick, User(other_room.nick, Const.PROFILE_DICT[other_profile]))
+                for other_nick in other_room.roster:
+                    roster.setdefault(other_nick, other_room.roster[other_nick])
+            except (AttributeError, KeyError):
+                pass
+
+        # rename our nick if it already exists
+        while nick in roster.keys():
+            if Const.PROFILE_DICT[profile].userhost() == roster[nick].entity.userhost():
+                break  # same user with different resource --> same nickname
+            nick = nick + "_"
+
+        room = Room(roomJID, nick)
+        room.roster = roster
+        self.joined_rooms[roomJID.userhost()] = room
+
+        # fill the other rosters with the new entry
+        for i in xrange(0, len(Const.PROFILE)):
+            other_profile = Const.PROFILE[i]
+            if other_profile == profile:
+                continue
+            try:
+                other_room = self.plugin_parent.clients[other_profile].joined_rooms[roomJID.userhost()]
+                other_room.roster.setdefault(room.nick, User(room.nick, Const.PROFILE_DICT[profile]))
+            except (AttributeError, KeyError):
+                pass
+
+        return room
+
+
+class FakeXEP_0045(XEP_0045):
+
+    def __init__(self, host):
+        self.host = host
+        self.clients = {}
+        for profile in Const.PROFILE:
+            self.clients[profile] = FakeMUCClient(self)
+
+    def join(self, room_jid, nick, options={}, profile_key='@DEFAULT@'):
+        profile = self.host.memory.getProfileName(profile_key)
+        room_jid_s = room_jid.userhost()
+        if room_jid_s in self.clients[profile].joined_rooms:
+            return defer.succeed(None)
+        room = self.clients[profile].join(room_jid, nick, profile)
+        return defer.succeed(room)
+
+    def joinRoom(self, muc_index, user_index):
+        """Called by tests
+        @return: the nickname of the user in the joined room"""
+        muc = Const.MUC[muc_index]
+        nick = Const.JID[user_index].user
+        profile = Const.PROFILE[user_index]
+        self.join(muc, nick, profile_key=profile)
+        return self.getNick(muc_index, user_index)
+
+    def getRoom(self, muc_index, user_index):
+        """Called by tests
+        @return: a wokkel.muc.Room instance"""
+        profile = Const.PROFILE[user_index]
+        muc_s = Const.MUC_STR[muc_index]
+        try:
+            return self.clients[profile].joined_rooms[muc_s]
+        except (AttributeError, KeyError):
+            return None
+
+    def getNick(self, muc_index, user_index):
+        try:
+            return self.getRoomNick(Const.MUC_STR[muc_index], Const.PROFILE[user_index])
+        except (KeyError, AttributeError):
+            return ''
+
+    def getNickOfUser(self, muc_index, user_index, profile_index, secure=True):
+        try:
+            room = self.clients[Const.PROFILE[profile_index]].joined_rooms[Const.MUC_STR[muc_index]]
+            return self.getRoomNickOfUser(room, Const.JID_STR[user_index])
+        except (KeyError, AttributeError):
+            return None
+
+
+class FakeXEP_0249(object):
+
+    def __init__(self, host):
+        self.host = host
+
+    def invite(self, target, room, options={}, profile_key='@DEFAULT@'):
+        """
+        Invite a user to a room. To accept the invitation from a test,
+        just call FakeXEP_0045.joinRoom (no need to have a dedicated method).
+        @param target: jid of the user to invite
+        @param room: jid of the room where the user is invited
+        @options: attribute with extra info (reason, password) as in #XEP-0249
+        @profile_key: %(doc_profile_key)s
+        """
+        pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/test_helpers_plugins.py	Fri Jan 10 18:15:02 2014 +0100
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SAT: a jabber client
+# Copyright (C) 2009, 2010, 2011, 2012, 2013  Jérôme Poisson (goffi@goffi.org)
+# Copyright (C) 2013  Adrien Cossa (souliane@mailoo.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+""" Test the helper classes to see if they behave well"""
+
+import helpers
+import helpers_plugins
+
+
+class FakeXEP_0045Test(helpers.SatTestCase):
+
+    def setUp(self):
+        self.host = helpers.FakeSAT()
+        self.plugin = helpers_plugins.FakeXEP_0045(self.host)
+
+    def test_joinRoom(self):
+        self.plugin.joinRoom(0, 0)
+        self.assertEqual('test', self.plugin.getNick(0, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 0))
+        self.assertEqual('', self.plugin.getNick(0, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 1))
+        self.assertEqual('', self.plugin.getNick(0, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 2))
+        self.assertEqual('', self.plugin.getNick(0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 3))
+        self.plugin.joinRoom(0, 1)
+        self.assertEqual('test', self.plugin.getNick(0, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 0))
+        self.assertEqual('sender', self.plugin.getNick(0, 1))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 1))
+        self.assertEqual('', self.plugin.getNick(0, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 2))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 2))
+        self.assertEqual('', self.plugin.getNick(0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 3))
+        self.plugin.joinRoom(0, 2)
+        self.assertEqual('test', self.plugin.getNick(0, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 0))
+        self.assertEqual('sender', self.plugin.getNick(0, 1))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 1))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 1))  # Const.JID[2] is in the roster for Const.PROFILE[1]
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 1))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 1))
+        self.assertEqual('sender', self.plugin.getNick(0, 2))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 2))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 2))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 2))   # Const.JID[1] is in the roster for Const.PROFILE[2]
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 2))
+        self.assertEqual('', self.plugin.getNick(0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 1, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 2, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 3))
+        self.plugin.joinRoom(0, 3)
+        self.assertEqual('test', self.plugin.getNick(0, 0))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 0, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 0))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 0))
+        self.assertEqual('sender_', self.plugin.getNickOfUser(0, 3, 0))
+        self.assertEqual('sender', self.plugin.getNick(0, 1))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 1))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 1))  # Const.JID[2] is in the roster for Const.PROFILE[1]
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 1))
+        self.assertEqual('sender_', self.plugin.getNickOfUser(0, 3, 1))
+        self.assertEqual('sender', self.plugin.getNick(0, 2))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 2))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 2))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 2))   # Const.JID[1] is in the roster for Const.PROFILE[2]
+        self.assertEqual('sender_', self.plugin.getNickOfUser(0, 3, 2))
+        self.assertEqual('sender_', self.plugin.getNick(0, 3))
+        self.assertEqual('test', self.plugin.getNickOfUser(0, 0, 3))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 1, 3))
+        self.assertEqual('sender', self.plugin.getNickOfUser(0, 2, 3))
+        self.assertEqual(None, self.plugin.getNickOfUser(0, 3, 3))