/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6404.6.1 by Vincent Ladeuil
Tests passing for a first rough version of a cached branch config store. The changes here are too invasive and several parallel proposals have been made.
1
# Copyright (C) 2007, 2008, 2009, 2011, 2012 Canonical Ltd
1551.12.36 by Aaron Bentley
Fix failing tests
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1551.12.36 by Aaron Bentley
Fix failing tests
16
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
17
import re
1551.12.36 by Aaron Bentley
Fix failing tests
18
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
19
from bzrlib import (
20
    errors,
1551.12.16 by Aaron Bentley
Enable signing merge directives
21
    gpg,
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
22
    mail_client,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
23
    merge_directive,
24
    tests,
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
25
    trace,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
26
    )
27
1551.12.4 by Aaron Bentley
Add failing test
28
1551.12.45 by Aaron Bentley
Change format marker to not experimental
29
OUTPUT1 = """# Bazaar merge directive format 1
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
30
# revision_id: example:
31
# target_branch: http://example.com
32
# testament_sha1: sha
33
# timestamp: 1970-01-01 00:09:33 +0002
34
#\x20
35
booga"""
36
2687.2.2 by Martin Pool
Fix up other references to 0.19
37
OUTPUT1_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
2520.4.73 by Aaron Bentley
Implement new merge directive format
38
# revision_id: example:
39
# target_branch: http://example.com
40
# testament_sha1: sha
41
# timestamp: 1970-01-01 00:09:33 +0002
2520.4.105 by Aaron Bentley
Implement patch verification
42
# base_revision_id: null:
2520.4.73 by Aaron Bentley
Implement new merge directive format
43
#\x20
44
# Begin bundle
45
booga"""
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
46
1551.12.45 by Aaron Bentley
Change format marker to not experimental
47
OUTPUT2 = """# Bazaar merge directive format 1
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
48
# revision_id: example:
49
# target_branch: http://example.com
50
# testament_sha1: sha
51
# timestamp: 1970-01-01 00:09:33 +0002
52
# source_branch: http://example.org
53
# message: Hi mom!
54
#\x20
55
booga"""
56
2687.2.2 by Martin Pool
Fix up other references to 0.19
57
OUTPUT2_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
2520.4.73 by Aaron Bentley
Implement new merge directive format
58
# revision_id: example:
59
# target_branch: http://example.com
60
# testament_sha1: sha
61
# timestamp: 1970-01-01 00:09:33 +0002
62
# source_branch: http://example.org
63
# message: Hi mom!
2520.4.105 by Aaron Bentley
Implement patch verification
64
# base_revision_id: null:
2520.4.73 by Aaron Bentley
Implement new merge directive format
65
#\x20
66
# Begin patch
67
booga"""
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
68
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
69
INPUT1 = """
70
I was thinking today about creating a merge directive.
71
72
So I did.
73
74
Here it is.
75
76
(I've pasted it in the body of this message)
77
78
Aaron
79
80
# Bazaar merge directive format 1\r
81
# revision_id: example:
82
# target_branch: http://example.com
83
# testament_sha1: sha
84
# timestamp: 1970-01-01 00:09:33 +0002
85
# source_branch: http://example.org
86
# message: Hi mom!
87
#\x20
88
booga""".splitlines(True)
89
90
2520.4.73 by Aaron Bentley
Implement new merge directive format
91
INPUT1_2 = """
92
I was thinking today about creating a merge directive.
93
94
So I did.
95
96
Here it is.
97
98
(I've pasted it in the body of this message)
99
100
Aaron
101
2687.2.2 by Martin Pool
Fix up other references to 0.19
102
# Bazaar merge directive format 2 (Bazaar 0.90)\r
2520.4.73 by Aaron Bentley
Implement new merge directive format
103
# revision_id: example:
104
# target_branch: http://example.com
105
# testament_sha1: sha
106
# timestamp: 1970-01-01 00:09:33 +0002
107
# source_branch: http://example.org
2520.4.105 by Aaron Bentley
Implement patch verification
108
# base_revision_id: null:
2520.4.73 by Aaron Bentley
Implement new merge directive format
109
# message: Hi mom!
110
#\x20
111
# Begin patch
112
booga""".splitlines(True)
113
114
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
115
INPUT1_2_OLD = """
116
I was thinking today about creating a merge directive.
117
118
So I did.
119
120
Here it is.
121
122
(I've pasted it in the body of this message)
123
124
Aaron
125
126
# Bazaar merge directive format 2 (Bazaar 0.19)\r
127
# revision_id: example:
128
# target_branch: http://example.com
129
# testament_sha1: sha
130
# timestamp: 1970-01-01 00:09:33 +0002
131
# source_branch: http://example.org
132
# base_revision_id: null:
133
# message: Hi mom!
134
#\x20
135
# Begin patch
136
booga""".splitlines(True)
137
2694.1.2 by Aaron Bentley
Fix whitespace
138
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
139
OLD_DIRECTIVE_2 = """# Bazaar merge directive format 2 (Bazaar 0.19)
140
# revision_id: abentley@panoramicfeedback.com-20070807234458-\
141
#   nzhkoyza56lan7z5
142
# target_branch: http://panoramicfeedback.com/opensource/bzr/repo\
143
#   /bzr.ab
144
# testament_sha1: d825a5cdb267a90ec2ba86b00895f3d8a9bed6bf
145
# timestamp: 2007-08-10 16:15:02 -0400
146
# source_branch: http://panoramicfeedback.com/opensource/bzr/repo\
147
#   /bzr.ab
148
# base_revision_id: abentley@panoramicfeedback.com-20070731163346-\
149
#   623xwcycwij91xen
150
#
151
""".splitlines(True)
152
153
2520.4.73 by Aaron Bentley
Implement new merge directive format
154
class TestMergeDirective(object):
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
155
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
156
    def test_merge_source(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
157
        time = 500000.0
158
        timezone = 5 * 3600
2520.4.73 by Aaron Bentley
Implement new merge directive format
159
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
160
            'example:', 'sha', time, timezone, 'http://example.com')
