~bzr-pqm/bzr/bzr.dev

1551.12.36 by Aaron Bentley
Fix failing tests
1
# Copyright (C) 2007 Canonical Ltd
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
18
from bzrlib import (
19
    errors,
1551.12.16 by Aaron Bentley
Enable signing merge directives
20
    gpg,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
21
    merge_directive,
22
    tests,
23
    )
24
1551.12.4 by Aaron Bentley
Add failing test
25
1551.12.45 by Aaron Bentley
Change format marker to not experimental
26
OUTPUT1 = """# Bazaar merge directive format 1
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
27
# revision_id: example:
28
# target_branch: http://example.com
29
# testament_sha1: sha
30
# timestamp: 1970-01-01 00:09:33 +0002
31
#\x20
32
booga"""
33
34
1551.12.45 by Aaron Bentley
Change format marker to not experimental
35
OUTPUT2 = """# Bazaar merge directive format 1
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
36
# revision_id: example:
37
# target_branch: http://example.com
38
# testament_sha1: sha
39
# timestamp: 1970-01-01 00:09:33 +0002
40
# source_branch: http://example.org
41
# message: Hi mom!
42
#\x20
43
booga"""
44
45
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
46
INPUT1 = """
47
I was thinking today about creating a merge directive.
48
49
So I did.
50
51
Here it is.
52
53
(I've pasted it in the body of this message)
54
55
Aaron
56
57
# Bazaar merge directive format 1\r
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!
64
#\x20
65
booga""".splitlines(True)
66
67
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
68
class TestMergeDirective(tests.TestCase):
69
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
70
    def test_merge_source(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
71
        time = 500000.0
72
        timezone = 5 * 3600
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
73
        self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
74
            'example:', 'sha', time, timezone, 'http://example.com')
75
        self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
76
            'example:', 'sha', time, timezone, 'http://example.com',
77
            patch_type='diff')
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
78
        merge_directive.MergeDirective('example:', 'sha', time, timezone,
1551.12.13 by Aaron Bentley
Rename fields
79
            'http://example.com', source_branch='http://example.org')
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
80
        md = merge_directive.MergeDirective('null:', 'sha', time, timezone,
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
81
            'http://example.com', patch='blah', patch_type='bundle')
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
82
        self.assertIs(None, md.source_branch)
83
        md2 = merge_directive.MergeDirective('null:', 'sha', time, timezone,
84
            'http://example.com', patch='blah', patch_type='bundle',
85
            source_branch='bar')
86
        self.assertEqual('bar', md2.source_branch)
87
88
    def test_require_patch(self):
89
        time = 500.0
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
90
        timezone = 120
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
91
        self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
1551.12.6 by Aaron Bentley
Force times to be floats
92
            'example:', 'sha', time, timezone, 'http://example.com',
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
93
            patch_type='bundle')
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
94
        md = merge_directive.MergeDirective('example:', 'sha1', time, timezone,
1551.12.13 by Aaron Bentley
Rename fields
95
            'http://example.com', source_branch="http://example.org",
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
96
            patch='', patch_type='diff')
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
97
        self.assertEqual(md.patch, '')
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
98
99
    def test_serialization(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
100
        time = 453
101
        timezone = 120
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
102
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
103
            'http://example.com', patch='booga', patch_type='bundle')
104
        self.assertEqualDiff(OUTPUT1, ''.join(md.to_lines()))
105
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
106
            'http://example.com', source_branch="http://example.org",
107
            patch='booga', patch_type='diff', message="Hi mom!")
108
        self.assertEqualDiff(OUTPUT2, ''.join(md.to_lines()))
