# HG changeset patch # User souliane # Date 1388923531 -3600 # Node ID dd656d745d6a36eb70feecc15146c13add3af234 # Parent c3acc1298a2f97ae6c51fb2996241e52418441a4 test: added tests for XEP-0033 diff -r c3acc1298a2f -r dd656d745d6a src/core/sat_main.py --- a/src/core/sat_main.py Sun Jan 05 13:04:54 2014 +0100 +++ b/src/core/sat_main.py Sun Jan 05 13:05:31 2014 +0100 @@ -68,7 +68,9 @@ """ 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 @@ 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 -r c3acc1298a2f -r dd656d745d6a src/plugins/plugin_xep_0033.py --- a/src/plugins/plugin_xep_0033.py Sun Jan 05 13:04:54 2014 +0100 +++ b/src/plugins/plugin_xep_0033.py Sun Jan 05 13:05:31 2014 +0100 @@ -96,7 +96,7 @@ 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 @@ 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 -r c3acc1298a2f -r dd656d745d6a src/test/test_plugin_xep_0033.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/test_plugin_xep_0033.py Sun Jan 05 13:05:31 2014 +0100 @@ -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()