2520.4.73 by Aaron Bentley
Implement new merge directive format
161
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
162
            'example:', 'sha', time, timezone, 'http://example.com',
163
            patch_type='diff')
2520.4.73 by Aaron Bentley
Implement new merge directive format
164
        self.make_merge_directive('example:', 'sha', time, timezone,
1551.12.13 by Aaron Bentley
Rename fields
165
            'http://example.com', source_branch='http://example.org')
2520.4.73 by Aaron Bentley
Implement new merge directive format
166
        md = self.make_merge_directive('null:', 'sha', time, timezone,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
167
            'http://example.com', patch='blah', patch_type='bundle')
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
168
        self.assertIs(None, md.source_branch)
2520.4.73 by Aaron Bentley
Implement new merge directive format
169
        md2 = self.make_merge_directive('null:', 'sha', time, timezone,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
170
            'http://example.com', patch='blah', patch_type='bundle',
171
            source_branch='bar')
172
        self.assertEqual('bar', md2.source_branch)
173
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
174
    def test_serialization(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
175
        time = 453
176
        timezone = 120
2520.4.73 by Aaron Bentley
Implement new merge directive format
177
        md = self.make_merge_directive('example:', 'sha', time, timezone,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
178
            'http://example.com', patch='booga', patch_type='bundle')
2520.4.73 by Aaron Bentley
Implement new merge directive format
179
        self.assertEqualDiff(self.OUTPUT1, ''.join(md.to_lines()))
180
        md = self.make_merge_directive('example:', 'sha', time, timezone,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
181
            'http://example.com', source_branch="http://example.org",
182
            patch='booga', patch_type='diff', message="Hi mom!")
2520.4.73 by Aaron Bentley
Implement new merge directive format
183
        self.assertEqualDiff(self.OUTPUT2, ''.join(md.to_lines()))
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
184
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
185
    def test_deserialize_junk(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
186
        time = 501
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
187
        self.assertRaises(errors.NotAMergeDirective,
188
                          merge_directive.MergeDirective.from_lines, 'lala')
189
1551.12.59 by Aaron Bentley
Correctly handle empty merge directive texts
190
    def test_deserialize_empty(self):
191
        self.assertRaises(errors.NotAMergeDirective,
192
                          merge_directive.MergeDirective.from_lines, [])
193
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
194
    def test_deserialize_leading_junk(self):
2520.4.73 by Aaron Bentley
Implement new merge directive format
195
        md = merge_directive.MergeDirective.from_lines(self.INPUT1)
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
196
        self.assertEqual('example:', md.revision_id)
197
        self.assertEqual('sha', md.testament_sha1)
198
        self.assertEqual('http://example.com', md.target_branch)
199
        self.assertEqual('http://example.org', md.source_branch)
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
200
        self.assertEqual(453, md.time)
201
        self.assertEqual(120, md.timezone)
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
202
        self.assertEqual('booga', md.patch)
203
        self.assertEqual('diff', md.patch_type)
204
        self.assertEqual('Hi mom!', md.message)
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
205
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
206
    def test_roundtrip(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
207
        time = 500000
208
        timezone = 7.5 * 3600
2520.4.73 by Aaron Bentley
Implement new merge directive format
209
        md = self.make_merge_directive('example:', 'sha', time, timezone,
1551.12.13 by Aaron Bentley
Rename fields
210
            'http://example.com', source_branch="http://example.org",
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
211
            patch='booga', patch_type='diff')
212
        md2 = merge_directive.MergeDirective.from_lines(md.to_lines())
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
213
        self.assertEqual('example:', md2.revision_id)
1551.12.54 by Aaron Bentley
Decoded revision ids are utf-8
214
        self.assertIsInstance(md2.revision_id, str)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
215
        self.assertEqual('sha', md2.testament_sha1)
1551.12.13 by Aaron Bentley
Rename fields
216
        self.assertEqual('http://example.com', md2.target_branch)
217
        self.assertEqual('http://example.org', md2.source_branch)
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
218
        self.assertEqual(time, md2.time)
219
        self.assertEqual(timezone, md2.timezone)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
220
        self.assertEqual('diff', md2.patch_type)
221
        self.assertEqual('booga', md2.patch)
1551.12.26 by Aaron Bentley
Get email working, with optional message
222
        self.assertEqual(None, md2.message)
2520.4.73 by Aaron Bentley
Implement new merge directive format
223
        self.set_bundle(md, "# Bazaar revision bundle v0.9\n#\n")
1551.12.26 by Aaron Bentley
Get email working, with optional message
224
        md.message = "Hi mom!"
2520.4.73 by Aaron Bentley
Implement new merge directive format
225
        lines = md.to_lines()
226
        md3 = merge_directive.MergeDirective.from_lines(lines)
227
        self.assertEqual("# Bazaar revision bundle v0.9\n#\n", md3.bundle)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
228
        self.assertEqual("bundle", md3.patch_type)
1551.12.12 by Aaron Bentley
Add format header
229
        self.assertContainsRe(md3.to_lines()[0],
230
            '^# Bazaar merge directive format ')
1551.12.26 by Aaron Bentley
Get email working, with optional message
231
        self.assertEqual("Hi mom!", md3.message)
2520.4.73 by Aaron Bentley
Implement new merge directive format
232
        md3.clear_payload()
2520.4.80 by Aaron Bentley
Improve merge directive tests
233
        self.assertIs(None, md3.get_raw_bundle())
1551.12.53 by Aaron Bentley
Fix deserialization of merge directives with no patch
234
        md4 = merge_directive.MergeDirective.from_lines(md3.to_lines())
235
        self.assertIs(None, md4.patch_type)
1551.12.26 by Aaron Bentley
Get email working, with optional message
236
237
2520.4.73 by Aaron Bentley
Implement new merge directive format
238
class TestMergeDirective1(tests.TestCase, TestMergeDirective):
239
    """Test merge directive format 1"""
240
241
    INPUT1 = INPUT1
242
243
    OUTPUT1 = OUTPUT1
244
245
    OUTPUT2 = OUTPUT2
246
247
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
248
                 target_branch, patch=None, patch_type=None,
249
                 source_branch=None, message=None):
250
        return merge_directive.MergeDirective(revision_id, testament_sha1,
251
                 time, timezone, target_branch, patch, patch_type,
252
                 source_branch, message)
253
254
    @staticmethod
255
    def set_bundle(md, value):
256
        md.patch = value
257
258
    def test_require_patch(self):
259
        time = 500.0
260
        timezone = 120
261
        self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
262
            'example:', 'sha', time, timezone, 'http://example.com',
263
            patch_type='bundle')
264
        md = merge_directive.MergeDirective('example:', 'sha1', time, timezone,
265
            'http://example.com', source_branch="http://example.org",
266
            patch='', patch_type='diff')
267
        self.assertEqual(md.patch, '')
268
269
270
class TestMergeDirective2(tests.TestCase, TestMergeDirective):
271
    """Test merge directive format 2"""
272
273
    INPUT1 = INPUT1_2
274
275
    OUTPUT1 = OUTPUT1_2
276
277
    OUTPUT2 = OUTPUT2_2
278
279
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
280
                 target_branch, patch=None, patch_type=None,
2520.4.105 by Aaron Bentley
Implement patch verification
281
                 source_branch=None, message=None, base_revision_id='null:'):
