From 84bfd205ddbc6f4447c0a863f7a24ff7fc16684c Mon Sep 17 00:00:00 2001 From: souliane Date: Sun, 5 Jan 2014 13:05:31 +0100 Subject: [PATCH] test: added tests for XEP-0033 --- src/core/sat_main.py | 10 +- src/plugins/plugin_xep_0033.py | 7 +- src/test/test_plugin_xep_0033.py | 164 +++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 src/test/test_plugin_xep_0033.py diff --git a/src/core/sat_main.py b/src/core/sat_main.py index f5da7d27..049ab958 100644 --- a/src/core/sat_main.py +++ b/src/core/sat_main.py @@ -68,7 +68,9 @@ class MessageSentAndStored(Exception): """ Exception to raise if the message has been already sent and stored in the history by the trigger, so the rest of the process should be stopped. This should normally be raised by the trigger with the minimal priority """ - pass + def __init__(self, reason, mess_data): + Exception(reason) + self.mess_data = mess_data # added for testing purpose class AbortSendMessage(Exception): @@ -652,10 +654,10 @@ class SAT(service.Service): def requestServerDisco(self, feature, jid_=None, cache_only=False, profile_key="@NONE"): """Discover if a server or its items offer a given feature @param feature: the feature to check - @param jid_: the jid of the server + @param jid_: the jid of the server, local server if None @param cache_only: expect the result to be in cache and don't actually - make any request to avoid returning a Deferred. This can be used anytime - for requesting the local server because the data are cached for sure. + make any request. This can be used anytime for requesting a feature on + the local server because the data are cached for sure. @result: the Deferred entity jid offering the feature, or None """ profile = self.memory.getProfileName(profile_key) diff --git a/src/plugins/plugin_xep_0033.py b/src/plugins/plugin_xep_0033.py index 81cb061f..add9552c 100644 --- a/src/plugins/plugin_xep_0033.py +++ b/src/plugins/plugin_xep_0033.py @@ -96,7 +96,7 @@ class XEP_0033(object): element.addChild(domish.Element((None, 'address'), None, {'type': type_, 'jid': jid_})) # when the prosody plugin is completed, we can immediately return mess_data from here self.sendAndStoreMessage(mess_data, entries, profile) - return Failure(MessageSentAndStored("XEP-0033 took over")) + return Failure(MessageSentAndStored("XEP-0033 took over", mess_data)) d = self.host.requestServerDisco(NS_ADDRESS, profile_key=profile) d.addCallbacks(discoCallback, lambda dummy: discoCallback(None)) return d @@ -151,7 +151,10 @@ class XEP_0033(object): def post_treat_addr(data, addresses): data['extra']['addresses'] = "" for address in addresses: - data['extra']['addresses'] += '%s:%s\n' % (address['type'], address['jid']) + # Depending how message has been constructed, we could get here + # some noise like "\n " instead of an address element. + if isinstance(address, domish.Element): + data['extra']['addresses'] += '%s:%s\n' % (address['type'], address['jid']) return data try: diff --git a/src/test/test_plugin_xep_0033.py b/src/test/test_plugin_xep_0033.py new file mode 100644 index 00000000..65fd15ae --- /dev/null +++ b/src/test/test_plugin_xep_0033.py @@ -0,0 +1,164 @@ +#!/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 . + +""" Plugin extended addressing stanzas """ + +from constants import Const +from sat.test import helpers +from sat.plugins import plugin_xep_0033 as plugin +from sat.memory.memory import NO_SECURITY_LIMIT +from sat.core.sat_main import AbortSendMessage, MessageSentAndStored +from copy import deepcopy +from twisted.internet import defer +from wokkel.generic import parseXml +from twisted.words.protocols.jabber.jid import JID + + +class XEP_0033Test(helpers.SatTestCase): + + def setUp(self): + self.host = helpers.FakeSAT() + self.plugin = plugin.XEP_0033(self.host) + + def test_messageReceived(self): + self.host.memory.init() + xml = u""" + + test + +
+
+
+ + + """ % (Const.TEST_JID_2_STR, self.host.getClientHostJid(Const.TEST_PROFILE), + Const.TEST_JID_STR, Const.TEST_JID_2_STR, Const.TEST_JID_3_STR) + stanza = parseXml(xml.encode("utf-8")) + treatments = defer.Deferred() + self.plugin.messageReceivedTrigger(stanza, treatments, Const.TEST_PROFILE) + data = {'extra': {}} + + def assert_(data): + expected = ('to', Const.TEST_JID_STR, 'cc', Const.TEST_JID_2_STR, 'bcc', Const.TEST_JID_3_STR) + assert(data['extra']['addresses'] == '%s:%s\n%s:%s\n%s:%s\n' % expected) + + treatments.addCallback(assert_) + treatments.callback(data) + + def test_sendMessageTrigger(self): + mess_data = {"to": self.host.getClientHostJid(Const.TEST_PROFILE), + "type": "chat", + "message": "content", + "extra": {} + } + addresses = ('to', Const.TEST_JID_STR, 'cc', Const.TEST_JID_2_STR, 'bcc', Const.TEST_JID_3_STR) + mess_data["extra"]["address"] = '%s:%s\n%s:%s\n%s:%s\n' % addresses + original_stanza = u""" + + content + + """ % (Const.TEST_JID_2_STR, self.host.getClientHostJid(Const.TEST_PROFILE)) + mess_data['xml'] = parseXml(original_stanza.encode("utf-8")) + expected = deepcopy(mess_data['xml']) + addresses_extra = """ + +
+
+
+ """ % addresses + addresses_element = parseXml(addresses_extra.encode('utf-8')) + expected.addChild(addresses_element) + + def assert_(mess_data): + """The mess_data that we got here as been modified by self.plugin.sendMessageTrigger, + check that the addresses element has been added to the stanza.""" + self.assertEqualXML(mess_data['xml'].toXml().encode("utf-8"), expected.toXml().encode("utf-8")) + + def fail_(failure, exception_class): + """If the failure does encapsulate the expected exception, it will be silently + trapped, otherwise it will be re-raised and will make the test fail""" + if exception_class == MessageSentAndStored: + assert_(failure.value.mess_data) + failure.trap(exception_class) + + def checkSentAndStored(): + """Check that all the recipients got their messages and that the history has been filled. + /!\ see the comments in XEP_0033.sendAndStoreMessage""" + sent = [] + stored = [] + cache = set() + for to_s in [addresses[1], addresses[3], addresses[5]]: + to_jid = JID(to_s) + host = JID(to_jid.host) + if self.host.memory.hasServerFeature(plugin.NS_ADDRESS, host, Const.TEST_PROFILE): + if host not in cache: + sent.append(host) + stored.append(host) + cache.add(host) + stored.append(to_jid) + else: + sent.append(to_jid) + stored.append(to_jid) + try: + assert(len(self.host.sent_messages) == len(sent)) + assert(len(self.host.stored_messages) == len(stored)) + assert(set(self.host.sent_messages) == set(sent)) + assert(set(self.host.stored_messages) == set(stored)) + except AssertionError as e: + print "----------------------------------------------------" + print "Comparing sent and stored messages failed!" + print self.host.sent_messages + print sent + print self.host.stored_messages + print stored + print "/!\ see the comments in XEP_0033.sendAndStoreMessage" + print "----------------------------------------------------" + raise e + + # feature is not supported, abort the message + self.host.memory.init() + treatments = defer.Deferred() + data = deepcopy(mess_data) + self.plugin.sendMessageTrigger(data, treatments, Const.TEST_PROFILE) + treatments.addCallbacks(assert_, lambda failure: fail_(failure, AbortSendMessage)) + treatments.callback(data) + + # feature is supported + self.host.init() + self.host.memory.init() + self.host.memory.addServerFeature(plugin.NS_ADDRESS, self.host.getClientHostJid(Const.TEST_PROFILE), Const.TEST_PROFILE) + treatments = defer.Deferred() + data = deepcopy(mess_data) + self.plugin.sendMessageTrigger(data, treatments, Const.TEST_PROFILE) + treatments.addCallbacks(assert_, lambda failure: fail_(failure, MessageSentAndStored)) + treatments.callback(data) + checkSentAndStored() + + # check that a wrong recipient entity is fixed by the backend + self.host.init() + self.host.memory.init() + self.host.memory.addServerFeature(plugin.NS_ADDRESS, self.host.getClientHostJid(Const.TEST_PROFILE), Const.TEST_PROFILE) + treatments = defer.Deferred() + data = deepcopy(mess_data) + data["to"] = Const.TEST_JID + self.plugin.sendMessageTrigger(data, treatments, Const.TEST_PROFILE) + treatments.addCallbacks(assert_, lambda failure: fail_(failure, MessageSentAndStored)) + treatments.callback(mess_data) + checkSentAndStored()