[Zope3-checkins] CVS: Zope3/src/zope/app/mail/tests - __init__.py:1.1 test_asyncmailservice.py:1.1 test_batchmailer.py:1.1 test_directives.py:1.1 test_mailevents.py:1.1 test_simplemailer.py:1.1

Stephan Richter srichter@cbu.edu
Wed, 16 Apr 2003 09:45:45 -0400


Update of /cvs-repository/Zope3/src/zope/app/mail/tests
In directory cvs.zope.org:/tmp/cvs-serv29814/mail/tests

Added Files:
	__init__.py test_asyncmailservice.py test_batchmailer.py 
	test_directives.py test_mailevents.py test_simplemailer.py 
Log Message:
This is a first stab at a flexible facility to send out mail. I discussed
the API with Barry a bit, before writing this code. 

Goals:

  - Keep the actual IMailService interface as simple as possible.

  - Allow flexible mechanisms to send mail.

  - Be able to implement and register you own mail sending policies. 

Implementation:

  - The global mail service is an asynchronous mail sender, which means 
    it does not block the request. Once it is done, it will send an event
    to which interested parties can subscribe.

  - The AsyncMailService registers and works with Mailer objects, which 
    encode the policy of the mailing. I supplied a SimpleMailer, which has
    no specific policies and a BatchMailer, which allows to send the 
    messages in batches, so that the SMTP server will not overload. I 
    currently do not have any of the mailers in action, but I am going to
    add MailService support to the zwiki product for testing purposes soon.

  - MailService will make heavy use of the EventService for publishing 
    status updates, which is necessary due to its async nature. Currently 
    I have only one event, but I plan to add more soon.

To Do:

  - I lied about the AsyncMailService to be async! :-) I actually have not 
    implemented the async behavior yet; I need help from other people for
    this feature. Should I use thread or asyncore, and how do I use either 
    one. I am not really knowledgable in this area.

  - As mentioned above, add more events.

  - Come up with advanced unit tests for the BatchMailer.

  - Put the MailService-specific ZCML directive into a higher up ZCML file,
    since it contains server-specific information, similar to the ones for 
    HTTP and FTP.


=== Added File Zope3/src/zope/app/mail/tests/__init__.py ===


=== Added File Zope3/src/zope/app/mail/tests/test_asyncmailservice.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""MailService Implementation

Simple implementation of the MailService, Mailers and MailEvents.

$Id: test_asyncmailservice.py,v 1.1 2003/04/16 13:45:44 srichter Exp $
"""
from unittest import TestCase, TestSuite, makeSuite
from zope.app.interfaces.mail import IAsyncMailService, IMailer, IMailSentEvent
from zope.app.mail.service import AsyncMailService


class MailerStub:
    __implements__ = IMailer

    def send(self, fromaddr, toaddrs, message,
             hostname, port, username, password):
        self.fromaddr = fromaddr
        self.toaddrs = toaddrs
        self.message = message
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password


class TestAsyncMailService(TestCase):

    def setUp(self):
        self.obj = AsyncMailService()
        self.obj.provideMailer('dummy', MailerStub, True)

    def testInterfaceConformity(self):
        self.assert_(IAsyncMailService.isImplementedBy(self.obj))

    def test_createMailer(self):
        self.assertEqual(MailerStub, self.obj.createMailer('dummy').__class__)
        self.assertRaises(KeyError, self.obj.createMailer, ('foo',))

    def test_getMailerNames(self):
        self.assertEqual(['dummy'], self.obj.getMailerNames())
        self.obj.provideMailer('dummy2', MailerStub)
        names = self.obj.getMailerNames()
        names.sort()
        self.assertEqual(['dummy', 'dummy2'], names)

    def test_getDefaultMailerName(self):
        self.assertEqual('dummy', self.obj.getDefaultMailerName())

    def test_send(self):
        # Just test API conformity
        self.obj.send('foo@bar.com', ['blah@bar.com'], 'This is a message')
        mailer = MailerStub()
        self.obj.send('foo@bar.com', ['blah@bar.com'], 'This is a message',
                      mailer)
        self.assertEqual('foo@bar.com', mailer.fromaddr)
        self.assertEqual(['blah@bar.com'], mailer.toaddrs)
        self.assertEqual('This is a message', mailer.message)

    

def test_suite():
    return TestSuite((
        makeSuite(TestAsyncMailService),
        ))


=== Added File Zope3/src/zope/app/mail/tests/test_batchmailer.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""MailService Implementation

Simple implementation of the MailService, Mailers and MailEvents.

$Id: test_batchmailer.py,v 1.1 2003/04/16 13:45:44 srichter Exp $
"""
from unittest import TestCase, TestSuite, makeSuite
from test_simplemailer import TestSimpleMailer


class TestBatchMailer(TestSimpleMailer):
    # Minimal test.
    pass


def test_suite():
    return TestSuite((
        makeSuite(TestBatchMailer),
        ))


=== Added File Zope3/src/zope/app/mail/tests/test_directives.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test the gts ZCML namespace directives.