2520.4.73 by Aaron Bentley
Implement new merge directive format
282
        if patch_type == 'bundle':
283
            bundle = patch
284
            patch = None
285
        else:
286
            bundle = None
287
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
288
            time, timezone, target_branch, patch, source_branch, message,
2520.4.105 by Aaron Bentley
Implement patch verification
289
            bundle, base_revision_id)
2520.4.73 by Aaron Bentley
Implement new merge directive format
290
291
    @staticmethod
292
    def set_bundle(md, value):
293
        md.bundle = value
294
295
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
296
EMAIL1 = """From: "J. Random Hacker" <jrandom@example.com>
1551.12.26 by Aaron Bentley
Get email working, with optional message
297
Subject: Commit of rev2a
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
298
To: pqm@example.com
299
User-Agent: Bazaar \(.*\)
1551.12.26 by Aaron Bentley
Get email working, with optional message
300
1551.12.45 by Aaron Bentley
Change format marker to not experimental
301
# Bazaar merge directive format 1
1551.12.26 by Aaron Bentley
Get email working, with optional message
302
# revision_id: rev2a
303
# target_branch: (.|\n)*
304
# testament_sha1: .*
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
305
# timestamp: 1970-01-01 00:08:56 \\+0001
1551.12.26 by Aaron Bentley
Get email working, with optional message
306
# source_branch: (.|\n)*
307
"""
308
309
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
310
EMAIL1_2 = """From: "J. Random Hacker" <jrandom@example.com>
2520.4.80 by Aaron Bentley
Improve merge directive tests
311
Subject: Commit of rev2a
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
312
To: pqm@example.com
313
User-Agent: Bazaar \(.*\)
2520.4.80 by Aaron Bentley
Improve merge directive tests
314
2687.2.2 by Martin Pool
Fix up other references to 0.19
315
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
2520.4.80 by Aaron Bentley
Improve merge directive tests
316
# revision_id: rev2a
317
# target_branch: (.|\n)*
318
# testament_sha1: .*
319
# timestamp: 1970-01-01 00:08:56 \\+0001
320
# source_branch: (.|\n)*
321
"""
322
323
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
324
EMAIL2 = """From: "J. Random Hacker" <jrandom@example.com>
1551.12.26 by Aaron Bentley
Get email working, with optional message
325
Subject: Commit of rev2a with special message
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
326
To: pqm@example.com
327
User-Agent: Bazaar \(.*\)
1551.12.26 by Aaron Bentley
Get email working, with optional message
328
1551.12.45 by Aaron Bentley
Change format marker to not experimental
329
# Bazaar merge directive format 1
1551.12.26 by Aaron Bentley
Get email working, with optional message
330
# revision_id: rev2a
331
# target_branch: (.|\n)*
332
# testament_sha1: .*
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
333
# timestamp: 1970-01-01 00:08:56 \\+0001
1551.12.26 by Aaron Bentley
Get email working, with optional message
334
# source_branch: (.|\n)*
335
# message: Commit of rev2a with special message
336
"""
1551.12.4 by Aaron Bentley
Add failing test
337
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
338
EMAIL2_2 = """From: "J. Random Hacker" <jrandom@example.com>
2520.4.80 by Aaron Bentley
Improve merge directive tests
339
Subject: Commit of rev2a with special message
2625.6.2 by Adeodato Simó
Merge bzr.dev, resolving conflicts and updating test_merge_directive.py.
340
To: pqm@example.com
341
User-Agent: Bazaar \(.*\)
2520.4.80 by Aaron Bentley
Improve merge directive tests
342
2687.2.2 by Martin Pool
Fix up other references to 0.19
343
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
2520.4.80 by Aaron Bentley
Improve merge directive tests
344
# revision_id: rev2a
345
# target_branch: (.|\n)*
346
# testament_sha1: .*
347
# timestamp: 1970-01-01 00:08:56 \\+0001
348
# source_branch: (.|\n)*
349
# message: Commit of rev2a with special message
350
"""
1551.12.4 by Aaron Bentley
Add failing test
351
2520.4.73 by Aaron Bentley
Implement new merge directive format
352
class TestMergeDirectiveBranch(object):
1551.12.4 by Aaron Bentley
Add failing test
353
1551.12.26 by Aaron Bentley
Get email working, with optional message
354
    def make_trees(self):
