Skip to content

Commit

Permalink
Merge pull request #36 from zopefoundation/maurits/delivery-datamanag…
Browse files Browse the repository at this point in the history
…er-savepoint-issue-35

Add minimal savepoint support, to not fail
  • Loading branch information
mauritsvanrees committed Dec 23, 2020
2 parents 7f71eec + dd48ed9 commit 0316df9
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
5.2 (unreleased)
================

- Add minimal savepoint support, so we do not fail if any code tries to create a savepoint.
(`#35 <https://github.com/zopefoundation/zope.sendmail/issues/35>`_).

- Fix TypeError: 'error' object is not subscriptable during error handling on
Windows (`#33 <https://github.com/zopefoundation/zope.sendmail/pull/33>`_).

Expand Down
18 changes: 16 additions & 2 deletions src/zope/sendmail/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
from time import strftime
from socket import gethostname

from transaction.interfaces import IDataManager
from transaction.interfaces import ISavepointDataManager
from transaction.interfaces import IDataManagerSavepoint
import transaction

from zope.interface import implementer
Expand All @@ -41,7 +42,14 @@
log = logging.getLogger("MailDataManager")


@implementer(IDataManager)
@implementer(IDataManagerSavepoint)
class _NoOpSavepoint(object):

def rollback(self):
return


@implementer(ISavepointDataManager)
class MailDataManager(object):

def __init__(self, callable, args=(), vote=None, onAbort=None):
Expand All @@ -62,6 +70,12 @@ def abort(self, txn):
def sortKey(self):
return str(id(self))

def savepoint(self):
# We do not need savepoint/rollback, but some code (like CMFEditions)
# uses savepoints, and breaks when one datamanager does not have this.
# So provide a dummy implementation.
return _NoOpSavepoint()

# No subtransaction support.
def abort_sub(self, txn):
"This object does not do anything with subtransactions"
Expand Down
29 changes: 29 additions & 0 deletions src/zope/sendmail/tests/test_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,35 @@ def send(self):
self.assertEqual(1, len(w))
self.assertIn("does not provide a vote method", str(w[0]))

def testSavepoint(self):
mailer = MailerStub()
delivery = DirectMailDelivery(mailer)
fromaddr = 'Jim <jim@example.com'
toaddrs = ('Guido <guido@example.com>',)
delivery.send(fromaddr, toaddrs, b'Subject: one')
# Reminder: nothing is sent yet, sending happens after commit.
self.assertEqual(mailer.sent_messages, [])
# We create a savepoint. If we rollback to this savepoint,
# the previous mail should still remain in the queue.
savepoint = transaction.savepoint()
delivery.send(fromaddr, toaddrs, b'Subject: two')
self.assertEqual(mailer.sent_messages, [])
# We rollback to the savepoint, so mail 2 should never be send anymore.
savepoint.rollback()
self.assertEqual(mailer.sent_messages, [])
# Any mail after this *should* be sent.
delivery.send(fromaddr, toaddrs, b'Subject: three')
self.assertEqual(mailer.sent_messages, [])
transaction.commit()
self.assertEqual(len(mailer.sent_messages), 2)
# They might not necessarily be sent in the order we expect.
# Get the subject lines.
all_text = b'\n'.join([mail[2] for mail in mailer.sent_messages])
lines = all_text.splitlines()
subjects = [line for line in lines if b'Subject' in line]
subjects.sort()
self.assertEqual([b'Subject: one', b'Subject: three'], subjects)


class MaildirWriterStub(object):

Expand Down

0 comments on commit 0316df9

Please sign in to comment.