109
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
110
    def test_deserialize_junk(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
111
        time = 501
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
112
        self.assertRaises(errors.NotAMergeDirective,
113
                          merge_directive.MergeDirective.from_lines, 'lala')
114
1551.12.59 by Aaron Bentley
Correctly handle empty merge directive texts
115
    def test_deserialize_empty(self):
116
        self.assertRaises(errors.NotAMergeDirective,
117
                          merge_directive.MergeDirective.from_lines, [])
118
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
119
    def test_deserialize_leading_junk(self):
120
        md = merge_directive.MergeDirective.from_lines(INPUT1)
121
        self.assertEqual('example:', md.revision_id)
122
        self.assertEqual('sha', md.testament_sha1)
123
        self.assertEqual('http://example.com', md.target_branch)
124
        self.assertEqual('http://example.org', md.source_branch)
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
125
        self.assertEqual(453, md.time)
126
        self.assertEqual(120, md.timezone)
1551.12.51 by Aaron Bentley
Allow leading junk before merge directive header
127
        self.assertEqual('booga', md.patch)
128
        self.assertEqual('diff', md.patch_type)
129
        self.assertEqual('Hi mom!', md.message)
1551.12.49 by Aaron Bentley
Proper error when deserializing junk
130
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
131
    def test_roundtrip(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
132
        time = 500000
133
        timezone = 7.5 * 3600
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
134
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
1551.12.13 by Aaron Bentley
Rename fields
135
            'http://example.com', source_branch="http://example.org",
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
136
            patch='booga', patch_type='diff')
137
        md2 = merge_directive.MergeDirective.from_lines(md.to_lines())
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
138
        self.assertEqual('example:', md2.revision_id)
1551.12.54 by Aaron Bentley
Decoded revision ids are utf-8
139
        self.assertIsInstance(md2.revision_id, str)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
140
        self.assertEqual('sha', md2.testament_sha1)
1551.12.13 by Aaron Bentley
Rename fields
141
        self.assertEqual('http://example.com', md2.target_branch)
142
        self.assertEqual('http://example.org', md2.source_branch)
1551.12.3 by Aaron Bentley
Add timestamps to merge directives
143
        self.assertEqual(time, md2.time)
144
        self.assertEqual(timezone, md2.timezone)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
145
        self.assertEqual('diff', md2.patch_type)
146
        self.assertEqual('booga', md2.patch)
1551.12.26 by Aaron Bentley
Get email working, with optional message
147
        self.assertEqual(None, md2.message)
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
148
        md.patch = "# Bazaar revision bundle v0.9\n#\n"
1551.12.26 by Aaron Bentley
Get email working, with optional message
149
        md.message = "Hi mom!"
1551.12.2 by Aaron Bentley
Got directives round-tripping, with bundles and everything
150
        md3 = merge_directive.MergeDirective.from_lines(md.to_lines())
151
        self.assertEqual("# Bazaar revision bundle v0.9\n#\n", md3.patch)
152
        self.assertEqual("bundle", md3.patch_type)
1551.12.12 by Aaron Bentley
Add format header
153
        self.assertContainsRe(md3.to_lines()[0],
154
            '^# Bazaar merge directive format ')
1551.12.26 by Aaron Bentley
Get email working, with optional message
155
        self.assertEqual("Hi mom!", md3.message)
1551.12.53 by Aaron Bentley
Fix deserialization of merge directives with no patch
156
        md3.patch_type = None
157
        md3.patch = None
158
        md4 = merge_directive.MergeDirective.from_lines(md3.to_lines())
159
        self.assertIs(None, md4.patch_type)
1551.12.26 by Aaron Bentley
Get email working, with optional message
160
161
162
EMAIL1 = """To: pqm@example.com
163
From: J. Random Hacker <jrandom@example.com>
164
Subject: Commit of rev2a
165
1551.12.45 by Aaron Bentley
Change format marker to not experimental
166
# Bazaar merge directive format 1
1551.12.26 by Aaron Bentley
Get email working, with optional message
167
# revision_id: rev2a
168
# target_branch: (.|\n)*
169
# testament_sha1: .*
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
170
# timestamp: 1970-01-01 00:08:56 \\+0001
1551.12.26 by Aaron Bentley
Get email working, with optional message
171
# source_branch: (.|\n)*
172
"""
173
174
175
EMAIL2 = """To: pqm@example.com
176
From: J. Random Hacker <jrandom@example.com>
177
Subject: Commit of rev2a with special message
178
1551.12.45 by Aaron Bentley
Change format marker to not experimental
179
# Bazaar merge directive format 1
1551.12.26 by Aaron Bentley
Get email working, with optional message
180
# revision_id: rev2a
181
# target_branch: (.|\n)*
182
# testament_sha1: .*
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
183
# timestamp: 1970-01-01 00:08:56 \\+0001
1551.12.26 by Aaron Bentley
Get email working, with optional message
184
# source_branch: (.|\n)*
185
# message: Commit of rev2a with special message
186
"""
1551.12.4 by Aaron Bentley
Add failing test
187
188
189
class TestMergeDirectiveBranch(tests.TestCaseWithTransport):
190
1551.12.26 by Aaron Bentley
Get email working, with optional message
191
    def make_trees(self):
1551.12.4 by Aaron Bentley
Add failing test
192
        tree_a = self.make_branch_and_tree('tree_a')
1551.12.26 by Aaron Bentley
Get email working, with optional message
193
        tree_a.branch.get_config().set_user_option('email',
194
            'J. Random Hacker <jrandom@example.com>')
1551.12.4 by Aaron Bentley
Add failing test
195
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_b\n')])
196
        tree_a.add('file')
197
        tree_a.commit('message', rev_id='rev1')
198
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
199
        branch_c = tree_a.bzrdir.sprout('branch_c').open_branch()
1551.12.4 by Aaron Bentley
Add failing test
200
        tree_b.commit('message', rev_id='rev2b')
201
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_c\n')])
1551.12.26 by Aaron Bentley
Get email working, with optional message
202
        tree_a.commit('Commit of rev2a', rev_id='rev2a')
203
        return tree_a, tree_b, branch_c
204
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
205
    def test_generate_patch(self):
206
        tree_a, tree_b, branch_c = self.make_trees()
207
        md2 = merge_directive.MergeDirective.from_objects(
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
208
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
209
            patch_type='diff', public_branch=tree_a.branch.base)
210
        self.assertNotContainsRe(md2.patch, 'Bazaar revision bundle')
211
        self.assertContainsRe(md2.patch, '\\+content_c')
212
        self.assertNotContainsRe(md2.patch, '\\+\\+\\+ b/')
213
        self.assertContainsRe(md2.patch, '\\+\\+\\+ file')
214
215
    def test_public_branch(self):
1551.12.26 by Aaron Bentley
Get email working, with optional message
216
        tree_a, tree_b, branch_c = self.make_trees()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
217
        self.assertRaises(errors.PublicBranchOutOfDate,
218
            merge_directive.MergeDirective.from_objects,
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
219
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
1551.12.34 by Aaron Bentley
Check public branch only if not using a bundle
220
            public_branch=branch_c.base, patch_type='diff')
221
        # public branch is not checked if patch format is bundle.
222
        md1 = merge_directive.MergeDirective.from_objects(
223
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
1551.12.33 by Aaron Bentley
Take public_branch as a string, not object
224
            public_branch=branch_c.base)
1551.12.34 by Aaron Bentley
Check public branch only if not using a bundle
225
        # public branch is provided with a bundle, despite possibly being out
226
        # of date, because it's not required if a bundle is present.
227
        self.assertEqual(md1.source_branch, branch_c.base)
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
228
        # Once we update the public branch, we can generate a diff.
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
229
        branch_c.pull(tree_a.branch)
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
230
        md3 = merge_directive.MergeDirective.from_objects(
1551.12.30 by Aaron Bentley
Use patch-style dates for timestamps in merge directives
231
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
232
            patch_type=None, public_branch=branch_c.base)
233
1551.12.50 by Aaron Bentley
Use public location of submit branch if possible
234
    def test_use_public_submit_branch(self):
235
        tree_a, tree_b, branch_c = self.make_trees()
236
        branch_c.pull(tree_a.branch)
237
        md = merge_directive.MergeDirective.from_objects(
238
             tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
239
             patch_type=None, public_branch=branch_c.base)
240
        self.assertEqual(md.target_branch, tree_b.branch.base)
241
        tree_b.branch.set_public_branch('http://example.com')
242
        md2 = merge_directive.MergeDirective.from_objects(
243
              tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
244
              patch_type=None, public_branch=branch_c.base)
245
        self.assertEqual(md2.target_branch, 'http://example.com')
246
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
247
    def test_message(self):
248
        tree_a, tree_b, branch_c = self.make_trees()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
249
        md3 = merge_directive.MergeDirective.from_objects(
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
250
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
1551.12.33 by Aaron Bentley
Take public_branch as a string, not object
251
            patch_type=None, public_branch=branch_c.base,
252
            message='Merge message')
1551.12.7 by Aaron Bentley
Fix use of public location/branch
253
        md3.to_lines()
1551.12.5 by Aaron Bentley
Get MergeDirective.from_objects working
254
        self.assertIs(None, md3.patch)
1551.12.27 by Aaron Bentley
support custom message everywhere
255
        self.assertEqual('Merge message', md3.message)
1551.12.16 by Aaron Bentley
Enable signing merge directives
256
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
257
    def test_generate_bundle(self):
1551.12.40 by Aaron Bentley
Do not show prefixes in diffs
258
        tree_a, tree_b, branch_c = self.make_trees()
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
259
        md1 = merge_directive.MergeDirective.from_objects(
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
260
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
1551.12.41 by Aaron Bentley
Clean up tests, add serialization text test
261
            public_branch=branch_c.base)
262
        self.assertContainsRe(md1.patch, 'Bazaar revision bundle')
263
        self.assertContainsRe(md1.patch, '\\+content_c')
264
        self.assertNotContainsRe(md1.patch, '\\+content_a')
265
        self.assertContainsRe(md1.patch, '\\+content_c')
266
        self.assertNotContainsRe(md1.patch, '\\+content_a')
1551.12.40 by Aaron Bentley
Do not show prefixes in diffs
267
1551.12.16 by Aaron Bentley
Enable signing merge directives
268
    def test_signing(self):
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
269
        time = 453
270
        timezone = 7200
1551.12.16 by Aaron Bentley
Enable signing merge directives
271
        class FakeBranch(object):
272
            def get_config(self):
273
                return self
274
            def gpg_signing_command(self):
275
                return 'loopback'
276
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
277
            'http://example.com', source_branch="http://example.org",
278
            patch='booga', patch_type='diff')