1551.12.4 by Aaron Bentley
Add failing test
355
        tree_a = self.make_branch_and_tree('tree_a')
6421.3.1 by Vincent Ladeuil
Migrate more branch options to config stacks.
356
        tree_a.branch.get_config_stack().set(
357
            'email', 'J. Random Hacker <jrandom@example.com>')
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
358
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_b\n'),
359
                                  ('tree_a/file_2', 'content_x\rcontent_y\r')])
360
        tree_a.add(['file', 'file_2'])
1551.12.4 by Aaron Bentley
Add failing test
361
        tree_a.commit('message', rev_id='rev1')
362
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
363
        branch_c = tree_a.bzrdir.sprout('branch_c').open_branch()
1551.12.4 by Aaron Bentley
Add failing test
364
        tree_b.commit('message', rev_id='rev2b')
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
365
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_c \n'),
366
                                  ('tree_a/file_2', 'content_x\rcontent_z\r')])
1551.12.26 by Aaron Bentley
Get email working, with optional message
367
        tree_a.commit('Commit of rev2a', rev_id='rev2a')
368
        return tree_a, tree_b, branch_c
369
2490.2.28 by Aaron Bentley
Fix handling of null revision
370
    def test_empty_target(self):
371
        tree_a, tree_b, branch_c = self.make_trees()
372
        tree_d = self.make_branch_and_tree('tree_d')
2520.4.73 by Aaron Bentley
Implement new merge directive format
373
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
374
            tree_d.branch.base, patch_type='diff',
375
            public_branch=tree_a.branch.base)
2490.2.28 by Aaron Bentley
Fix handling of null revision
376
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
377
    def test_disk_name(self):
378
        tree_a, tree_b, branch_c = self.make_trees()
3449.4.1 by Lukáš Lalinský
Sanitize branch nick before using it as an attachment filename in ``bzr send``
379
        tree_a.branch.nick = 'fancy <name>'
3251.2.1 by Aaron Bentley
Use nick/revno-based names for merge directives
380
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
381
            tree_b.branch.base)
382
        self.assertEqual('fancy-name-2', md.get_disk_name(tree_a.branch))
383
384
    def test_disk_name_old_revno(self):
385
        tree_a, tree_b, branch_c = self.make_trees()
386
        tree_a.branch.nick = 'fancy-name'
387
        md = self.from_objects(tree_a.branch.repository, 'rev1', 500, 120,
388
            tree_b.branch.base)
389
        self.assertEqual('fancy-name-1', md.get_disk_name(tree_a.branch))
390
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
391
    def test_generate_patch(self):
392
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.73 by Aaron Bentley
Implement new merge directive format
393
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
394
            tree_b.branch.base, patch_type='diff',
395
            public_branch=tree_a.branch.base)
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
396
        self.assertNotContainsRe(md2.patch, 'Bazaar revision bundle')
397
        self.assertContainsRe(md2.patch, '\\+content_c')
398
        self.assertNotContainsRe(md2.patch, '\\+\\+\\+ b/')
399
        self.assertContainsRe(md2.patch, '\\+\\+\\+ file')
400
401
    def test_public_branch(self):
1551.12.26 by Aaron Bentley
Get email working, with optional message
402
        tree_a, tree_b, branch_c = self.make_trees()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
403
        self.assertRaises(errors.PublicBranchOutOfDate,
2520.4.73 by Aaron Bentley
Implement new merge directive format
404
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
405
            tree_b.branch.base, public_branch=branch_c.base, patch_type='diff')
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
406
        self.assertRaises(errors.PublicBranchOutOfDate,
407
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
408
            tree_b.branch.base, public_branch=branch_c.base, patch_type=None)
1551.12.34 by Aaron Bentley
Check public branch only if not using a bundle
409
        # public branch is not checked if patch format is bundle.
