Rev 38: (James Henstridge) clean up the SMTP handling, and PQM Submission logic. in http://bazaar.launchpad.net/%7Ebzr/bzr-pqm/devel
John Arbash Meinel
john at arbash-meinel.com
Tue Nov 6 02:44:08 GMT 2007
At http://bazaar.launchpad.net/%7Ebzr/bzr-pqm/devel
------------------------------------------------------------
revno: 38
revision-id:john at arbash-meinel.com-20071106024333-wbjbqrtdgcvtu4bg
parent: mbp at sourcefrog.net-20070712231153-a0mqgiz3ppf2xgdx
parent: james at jamesh.id.au-20071025091923-vtb9vag27j1zatry
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: pqm
timestamp: Mon 2007-11-05 20:43:33 -0600
message:
(James Henstridge) clean up the SMTP handling, and PQM Submission logic.
modified:
__init__.py __init__.py-20060221052551-30932fa7d369a24b
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
test_pqm_submit.py test_pqm_submit.py-20060221060137-fb48d47216aa0077
------------------------------------------------------------
revno: 37.1.6
revision-id:james at jamesh.id.au-20071025091923-vtb9vag27j1zatry
parent: james at jamesh.id.au-20071025091756-rnh1w9i4oircmo3p
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Thu 2007-10-25 17:19:23 +0800
message:
Remove some unnecessary imports.
modified:
__init__.py __init__.py-20060221052551-30932fa7d369a24b
------------------------------------------------------------
revno: 37.1.5
revision-id:james at jamesh.id.au-20071025091756-rnh1w9i4oircmo3p
parent: james at jamesh.id.au-20071023105033-k9rgn1x1ip8tfm2c
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Thu 2007-10-25 17:17:56 +0800
message:
Simplify PQMSubmission object, fixing up locations in the constructor.
modified:
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
test_pqm_submit.py test_pqm_submit.py-20060221060137-fb48d47216aa0077
------------------------------------------------------------
revno: 37.1.4
revision-id:james at jamesh.id.au-20071023105033-k9rgn1x1ip8tfm2c
parent: james at jamesh.id.au-20071018104526-grxnfe1iensz7yrf
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Tue 2007-10-23 18:50:33 +0800
message:
* Move the PQM submission logic into a PQMSubmission object.
* Add tests for PQM submission logic.
modified:
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
test_pqm_submit.py test_pqm_submit.py-20060221060137-fb48d47216aa0077
------------------------------------------------------------
revno: 37.1.3
revision-id:james at jamesh.id.au-20071018104526-grxnfe1iensz7yrf
parent: james at jamesh.id.au-20071011041243-a39r6wjtcn6u18sb
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Thu 2007-10-18 23:45:26 +1300
message:
Try and share more configuration from merge directive code:
* Emit a warning if public_repository or pqm_branch configuration items
are used.
* Use submit_branch as a fallback for pqm_branch.
modified:
__init__.py __init__.py-20060221052551-30932fa7d369a24b
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
------------------------------------------------------------
revno: 37.1.2
revision-id:james at jamesh.id.au-20071011041243-a39r6wjtcn6u18sb
parent: james at jamesh.id.au-20071009040938-zc6082dyt5zfabko
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Thu 2007-10-11 17:12:43 +1300
message:
Kill the custom smtplib code, and use bzr's email+smtp infrastructure.
modified:
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
test_pqm_submit.py test_pqm_submit.py-20060221060137-fb48d47216aa0077
------------------------------------------------------------
revno: 37.1.1
revision-id:james at jamesh.id.au-20071009040938-zc6082dyt5zfabko
parent: mbp at sourcefrog.net-20070712231153-a0mqgiz3ppf2xgdx
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr-pqm.jamesh
timestamp: Tue 2007-10-09 17:09:38 +1300
message:
Change how we speak to the SMTP server a bit:
* Explicitly say EHLO/HELO to the server, rather than doing so
implicitly as part of smtp.login()
* Only try to STARTTLS if the extension is supported, and error out if
if fails.
* Say EHLO again after STARTTLS in case the server only supports AUTH
after switching to TLS.
With these changes, we should be able to successfully talk to more
servers (e.g. EXIM servers that only allow AUTH after TLS).
modified:
pqm_submit.py pqm_submit.py-20060221060137-b3a3cdde9f50efab
-------------- next part --------------
=== modified file '__init__.py'
--- a/__init__.py 2007-07-12 23:11:53 +0000
+++ b/__init__.py 2007-10-25 09:19:23 +0000
@@ -16,11 +16,8 @@
"""Functionality for controlling a Patch Queue Manager (pqm).
"""
-import os
-
from bzrlib.commands import Command, register_command
from bzrlib.option import Option
-import bzrlib.errors as errors
from bzrlib.bzrdir import BzrDir
@@ -29,11 +26,11 @@
"""Submit the parent tree to the pqm.
This acts like:
- $ echo "star-merge $PARENT $TARGET"
- | gpg --cl
+ $ echo "star-merge $PARENT $TARGET"
+ | gpg --cl
| mail pqm at somewhere -s "merge text"
- But it pays attention to who the local committer is
+ But it pays attention to who the local committer is
(using their e-mail address), and uses the local
gpg signing configuration. (As well as target pqm
settings, etc.)
@@ -41,26 +38,24 @@
The reason we use 'parent' instead of the local branch
is that most likely the local branch is not a public
branch. And the branch must be available to the pqm.
-
+
This can be configured at the branch level using ~/.bazaar/locations.conf.
Here is an example:
[/home/emurphy/repo]
pqm_email = PQM <pqm at example.com>
pqm_user_email = User Name <user at example.com>
- pqm_branch = http://code.example.com/code/project/devel
- public_repository = http://code.example.com/code/emurphy/project
+ submit_branch = http://code.example.com/code/project/devel
+ # Set public_branch appropriately for all branches in repository:
+ public_branch = http://code.example.com/code/emurphy/project
+ public_branch:policy = appendpath
[/home/emurphy/repo/branch]
- # public_repository is used when public_branch is not set.
- # default behavior is to append the trailing path
- # Default value based on public_repository would be
- # http://code.example.com/code/emurphy/project/branch
- # override with
+ # Override public_branch for this repository:
public_branch = http://alternate.host.example.com/other/public/branch
-
+
smtp_server = host:port
smtp_username =
smtp_password =
-
+
If you don't specify the smtp server, the message will be sent via localhost.
"""
@@ -77,7 +72,7 @@
]
def run(self, location=None, message=None, public_location=None, dry_run=False):
- from pqm_submit import submit
+ from bzrlib.plugins.pqm.pqm_submit import submit
if location is None:
location = '.'
@@ -97,7 +92,7 @@
def test_suite():
- from bzrlib.tests import TestSuite, TestLoader
+ from bzrlib.tests import TestLoader
import test_pqm_submit
loader = TestLoader()
=== modified file 'pqm_submit.py'
--- a/pqm_submit.py 2007-04-26 02:05:22 +0000
+++ b/pqm_submit.py 2007-10-25 09:17:56 +0000
@@ -15,22 +15,17 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Submit an email to a Patch Queue Manager"""
-import smtplib
-
-import bzrlib
from bzrlib import (
+ config as _mod_config,
errors,
+ gpg,
+ osutils,
+ urlutils,
)
from bzrlib.branch import Branch
-import bzrlib.config
-import bzrlib.gpg
-import bzrlib.osutils
-from bzrlib.trace import note
-import bzrlib.ui
-import bzrlib.urlutils
-
-
-_default_smtp_server = 'localhost'
+from bzrlib.email_message import EmailMessage
+from bzrlib.smtp_connection import SMTPConnection
+from bzrlib.trace import note, warning
class BadCommitMessage(errors.BzrError):
@@ -42,129 +37,131 @@
self.msg = message
-def _signed_submission(branch, config, target_base):
- """Get the signed text that we would submit to the pqm"""
-
- merge_target = config.get_user_option('pqm_branch')
- if not merge_target:
- raise errors.BzrCommandError('No PQM target branch specified '
- 'in configuration')
-
- unsigned_text = 'star-merge %s %s' % (target_base, merge_target)
- unsigned_text = unsigned_text.encode('ascii') #URLs should be ascii
-
- strategy = bzrlib.gpg.GPGStrategy(config)
-
- return strategy.sign(unsigned_text)
-
-
-_default_headers = '''From: %s
-To: %s
-Subject: %s
-
-'''
-
-
-def _setup_headers(message, user_from, user_to):
- """Get all of the important headers filled out."""
- if '\n' in message:
- raise BadCommitMessage(message)
- return _default_headers % (user_from, user_to, message)
-
-
-def public_branch(branch, config):
- target_base = config.get_user_option('public_branch')
- if target_base is None:
- repo_loc = branch.repository.bzrdir.root_transport.local_abspath('.')
- repo_config = bzrlib.config.LocationConfig(repo_loc)
- public_repo = repo_config.get_user_option("public_repository")
- if public_repo is not None:
- branch_relpath = bzrlib.osutils.relpath(repo_loc,
- branch.bzrdir.root_transport.local_abspath('.'))
- target_base = bzrlib.urlutils.join(public_repo, branch_relpath)
- return target_base
+class PQMSubmission(object):
+ """A request to perform a PQM merge into a branch."""
+
+ def __init__(self, source_branch, public_location=None,
+ submit_location=None, message=None):
+ """Create a PQMSubmission object.
+
+ :param source_branch: the source branch for the merge
+ :param public_location: the public location of the source branch
+ :param submit_location: the location of the target branch
+ :param message: The message to use when committing this merge
+
+ If any of public_location, submit_location or message are
+ omitted, they will be calculated from source_branch.
+ """
+ if source_branch is None:
+ raise errors.NoMergeSource()
+ self.source_branch = source_branch
+
+ if public_location is None:
+ public_location = self.source_branch.get_public_branch()
+ # Fall back to the old public_repository hack.
+ if public_location is None:
+ src_loc = source_branch.bzrdir.root_transport.local_abspath('.')
+ repository = source_branch.repository
+ repo_loc = repository.bzrdir.root_transport.local_abspath('.')
+ repo_config = _mod_config.LocationConfig(repo_loc)
+ public_repo = repo_config.get_user_option("public_repository")
+ if public_repo is not None:
+ warning("Please use public_branch, not public_repository, "
+ "to set the public location of branches.")
+ branch_relpath = osutils.relpath(repo_loc, src_loc)
+ public_location = urlutils.join(public_repo, branch_relpath)
+
+ if public_location is None:
+ raise errors.BzrCommandError(
+ 'No public branch location given. Please specify with '
+ '--public-location or see "bzr help pqm-submit" to see how '
+ 'to set it in ~/.bazaar/locations.conf')
+ self.public_location = public_location
+
+ if submit_location is None:
+ config = self.source_branch.get_config()
+ # First check the deprecated pqm_branch config key:
+ submit_location = config.get_user_option('pqm_branch')
+ if submit_location is not None:
+ warning("Please use submit_branch, not pqm_branch to set "
+ "the PQM merge target branch.")
+ else:
+ # Otherwise, use the standard config key:
+ submit_location = self.source_branch.get_submit_branch()
+
+ if submit_location is None:
+ raise errors.NoSubmitBranch(self.source_branch)
+ self.submit_location = submit_location
+
+ # Check that the message is okay to pass to PQM
+ if message is None:
+ repository = self.source_branch.repository
+ rev = repository.get_revision(self.source_branch.last_revision())
+ message = rev.message
+ self.message = message.encode('utf8')
+ if '\n' in self.message:
+ raise BadCommitMessage(self.message)
+
+ def check_public_branch(self):
+ """Check that the public branch is up to date with the local copy."""
+ note('Checking that the public branch is up to date ...')
+ local_revision = self.source_branch.last_revision()
+ public_revision = Branch.open(self.public_location).last_revision()
+ if local_revision != public_revision:
+ raise errors.PublicBranchOutOfDate(
+ self.public_location, local_revision)
+
+ def to_lines(self):
+ """Serialise as a list of lines."""
+ return ['star-merge %s %s\n' % (self.public_location, self.submit_location)]
+
+ def to_signed(self):
+ """Serialize as a signed string."""
+ unsigned_text = ''.join(self.to_lines())
+ unsigned_text = unsigned_text.encode('ascii') #URLs should be ascii
+
+ strategy = gpg.GPGStrategy(self.source_branch.get_config())
+ return strategy.sign(unsigned_text)
+
+ def to_email(self, mail_from, mail_to, sign=True):
+ """Serialize as an email message.
+
+ :param mail_from: The from address for the message
+ :param mail_to: The address to send the message to
+ :param sign: If True, gpg-sign the email
+ :return: an email message
+ """
+ if sign:
+ body = self.to_signed()
+ else:
+ body = ''.join(self.to_lines())
+ message = EmailMessage(mail_from, mail_to, self.message, body)
+ return message
def submit(branch, message, dry_run=False, public_location=None):
"""Submit the given branch to the pqm."""
config = branch.get_config()
- if message is None:
- rev = branch.repository.get_revision(branch.last_revision())
- message = rev.message
- message = message.encode('utf8')
+ submission = PQMSubmission(
+ source_branch=branch, public_location=public_location, message=message)
- user_from = config.get_user_option('pqm_user_email')
- if not user_from:
- user_from = config.username()
- user_from = user_from.encode('utf8') # Make sure this isn't unicode
- user_to = config.get_user_option('pqm_email')
- if not user_to:
+ mail_from = config.get_user_option('pqm_user_email')
+ if not mail_from:
+ mail_from = config.username()
+ mail_from = mail_from.encode('utf8') # Make sure this isn't unicode
+ mail_to = config.get_user_option('pqm_email')
+ if not mail_to:
raise errors.BzrCommandError('No PQM submission address specified '
'in configuration')
- user_to = user_to.encode('utf8') # same here
-
- # All the entries must be utf-8 so the message creation doesn't fail
- msg = _setup_headers(message, user_from, user_to)
-
- server = config.get_user_option('smtp_server')
- if not server:
- server = _default_smtp_server
- smtp_username = config.get_user_option('smtp_username')
- smtp_password = config.get_user_option('smtp_password')
-
- if public_location is None:
- target_base = public_branch(branch, config)
- else:
- target_base = public_location
-
- if target_base is None:
- raise errors.BzrCommandError('Could not find public location, either'
- 'specify with --public-location, or see'
- ' "bzr help pqm-submit" to see how to set'
- 'it in ~/.bazaar/locations.conf')
-
- note('Checking that the public branch is up to date ...')
- try:
- public_revision = Branch.open(target_base).last_revision()
- except errors.NotBranchError:
- raise errors.BzrCommandError(
- 'Public location has no branch: %s' % target_base)
- if public_revision != branch.last_revision():
- raise errors.BzrCommandError(
- 'Local last revision does not match public last revision: %s' %
- (target_base,))
- # Get the signed text, this should be done just before
- # emailing, so that we don't run gpg --cl for nothing
- msg += _signed_submission(branch, config, target_base)
+ mail_to = mail_to.encode('utf8') # same here
+
+ submission.check_public_branch()
+
+ message = submission.to_email(mail_from, mail_to)
if dry_run:
- return print_info(msg, server, user_from, user_to)
-
- smtp = smtplib.SMTP()
- smtp.connect(server)
-
- # The world can always use a little bit more encryption :)
- smtp.starttls()
-
- if smtp_username is not None:
- if smtp_password is None:
- smtp_password = bzrlib.ui.ui_factory.get_password(
- 'Please enter SMTP password for %(host)s', host=server)
- try:
- smtp.login(smtp_username, smtp_password)
- except smtplib.SMTPHeloError, e:
- raise errors.BzrCommandError('SMTP server refused HELO: %d %s'
- % (e.smtp_code, e.smtp_error))
- except smtplib.SMTPAuthenticationError, e:
- raise errors.BzrCommandError('SMTP server refused authentication: %d %s'
- % (e.smtp_code, e.smtp_error))
- except smtplib.SMTPException, e:
- raise errors.BzrCommandError(str(e))
-
- smtp.sendmail(user_from, [user_to], msg)
-
-
-def print_info(msg, server, user_from, user_to):
- print "Server: %s" % server
- print "%s" % msg
+ print message.as_string()
+ return
+
+ SMTPConnection(config).send_email(message)
=== modified file 'test_pqm_submit.py'
--- a/test_pqm_submit.py 2007-04-26 02:05:22 +0000
+++ b/test_pqm_submit.py 2007-10-25 09:17:56 +0000
@@ -15,12 +15,256 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Test cases for pqm submit."""
+import smtplib
+
+from bzrlib import (
+ config as _mod_config,
+ errors,
+ gpg,
+ )
from bzrlib.plugins.pqm import pqm_submit
-from bzrlib.tests import TestCase
-
-
-class TestMessage(TestCase):
-
- def test_newlines_errors(self):
+from bzrlib.tests import TestCaseWithMemoryTransport, TestCaseWithTransport
+
+
+EMAIL = """\
+From: "J. Random Hacker" <jrandom at example.com>
+Subject: commit message
+To: PQM <pqm at example.com>
+User-Agent: Bazaar \(.*\)
+
+-----BEGIN PSEUDO-SIGNED CONTENT-----
+star-merge .*/public/ http://example.com/submit
+-----END PSEUDO-SIGNED CONTENT-----
+"""
+
+
+class PQMSubmissionTests(TestCaseWithMemoryTransport):
+
+ def test_no_source_branch(self):
+ self.assertRaises(
+ errors.NoMergeSource, pqm_submit.PQMSubmission,
+ source_branch=None)
+
+ def test_newlines_in_message(self):
+ source_branch = self.make_branch('source')
self.assertRaises(pqm_submit.BadCommitMessage,
- pqm_submit._setup_headers, "foo\nbar", "me", "you")
+ pqm_submit.PQMSubmission,
+ source_branch=source_branch,
+ public_location='public-branch',
+ submit_location='submit-branch',
+ message='foo\nbar')
+
+ def test_check_public_branch(self):
+ tree = self.make_branch_and_memory_tree('source')
+ source_branch = tree.branch
+ public_branch = self.make_branch('public')
+
+ # Commit something to the source branch
+ tree.lock_write()
+ tree.add('')
+ tree.commit('message')
+ tree.unlock()
+
+ # Now the public branch is out of date:
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location=public_branch.base,
+ submit_location='submit-branch',
+ message='merge message')
+ self.assertRaises(errors.PublicBranchOutOfDate,
+ submission.check_public_branch)
+
+ # If we bring the public branch up to date, everything is fine.
+ public_branch.pull(source_branch)
+ submission.check_public_branch()
+
+ def test_check_public_branch_missing(self):
+ source_branch = self.make_branch('source')
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location=self.get_transport().abspath('public'),
+ submit_location='submit-branch',
+ message='merge message')
+ self.assertRaises(errors.NotBranchError,
+ submission.check_public_branch)
+
+ def test_to_lines(self):
+ source_branch = self.make_branch('source')
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location='public-branch',
+ submit_location='submit-branch',
+ message='commit message')
+ lines = submission.to_lines()
+ self.assertEqual(['star-merge public-branch submit-branch\n'], lines)
+
+ def test_to_signed(self):
+ source_branch = self.make_branch('source')
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location='public-branch',
+ submit_location='submit-branch',
+ message='commit message')
+ old_strategy = gpg.GPGStrategy
+ gpg.GPGStrategy = gpg.LoopbackGPGStrategy
+ try:
+ signed = submission.to_signed()
+ finally:
+ gpg.GPGStrategy = old_strategy
+ self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n'
+ 'star-merge public-branch submit-branch\n'
+ '-----END PSEUDO-SIGNED CONTENT-----\n', signed)
+
+ def test_to_email(self):
+ source_branch = self.make_branch('source')
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location='public-branch',
+ submit_location='submit-branch',
+ message='commit message')
+ message = submission.to_email('from at example.com', 'to at example.com',
+ sign=False)
+ self.assertEqual('from at example.com', message.get('From'))
+ self.assertEqual('to at example.com', message.get('To'))
+ self.assertEqual('commit message', message.get('Subject'))
+
+
+class PQMSubmissionLocationsTests(TestCaseWithTransport):
+
+ def test_find_public_branch(self):
+ source_branch = self.make_branch('source')
+ source_branch.set_public_branch('http://example.com/public')
+ # Also set the deprecated public_repository config item to
+ # show that public_branch is used in preference to it.
+ source_branch.get_config().set_user_option(
+ 'public_repository', 'bad-value')
+
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ submit_location='submit-branch',
+ message='commit message')
+ self.assertEqual('http://example.com/public',
+ submission.public_location)
+
+ def test_find_public_branch_from_repo(self):
+ # Test that public_location can be inferred from the obsolete
+ # "public_repository" config option.
+ source_repo = self.make_repository('repo', shared=True)
+ source_branch = self.make_bzrdir('repo/source').create_branch()
+
+ config = _mod_config.LocationConfig(
+ source_repo.bzrdir.root_transport.base)
+ config.set_user_option(
+ 'public_repository', 'http://example.com/repo',
+ store=_mod_config.STORE_LOCATION_NORECURSE)
+
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ submit_location='submit-branch',
+ message='commit message')
+ self.assertEqual('http://example.com/repo/source',
+ submission.public_location)
+
+ def test_find_public_branch_missing(self):
+ source_branch = self.make_branch('source')
+ self.assertRaises(
+ errors.BzrCommandError, pqm_submit.PQMSubmission,
+ source_branch=source_branch,
+ submit_location='submit-branch',
+ message='commit message')
+
+ def test_find_submit_branch(self):
+ source_branch = self.make_branch('source')
+ source_branch.set_submit_branch('http://example.com/submit')
+
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location='public-branch',
+ message='commit message')
+ self.assertEqual('http://example.com/submit',
+ submission.submit_location)
+
+ def test_find_submit_branch_from_pqm_branch(self):
+ # Test that submit_branch can be picked up from the obsolete
+ # pqm_branch config option.
+ source_branch = self.make_branch('source')
+ source_branch.get_config().set_user_option(
+ 'pqm_branch', 'http://example.com/submit')
+ # pqm_branch is used in preference to the submit_branch:
+ source_branch.set_submit_branch('bad-value')
+
+ submission = pqm_submit.PQMSubmission(
+ source_branch=source_branch,
+ public_location='public-branch',
+ message='commit message')
+ self.assertEqual('http://example.com/submit',
+ submission.submit_location)
+
+ def test_find_submit_branch_missing(self):
+ source_branch = self.make_branch('source')
+ self.assertRaises(
+ errors.NoSubmitBranch, pqm_submit.PQMSubmission,
+ source_branch=source_branch,
+ public_location='public-branch',
+ message='commit message')
+
+ def run_bzr_fakemail(self, *args, **kwargs):
+ # Run with fake smtplib and gpg stubs in place:
+ sendmail_calls = []
+ def sendmail(self, from_, to, message):
+ sendmail_calls.append((self, from_, to, message))
+ connect_calls = []
+ def connect(self, host='localhost', port=0):
+ connect_calls.append((self, host, port))
+ def ehlo(self):
+ return (200, 'Ok')
+ def has_extn(self):
+ return False
+ def starttls(self):
+ pass
+ old_sendmail = smtplib.SMTP.sendmail
+ smtplib.SMTP.sendmail = sendmail
+ old_connect = smtplib.SMTP.connect
+ smtplib.SMTP.connect = connect
+ old_ehlo = smtplib.SMTP.ehlo
+ smtplib.SMTP.ehlo = ehlo
+ old_has_extn = smtplib.SMTP.has_extn
+ smtplib.SMTP.has_extn = has_extn
+ old_starttls = smtplib.SMTP.starttls
+ smtplib.SMTP.starttls = starttls
+ old_strategy = gpg.GPGStrategy
+ gpg.GPGStrategy = gpg.LoopbackGPGStrategy
+ try:
+ result = self.run_bzr(*args, **kwargs)
+ finally:
+ smtplib.SMTP.sendmail = old_sendmail
+ smtplib.SMTP.connect = old_connect
+ smtplib.SMTP.ehlo = old_ehlo
+ smtplib.SMTP.has_extn = old_has_extn
+ smtplib.SMTP.starttls = old_starttls
+ gpg.GPGStrategy = old_strategy
+
+ return result + (connect_calls, sendmail_calls)
+
+ def test_pqm_submit(self):
+ source_branch = self.make_branch('source')
+ public_branch = self.make_branch('public')
+ source_branch.set_public_branch(public_branch.base)
+ source_branch.set_submit_branch('http://example.com/submit')
+ config = source_branch.get_config()
+ config.set_user_option('pqm_email', 'PQM <pqm at example.com>')
+ config.set_user_option(
+ 'email', 'J. Random Hacker <jrandom at example.com>')
+
+ out, err, connect_calls, sendmail_calls = \
+ self.run_bzr_fakemail(['pqm-submit', '-m', 'commit message',
+ './source'])
+ self.assertEqual('', out)
+ self.assertEqual(1, len(connect_calls))
+ call = connect_calls[0]
+ self.assertEqual(('localhost', 0), call[1:3])
+ self.assertEqual(1, len(sendmail_calls))
+ call = sendmail_calls[0]
+ self.assertEqual(('jrandom at example.com', ['pqm at example.com']),
+ call[1:3])
+ self.assertContainsRe(call[3], EMAIL)
More information about the bazaar-commits
mailing list