279
        old_strategy = gpg.GPGStrategy
280
        gpg.GPGStrategy = gpg.LoopbackGPGStrategy
281
        try:
282
            signed = md.to_signed(FakeBranch())
283
        finally:
284
            gpg.GPGStrategy = old_strategy
285
        self.assertContainsRe(signed, '^-----BEGIN PSEUDO-SIGNED CONTENT')
286
        self.assertContainsRe(signed, 'example.org')
287
        self.assertContainsRe(signed, 'booga')
1551.12.26 by Aaron Bentley
Get email working, with optional message
288
289
    def test_email(self):
290
        tree_a, tree_b, branch_c = self.make_trees()
291
        md = merge_directive.MergeDirective.from_objects(
2425.6.1 by Martin Pool
Fix formatting of timezones in bundles and merge directives.
292
            tree_a.branch.repository, 'rev2a', 476, 60, tree_b.branch.base,
1551.12.33 by Aaron Bentley
Take public_branch as a string, not object
293
            patch_type=None, public_branch=tree_a.branch.base)
1551.12.26 by Aaron Bentley
Get email working, with optional message
294
        message = md.to_email('pqm@example.com', tree_a.branch)
295
        self.assertContainsRe(message.as_string(), EMAIL1)
296
        md.message = 'Commit of rev2a with special message'