2520.4.73 by Aaron Bentley
Implement new merge directive format
410
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
411
            tree_b.branch.base, public_branch=branch_c.base)
1551.12.34 by Aaron Bentley
Check public branch only if not using a bundle
412
        # public branch is provided with a bundle, despite possibly being out
413
        # of date, because it's not required if a bundle is present.
414
        self.assertEqual(md1.source_branch, branch_c.base)
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
415
        # Once we update the public branch, we can generate a diff.
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
416
        branch_c.pull(tree_a.branch)
2520.4.73 by Aaron Bentley
Implement new merge directive format
417
        md3 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
418
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
419
1551.12.50 by Aaron Bentley
Use public location of submit branch if possible
420
    def test_use_public_submit_branch(self):
421
        tree_a, tree_b, branch_c = self.make_trees()
422
        branch_c.pull(tree_a.branch)
2520.4.80 by Aaron Bentley
Improve merge directive tests
423
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
424
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
1551.12.50 by Aaron Bentley
Use public location of submit branch if possible
425
        self.assertEqual(md.target_branch, tree_b.branch.base)
6404.6.1 by Vincent Ladeuil
Tests passing for a first rough version of a cached branch config store. The changes here are too invasive and several parallel proposals have been made.
426
        tree_b.branch.lock_write()
1551.12.50 by Aaron Bentley
Use public location of submit branch if possible
427
        tree_b.branch.set_public_branch('http://example.com')
6404.6.1 by Vincent Ladeuil
Tests passing for a first rough version of a cached branch config store. The changes here are too invasive and several parallel proposals have been made.
428
        tree_b.branch.unlock()
2520.4.80 by Aaron Bentley
Improve merge directive tests
429
        md2 = self.from_objects(
1551.12.50 by Aaron Bentley
Use public location of submit branch if possible
430
              tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
431
              patch_type=None, public_branch=branch_c.base)
432
        self.assertEqual(md2.target_branch, 'http://example.com')
433
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
434
    def test_message(self):
435
        tree_a, tree_b, branch_c = self.make_trees()
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
436
        md3 = self.from_objects(tree_a.branch.repository, 'rev1', 500, 120,
2520.4.80 by Aaron Bentley
Improve merge directive tests
437
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base,
1551.12.33 by Aaron Bentley
Take public_branch as a string, not object
438
            message='Merge message')
1551.12.7 by Aaron Bentley
Fix use of public location/branch
439
        md3.to_lines()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
440
        self.assertIs(None, md3.patch)
1551.12.27 by Aaron Bentley
support custom message everywhere
441
        self.assertEqual('Merge message', md3.message)
1551.12.16 by Aaron Bentley
Enable signing merge directives
442
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
443
    def test_generate_bundle(self):
1551.12.40 by Aaron Bentley
Do not show prefixes in diffs
444
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.80 by Aaron Bentley
Improve merge directive tests
445
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
446
            tree_b.branch.base, public_branch=branch_c.base)
447
448
        self.assertContainsRe(md1.get_raw_bundle(), 'Bazaar revision bundle')
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
449
        self.assertContainsRe(md1.patch, '\\+content_c')
450
        self.assertNotContainsRe(md1.patch, '\\+content_a')
451
        self.assertContainsRe(md1.patch, '\\+content_c')
452
        self.assertNotContainsRe(md1.patch, '\\+content_a')
1551.12.40 by Aaron Bentley
Do not show prefixes in diffs
453
1551.15.29 by Aaron Bentley
Make merge directives robust against broken bundles
454
    def test_broken_bundle(self):
455
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.73 by Aaron Bentley
Implement new merge directive format
456
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
457
            tree_b.branch.base, public_branch=branch_c.base)
1551.15.29 by Aaron Bentley
Make merge directives robust against broken bundles
458
        lines = md1.to_lines()
459
        lines = [l.replace('\n', '\r\n') for l in lines]
460
        md2 = merge_directive.MergeDirective.from_lines(lines)
461
        self.assertEqual('rev2a', md2.revision_id)
462
1551.12.16 by Aaron Bentley
Enable signing merge directives
463
    def test_signing(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
464
        time = 453
465
        timezone = 7200
1551.12.16 by Aaron Bentley
Enable signing merge directives
466
        class FakeBranch(object):
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
467
            def get_config_stack(self):
1551.12.16 by Aaron Bentley
Enable signing merge directives
468
                return self
469
            def gpg_signing_command(self):
470
                return 'loopback'
2520.4.80 by Aaron Bentley
Improve merge directive tests
471
        md = self.make_merge_directive('example:', 'sha', time, timezone,
1551.12.16 by Aaron Bentley
Enable signing merge directives
472
            'http://example.com', source_branch="http://example.org",
473
            patch='booga', patch_type='diff')
474
        old_strategy = gpg.GPGStrategy
475
        gpg.GPGStrategy = gpg.LoopbackGPGStrategy
476
        try:
477
            signed = md.to_signed(FakeBranch())
478
        finally:
479
            gpg.GPGStrategy = old_strategy
480
        self.assertContainsRe(signed, '^-----BEGIN PSEUDO-SIGNED CONTENT')
481
        self.assertContainsRe(signed, 'example.org')
482
        self.assertContainsRe(signed, 'booga')
1551.12.26 by Aaron Bentley
Get email working, with optional message
483
484
    def test_email(self):
485
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.80 by Aaron Bentley
Improve merge directive tests
486
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 476, 60,
487
            tree_b.branch.base, patch_type=None,
488
            public_branch=tree_a.branch.base)