$Id: test_directives.py,v 1.1 2003/04/16 13:45:44 srichter Exp $
"""
import os
import unittest

from cStringIO import StringIO

from zope.component import getService
from zope.component.tests.placelesssetup import PlacelessSetup
from zope.configuration.xmlconfig import xmlconfig, Context, XMLConfig
from zope.configuration.exceptions import ConfigurationError

from zope.app.component.metaconfigure import managerHandler, provideInterface
import zope.app.mail
import zope.app.interfaces.mail 

template = """<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:mail='http://namespaces.zope.org/mail'>
   xmlns:test='http://www.zope.org/NS/Zope3/test'>
   %s
   </zopeConfigure>"""


class DirectivesTest(PlacelessSetup, unittest.TestCase):

    def setUp(self):
        PlacelessSetup.setUp(self)
        managerHandler('defineService', 'Mail',
                       zope.app.interfaces.mail.IMailService)
        provideInterface('zope.app.interfaces.mail.IMailService',
                         zope.app.interfaces.mail.IMailService)
        XMLConfig('metameta.zcml', zope.configuration)()
        XMLConfig('meta.zcml', zope.app.mail)()

    def test_mailservice(self):        
        xmlconfig(StringIO(template % (
            '''            
            <mail:mailservice name="Mail"
               hostname="somehost" port="125"
               username="foo" password="bar"
               class=".mail.AsyncMailService" 
               permission="zope.Public" />
            '''
            )), None, Context([], zope.app.mail))
        service = getService(None, 'Mail') 
        self.assertEqual('AsyncMailService', service.__class__.__name__)
        self.assertEqual('somehost', service.hostname)
        self.assertEqual(125, service.port)
        self.assertEqual('foo', service.username)
        self.assertEqual('bar', service.password)

    def test_mailer(self):
        xmlconfig(StringIO(template % (
            '''            
            <mail:mailservice class=".mail.AsyncMailService" 
                permission="zope.Public" />

            <mail:mailer name="TestSimpleMailer" class=".mailer.SimpleMailer" 
                serviceType="Mail" default="True" /> 
            '''
            )), None, Context([], zope.app.mail))

        service = getService(None, "Mail")
        self.assertEqual("TestSimpleMailer", service.getDefaultMailerName())
        self.assertEqual(service._AsyncMailService__mailers['TestSimpleMailer'],
                         service.createMailer('TestSimpleMailer').__class__)


def test_suite():
    return unittest.makeSuite(DirectivesTest)

if __name__ == '__main__':
    unittest.TextTestRunner().run(test_suite())


=== Added File Zope3/src/zope/app/mail/tests/test_mailevents.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""MailService Implementation

Simple implementation of the MailService, Mailers and MailEvents.

$Id: test_mailevents.py,v 1.1 2003/04/16 13:45:44 srichter Exp $
"""
from unittest import TestCase, TestSuite, makeSuite
from zope.app.interfaces.mail import IMailer, IMailSentEvent
from zope.app.mail.event import MailSentEvent


class MailerStub:
    __implements__ = IMailer

    def send(self, fromaddr, toaddrs, message,
             hostname, port, username, password):
        self.fromaddr = fromaddr
        self.toaddrs = toaddrs
        self.message = message
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password


class TestMailSentEvent(TestCase):

    def setUp(self):
        self.mailer = MailerStub()
        self.obj = MailSentEvent(self.mailer)

    def test_InterfaceConformity(self):
        self.assert_(IMailSentEvent.isImplementedBy(self.obj))

    def test_mailerAttr(self):
        self.assertEqual(self.mailer, self.obj.mailer)


def test_suite():
    return TestSuite((
        makeSuite(TestMailSentEvent),
        ))


=== Added File Zope3/src/zope/app/mail/tests/test_simplemailer.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""MailService Implementation

Simple implementation of the MailService, Mailers and MailEvents.

$Id: test_simplemailer.py,v 1.1 2003/04/16 13:45:44 srichter Exp $
"""
from unittest import TestCase, TestSuite, makeSuite
from zope.app.interfaces.mail import IAsyncMailService, IMailer, IMailSentEvent
from zope.app.mail.event import MailSentEvent 
import zope.app.mail.mailer 

from zope.component.tests.placelesssetup import PlacelessSetup
import zope.app.event.tests.placelesssetup as event_setup

class SMTPStub(TestCase):

    hostname = ''
    port = 25
    username = ''
    password = ''
    fromaddr = ''
    toaddrs = ''
    message = ''

    def __init__(self, hostname, port=25):
        self.assertEqual(self.hostname, hostname)
        self.assertEqual(self.port, port)

    def set_debuglevel(self, level):
        pass

    def login(self, username, password):
        self.assertEqual(self.username, username)
        self.assertEqual(self.password, password)


    def sendmail(self, fromaddr, toaddrs, message):
        self.assertEqual(self.fromaddr, fromaddr)
        self.assertEqual(self.toaddrs, toaddrs)
        self.assertEqual(self.message, message)

    def quit(self):
        pass



class TestSimpleMailer(event_setup.PlacelessSetup, PlacelessSetup, TestCase):

    def setUp(self):
        PlacelessSetup.setUp(self)
        event_setup.PlacelessSetup.setUp(self)
        self.obj = zope.app.mail.mailer.SimpleMailer()

    def test_InterfaceConformity(self):
        self.assert_(IMailer.isImplementedBy(self.obj))

    def test_send(self):
        SMTPStub.hostname = 'localhost'
        SMTPStub.port = 1025
        SMTPStub.username = 'srichter'
        SMTPStub.password = 'blah'
        SMTPStub.fromaddr = 'foo@bar.com'
        SMTPStub.toaddrs = ['blah@bar.com', 'booh@bar.com']
        SMTPStub.message = 'This is the message'
        zope.app.mail.mailer.SMTP = SMTPStub
        
        self.obj.send('foo@bar.com', ['blah@bar.com', 'booh@bar.com'],
                      'This is the message', 'localhost', 1025,
                      'srichter', 'blah');
        self.assertEqual(MailSentEvent, event_setup.events[0].__class__)
        

def test_suite():
    return TestSuite((
        makeSuite(TestSimpleMailer),
        ))