297
        message = md.to_email('pqm@example.com', tree_a.branch)
298
        self.assertContainsRe(message.as_string(), EMAIL2)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
299
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
300
    def test_install_revisions_branch(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
301
        tree_a, tree_b, branch_c = self.make_trees()
302
        md = merge_directive.MergeDirective.from_objects(
303
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
304
            patch_type=None, public_branch=tree_a.branch.base)
305
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
306
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
307
        self.assertEqual('rev2a', revision)
308
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
309
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
310
    def test_install_revisions_bundle(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
311
        tree_a, tree_b, branch_c = self.make_trees()
312
        md = merge_directive.MergeDirective.from_objects(
313
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
314
            patch_type='bundle', public_branch=tree_a.branch.base)
315
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
316
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
317
        self.assertEqual('rev2a', revision)
318
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
319
320
    def test_get_target_revision_nofetch(self):
321
        tree_a, tree_b, branch_c = self.make_trees()
322
        tree_b.branch.fetch(tree_a.branch)
323
        md = merge_directive.MergeDirective.from_objects(
324
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
325
            patch_type=None, public_branch=tree_a.branch.base)
326
        md.source_branch = '/dev/null'
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
327
        revision = md.install_revisions(tree_b.branch.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
328
        self.assertEqual('rev2a', revision)