1551.12.26 by Aaron Bentley
Get email working, with optional message
489
        message = md.to_email('pqm@example.com', tree_a.branch)
2520.4.80 by Aaron Bentley
Improve merge directive tests
490
        self.assertContainsRe(message.as_string(), self.EMAIL1)
1551.12.26 by Aaron Bentley
Get email working, with optional message
491
        md.message = 'Commit of rev2a with special message'
492
        message = md.to_email('pqm@example.com', tree_a.branch)
2520.4.80 by Aaron Bentley
Improve merge directive tests
493
        self.assertContainsRe(message.as_string(), self.EMAIL2)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
494
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
495
    def test_install_revisions_branch(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
496
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.80 by Aaron Bentley
Improve merge directive tests
497
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
498
            tree_b.branch.base, patch_type=None,
499
            public_branch=tree_a.branch.base)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
500
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
501
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
502
        self.assertEqual('rev2a', revision)
503
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
504
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
505
    def test_get_merge_request(self):
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
506
        tree_a, tree_b, branch_c = self.make_trees()
507
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
508
            tree_b.branch.base, patch_type='bundle',
509
            public_branch=tree_a.branch.base)
510
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
511
        md.install_revisions(tree_b.branch.repository)
512
        base, revision, verified = md.get_merge_request(
513
            tree_b.branch.repository)
514
        if isinstance(md, merge_directive.MergeDirective):
515
            self.assertIs(None, base)
516
            self.assertEqual('inapplicable', verified)
517
        else:
518
            self.assertEqual('rev1', base)
519
            self.assertEqual('verified', verified)
520
        self.assertEqual('rev2a', revision)
521
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
522
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
523
            tree_b.branch.base, patch_type=None,
524
            public_branch=tree_a.branch.base)
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
525
        base, revision, verified = md.get_merge_request(
526
            tree_b.branch.repository)
527
        if isinstance(md, merge_directive.MergeDirective):
528
            self.assertIs(None, base)
529
            self.assertEqual('inapplicable', verified)
530
        else:
531
            self.assertEqual('rev1', base)
532
            self.assertEqual('inapplicable', verified)
533
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
534
            tree_b.branch.base, patch_type='diff',
535
            public_branch=tree_a.branch.base)
536
        base, revision, verified = md.get_merge_request(
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
537
            tree_b.branch.repository)
538
        if isinstance(md, merge_directive.MergeDirective):
539
            self.assertIs(None, base)
540
            self.assertEqual('inapplicable', verified)
541
        else:
542
            self.assertEqual('rev1', base)
543
            self.assertEqual('verified', verified)
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
544
        md.patch='asdf'
545
        base, revision, verified = md.get_merge_request(
546
            tree_b.branch.repository)
547
        if isinstance(md, merge_directive.MergeDirective):
548
            self.assertIs(None, base)
549
            self.assertEqual('inapplicable', verified)
550
        else:
551
            self.assertEqual('rev1', base)
2520.7.1 by Aaron Bentley
Reactivate patch verification
552
            self.assertEqual('failed', verified)
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
553
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
554
    def test_install_revisions_bundle(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
555
        tree_a, tree_b, branch_c = self.make_trees()
2520.4.80 by Aaron Bentley
Improve merge directive tests
556
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
557
            tree_b.branch.base, patch_type='bundle',
558
            public_branch=tree_a.branch.base)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
559
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
560
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
561
        self.assertEqual('rev2a', revision)
562
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
563
564
    def test_get_target_revision_nofetch(self):
565
        tree_a, tree_b, branch_c = self.make_trees()
566
        tree_b.branch.fetch(tree_a.branch)
2520.4.80 by Aaron Bentley
Improve merge directive tests
567
        md = self.from_objects( tree_a.branch.repository, 'rev2a', 500, 36,
568
            tree_b.branch.base, patch_type=None,
569
            public_branch=tree_a.branch.base)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
570
        md.source_branch = '/dev/null'
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
571
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
572
        self.assertEqual('rev2a', revision)
2520.4.73 by Aaron Bentley
Implement new merge directive format
573
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
574
    def test_use_submit_for_missing_dependency(self):
575
        tree_a, tree_b, branch_c = self.make_trees()
576
        branch_c.pull(tree_a.branch)
577
        self.build_tree_contents([('tree_a/file', 'content_q\ncontent_r\n')])
578
        tree_a.commit('rev3a', rev_id='rev3a')
579
        md = self.from_objects(tree_a.branch.repository, 'rev3a', 500, 36,
580
            branch_c.base, base_revision_id='rev2a')
581
        revision = md.install_revisions(tree_b.branch.repository)
582
3535.8.1 by James Westby
Handle something that isn't a branch being specified in target_branch.
583
    def test_handle_target_not_a_branch(self):
584
        tree_a, tree_b, branch_c = self.make_trees()
585
        branch_c.pull(tree_a.branch)
586
        self.build_tree_contents([('tree_a/file', 'content_q\ncontent_r\n')])
587
        tree_a.commit('rev3a', rev_id='rev3a')
588
        md = self.from_objects(tree_a.branch.repository, 'rev3a', 500, 36,
589
            branch_c.base, base_revision_id='rev2a')
