1# Copyright (C) 2005-2008, 2010 by Canonical Ltd
2#   Authors: Robert Collins <robert.collins@canonical.com>
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18from unittest import TestLoader
19
20from .... import (
21    config,
22    tests,
23    )
24from ....bzr.bzrdir import BzrDir
25from ....tests import TestCaseInTempDir
26from ..emailer import EmailSender
27
28
29def test_suite():
30    return TestLoader().loadTestsFromName(__name__)
31
32
33sample_config = (b"[DEFAULT]\n"
34                 b"post_commit_to=demo@example.com\n"
35                 b"post_commit_sender=Sample <foo@example.com>\n"
36                 b"revision_mail_headers=X-Cheese: to the rescue!\n")
37
38unconfigured_config = (b"[DEFAULT]\n"
39                       b"email=Robert <foo@example.com>\n")
40
41sender_configured_config = (b"[DEFAULT]\n"
42                            b"post_commit_sender=Sample <foo@example.com>\n")
43
44to_configured_config = (b"[DEFAULT]\n"
45                        b"post_commit_to=Sample <foo@example.com>\n")
46
47multiple_to_configured_config = (b"[DEFAULT]\n"
48                                 b"post_commit_sender=Sender <from@example.com>\n"
49                                 b"post_commit_to=Sample <foo@example.com>, Other <baz@bar.com>\n")
50
51customized_mail_config = (b"[DEFAULT]\n"
52                          b"post_commit_to=demo@example.com\n"
53                          b"post_commit_sender=Sample <foo@example.com>\n"
54                          b"post_commit_subject=[commit] $message\n"
55                          b"post_commit_body='''$committer has committed "
56                          b"revision 1 at $url.\n\n'''\n")
57
58push_config = (b"[DEFAULT]\n"
59               b"post_commit_to=demo@example.com\n"
60               b"post_commit_push_pull=True\n")
61
62with_url_config = (b"[DEFAULT]\n"
63                   b"post_commit_url=http://some.fake/url/\n"
64                   b"post_commit_to=demo@example.com\n"
65                   b"post_commit_sender=Sample <foo@example.com>\n")
66
67# FIXME: this should not use a literal log, rather grab one from breezy.log
68sample_log = ('------------------------------------------------------------\n'
69              'revno: 1\n'
70              'revision-id: A\n'
71              'committer: Sample <john@example.com>\n'
72              'branch nick: work\n'
73              'timestamp: Thu 1970-01-01 00:00:01 +0000\n'
74              'message:\n'
75              '  foo bar baz\n'
76              '  fuzzy\n'
77              '  wuzzy\n')
78
79
80class TestGetTo(TestCaseInTempDir):
81
82    def test_body(self):
83        sender = self.get_sender()
84        self.assertEqual('At %s\n\n%s' % (sender.url(), sample_log),
85                         sender.body())
86
87    def test_custom_body(self):
88        sender = self.get_sender(customized_mail_config)
89        self.assertEqual('%s has committed revision 1 at %s.\n\n%s' %
90                         (sender.revision.committer, sender.url(), sample_log),
91                         sender.body())
92
93    def test_command_line(self):
94        sender = self.get_sender()
95        self.assertEqual(['mail', '-s', sender.subject(), '-a',
96                          'From: ' + sender.from_address()] + sender.to(),
97                         sender._command_line())
98
99    def test_to(self):
100        sender = self.get_sender()
101        self.assertEqual(['demo@example.com'], sender.to())
102
103    def test_from(self):
104        sender = self.get_sender()
105        self.assertEqual('Sample <foo@example.com>', sender.from_address())
106
107    def test_from_default(self):
108        sender = self.get_sender(unconfigured_config)
109        self.assertEqual('Robert <foo@example.com>', sender.from_address())
110
111    def test_should_send(self):
112        sender = self.get_sender()
113        self.assertEqual(True, sender.should_send())
114
115    def test_should_not_send(self):
116        sender = self.get_sender(unconfigured_config)
117        self.assertEqual(False, sender.should_send())
118
119    def test_should_not_send_sender_configured(self):
120        sender = self.get_sender(sender_configured_config)
121        self.assertEqual(False, sender.should_send())
122
123    def test_should_not_send_to_configured(self):
124        sender = self.get_sender(to_configured_config)
125        self.assertEqual(True, sender.should_send())
126
127    def test_send_to_multiple(self):
128        sender = self.get_sender(multiple_to_configured_config)
129        self.assertEqual([u'Sample <foo@example.com>', u'Other <baz@bar.com>'],
130                         sender.to())
131        self.assertEqual([u'Sample <foo@example.com>', u'Other <baz@bar.com>'],
132                         sender._command_line()[-2:])
133
134    def test_url_set(self):
135        sender = self.get_sender(with_url_config)
136        self.assertEqual(sender.url(), 'http://some.fake/url/')
137
138    def test_public_url_set(self):
139        config = (b"[DEFAULT]\n"
140                  b"public_branch=http://the.publication/location/\n")
141        sender = self.get_sender(config)
142        self.assertEqual(sender.url(), 'http://the.publication/location/')
143
144    def test_url_precedence(self):
145        config = (b"[DEFAULT]\n"
146                  b"post_commit_url=http://some.fake/url/\n"
147                  b"public_branch=http://the.publication/location/\n")
148        sender = self.get_sender(config)
149        self.assertEqual(sender.url(), 'http://some.fake/url/')
150
151    def test_url_unset(self):
152        sender = self.get_sender()
153        self.assertEqual(sender.url(), sender.branch.base)
154
155    def test_subject(self):
156        sender = self.get_sender()
157        self.assertEqual("Rev 1: foo bar baz in %s" %
158                         sender.branch.base,
159                         sender.subject())
160
161    def test_custom_subject(self):
162        sender = self.get_sender(customized_mail_config)
163        self.assertEqual("[commit] %s" %
164                         sender.revision.get_summary(),
165                         sender.subject())
166
167    def test_diff_filename(self):
168        sender = self.get_sender()
169        self.assertEqual('patch-1.diff', sender.diff_filename())
170
171    def test_headers(self):
172        sender = self.get_sender()
173        self.assertEqual({'X-Cheese': 'to the rescue!'},
174                         sender.extra_headers())
175
176    def get_sender(self, text=sample_config):
177        my_config = config.MemoryStack(text)
178        self.branch = BzrDir.create_branch_convenience('.')
179        tree = self.branch.controldir.open_workingtree()
180        tree.commit('foo bar baz\nfuzzy\nwuzzy', rev_id=b'A',
181                    allow_pointless=True,
182                    timestamp=1,
183                    timezone=0,
184                    committer="Sample <john@example.com>",
185                    )
186        sender = EmailSender(self.branch, b'A', my_config)
187        # This is usually only done after the EmailSender has locked the branch
188        # and repository during send(), however, for testing, we need to do it
189        # earlier, since send() is not called.
190        sender._setup_revision_and_revno()
191        return sender
192
193
194class TestEmailerWithLocal(tests.TestCaseWithTransport):
195    """Test that Emailer will use a local branch if supplied."""
196
197    def test_local_has_revision(self):
198        master_tree = self.make_branch_and_tree('master')
199        self.build_tree(['master/a'])
200        master_tree.add('a')
201        master_tree.commit('a')
202
203        child_tree = master_tree.controldir.sprout('child').open_workingtree()
204        child_tree.branch.bind(master_tree.branch)
205
206        self.build_tree(['child/b'])
207        child_tree.add(['b'])
208        revision_id = child_tree.commit('b')
209
210        sender = EmailSender(master_tree.branch, revision_id,
211                             master_tree.branch.get_config(),
212                             local_branch=child_tree.branch)
213
214        # Make sure we are using the 'local_branch' repository, and not the
215        # remote one.
216        self.assertIs(child_tree.branch.repository, sender.repository)
217
218    def test_local_missing_revision(self):
219        master_tree = self.make_branch_and_tree('master')
220        self.build_tree(['master/a'])
221        master_tree.add('a')
222        master_tree.commit('a')
223
224        child_tree = master_tree.controldir.sprout('child').open_workingtree()
225        child_tree.branch.bind(master_tree.branch)
226
227        self.build_tree(['master/c'])
228        master_tree.add(['c'])
229        revision_id = master_tree.commit('c')
230
231        self.assertFalse(
232            child_tree.branch.repository.has_revision(revision_id))
233        sender = EmailSender(master_tree.branch, revision_id,
234                             master_tree.branch.get_config(),
235                             local_branch=child_tree.branch)
236        # We should be using the master repository here, because the child
237        # repository doesn't contain the revision.
238        self.assertIs(master_tree.branch.repository, sender.repository)
239