3535.8.2 by James Westby
Incorporate spiv's feedback.
590
        md.target_branch = self.get_url('not-a-branch')
3535.8.1 by James Westby
Handle something that isn't a branch being specified in target_branch.
591
        self.assertRaises(errors.TargetNotBranch, md.install_revisions,
592
                tree_b.branch.repository)
593
2520.4.73 by Aaron Bentley
Implement new merge directive format
594
595
class TestMergeDirective1Branch(tests.TestCaseWithTransport,
596
    TestMergeDirectiveBranch):
597
    """Test merge directive format 1 with a branch"""
2520.4.80 by Aaron Bentley
Improve merge directive tests
598
599
    EMAIL1 = EMAIL1
600
601
    EMAIL2 = EMAIL2
602
2520.4.73 by Aaron Bentley
Implement new merge directive format
603
    def from_objects(self, repository, revision_id, time, timezone,
604
        target_branch, patch_type='bundle', local_target_branch=None,
1551.19.19 by Aaron Bentley
Merge directives can now fetch prerequisites from the target branch
605
        public_branch=None, message=None, base_revision_id=None):
606
        if base_revision_id is not None:
607
            raise tests.TestNotApplicable('This format does not support'
608
                                          ' explicit bases.')
3010.1.9 by Robert Collins
test_merge_directive locking correctness.
609
        repository.lock_write()
610
        try:
611
            return merge_directive.MergeDirective.from_objects( repository,
612
                revision_id, time, timezone, target_branch, patch_type,
613
                local_target_branch, public_branch, message)
614
        finally:
615
            repository.unlock()
2520.4.73 by Aaron Bentley
Implement new merge directive format
616
2520.4.80 by Aaron Bentley
Improve merge directive tests
617
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
618
                 target_branch, patch=None, patch_type=None,
619
                 source_branch=None, message=None):
620
        return merge_directive.MergeDirective(revision_id, testament_sha1,
621
                 time, timezone, target_branch, patch, patch_type,
622
                 source_branch, message)
623
2520.4.73 by Aaron Bentley
Implement new merge directive format
624
625
class TestMergeDirective2Branch(tests.TestCaseWithTransport,
626
    TestMergeDirectiveBranch):
627
    """Test merge directive format 2 with a branch"""
628
2520.4.80 by Aaron Bentley
Improve merge directive tests
629
    EMAIL1 = EMAIL1_2
630
631
    EMAIL2 = EMAIL2_2
632
2520.4.73 by Aaron Bentley
Implement new merge directive format
633
    def from_objects(self, repository, revision_id, time, timezone,
634
        target_branch, patch_type='bundle', local_target_branch=None,
2520.4.112 by Aaron Bentley
Make cherry-pick merge directives possible
635
        public_branch=None, message=None, base_revision_id=None):
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
636
        include_patch = (patch_type in ('bundle', 'diff'))
637
        include_bundle = (patch_type == 'bundle')
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
638
        self.assertTrue(patch_type in ('bundle', 'diff', None))
2520.4.73 by Aaron Bentley
Implement new merge directive format
639
        return merge_directive.MergeDirective2.from_objects(
640
            repository, revision_id, time, timezone, target_branch,
2520.5.4 by Aaron Bentley
Replace 'bundle-revisions' with 'submit' command
641
            include_patch, include_bundle, local_target_branch, public_branch,
642
            message, base_revision_id)
2520.4.80 by Aaron Bentley
Improve merge directive tests
643
644
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
645
                 target_branch, patch=None, patch_type=None,
2520.4.105 by Aaron Bentley
Implement patch verification
646
                 source_branch=None, message=None, base_revision_id='null:'):
2520.4.80 by Aaron Bentley
Improve merge directive tests
647
        if patch_type == 'bundle':
648
            bundle = patch
649
            patch = None
650
        else:
651
            bundle = None
652
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
653
            time, timezone, target_branch, patch, source_branch, message,
2520.4.105 by Aaron Bentley
Implement patch verification
654
            bundle, base_revision_id)
655
656
    def test_base_revision(self):
657
        tree_a, tree_b, branch_c = self.make_trees()
658
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
659
            tree_b.branch.base, patch_type='bundle',
2520.4.112 by Aaron Bentley
Make cherry-pick merge directives possible
660
            public_branch=tree_a.branch.base, base_revision_id=None)
2520.4.105 by Aaron Bentley
Implement patch verification
661
        self.assertEqual('rev1', md.base_revision_id)
2520.4.112 by Aaron Bentley
Make cherry-pick merge directives possible
662
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
663
            tree_b.branch.base, patch_type='bundle',
664
            public_branch=tree_a.branch.base, base_revision_id='null:')
665
        self.assertEqual('null:', md.base_revision_id)
2520.4.105 by Aaron Bentley
Implement patch verification
666
        lines = md.to_lines()
667
        md2 = merge_directive.MergeDirective.from_lines(lines)
668
        self.assertEqual(md2.base_revision_id, md.base_revision_id)
669
670
    def test_patch_verification(self):
671
        tree_a, tree_b, branch_c = self.make_trees()
672
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
673
            tree_b.branch.base, patch_type='bundle',
674
            public_branch=tree_a.branch.base)
675
        lines = md.to_lines()
676
        md2 = merge_directive.MergeDirective.from_lines(lines)
677
        md2._verify_patch(tree_a.branch.repository)
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
678
        # Strip trailing whitespace
2520.4.105 by Aaron Bentley
Implement patch verification
679
        md2.patch = md2.patch.replace(' \n', '\n')
680
        md2._verify_patch(tree_a.branch.repository)
681
        # Convert to Mac line-endings
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
682
        md2.patch = re.sub('(\r\n|\r|\n)', '\r', md2.patch)
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
683
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
2520.4.105 by Aaron Bentley
Implement patch verification
684
        # Convert to DOS line-endings
2520.7.2 by Aaron Bentley
Restore patch verification for CR, CRLF files
685
        md2.patch = re.sub('(\r\n|\r|\n)', '\r\n', md2.patch)
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
686
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
2520.4.105 by Aaron Bentley
Implement patch verification
687
        md2.patch = md2.patch.replace('content_c', 'content_d')
2520.4.108 by Aaron Bentley
Start work on using merge base from directives
688
        self.assertFalse(md2._verify_patch(tree_a.branch.repository))
2694.1.1 by Aaron Bentley
Restore support for Merge directive 2 / 0.19
689
690
691
class TestParseOldMergeDirective2(tests.TestCase):
692
693
    def test_parse_old_merge_directive(self):
694
        md = merge_directive.MergeDirective.from_lines(INPUT1_2_OLD)
695
        self.assertEqual('example:', md.revision_id)
696
        self.assertEqual('sha', md.testament_sha1)
697
        self.assertEqual('http://example.com', md.target_branch)
698
        self.assertEqual('http://example.org', md.source_branch)
699
        self.assertEqual(453, md.time)
700
        self.assertEqual(120, md.timezone)
701
        self.assertEqual('booga', md.patch)
702
        self.assertEqual('diff', md.patch_type)
703
        self.assertEqual('Hi mom!', md.message)
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
704
705
706
class TestHook(object):
707
    """Hook callback for test purposes."""
708
709
    def __init__(self, result=None):
710
        self.calls = []
711
        self.result = result
712
713
    def __call__(self, params):
714
        self.calls.append(params)
715
        return self.result
716
717
718
class HookMailClient(mail_client.MailClient):
719
    """Mail client for testing hooks."""
720
721
    def __init__(self, config):
722
        self.body = None
723
        self.config = config
724
725
    def compose(self, prompt, to, subject, attachment, mime_subtype,
726
                extension, basename=None, body=None):
727
        self.body = body
728
729
730
class TestBodyHook(tests.TestCaseWithTransport):
731
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
732
    def compose_with_hooks(self, test_hooks, supports_body=True):
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
733
        client = HookMailClient({})
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
734
        client.supports_body = supports_body
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
735
        for test_hook in test_hooks:
736
            merge_directive.MergeDirective.hooks.install_named_hook(
737
                'merge_request_body', test_hook, 'test')
738
        tree = self.make_branch_and_tree('foo')
739
        tree.commit('foo')
740
        directive = merge_directive.MergeDirective2(
741
            tree.branch.last_revision(), 'sha', 0, 0, 'sha',
742
            source_branch=tree.branch.base,
743
            base_revision_id=tree.branch.last_revision(),
744
            message='This code rox')
745
        directive.compose_merge_request(client, 'jrandom@example.com',
746
            None, tree.branch)
747
        return client, directive
748
4098.5.18 by Aaron Bentley
Gracefully handle mail clients that don't support bodies.
749
    def test_no_supports_body(self):
750
        test_hook = TestHook('foo')
751
        old_warn = trace.warning
752
        warnings = []
753
        def warn(*args):
754
            warnings.append(args)
755
        trace.warning = warn
756
        try:
757
            client, directive = self.compose_with_hooks([test_hook],
758
                supports_body=False)
759
        finally:
760
            trace.warning = old_warn
761
        self.assertEqual(0, len(test_hook.calls))
762
        self.assertEqual(('Cannot run merge_request_body hooks because mail'
763
                          ' client %s does not support message bodies.',
764
                          'HookMailClient'), warnings[0])
765
4098.5.16 by Aaron Bentley
Move hook to MergeDirective, implement MergeDirective.compose_merge_request.
766
    def test_body_hook(self):
767
        test_hook = TestHook('foo')
768
        client, directive = self.compose_with_hooks([test_hook])
769
        self.assertEqual(1, len(test_hook.calls))
770
        self.assertEqual('foo', client.body)
771
        params = test_hook.calls[0]
772
        self.assertIsInstance(params,
773
                              merge_directive.MergeRequestBodyParams)
774
        self.assertIs(None, params.body)
775
        self.assertIs(None, params.orig_body)
776
        self.assertEqual('jrandom@example.com', params.to)
777
        self.assertEqual('[MERGE] This code rox', params.subject)
778
        self.assertEqual(directive, params.directive)
779
        self.assertEqual('foo-1', params.basename)
780
781
    def test_body_hook_chaining(self):
782
        test_hook1 = TestHook('foo')
783
        test_hook2 = TestHook('bar')
784
        client = self.compose_with_hooks([test_hook1, test_hook2])[0]
785
        self.assertEqual(None, test_hook1.calls[0].body)
786
        self.assertEqual(None, test_hook1.calls[0].orig_body)
787
        self.assertEqual('foo', test_hook2.calls[0].body)
788
        self.assertEqual(None, test_hook2.calls[0].orig_body)
789
        self.assertEqual('bar', client.body)