/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
1
# Copyright (C) 2004-2006 by 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
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
16
17
from StringIO import StringIO
18
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
19
from bzrlib.builtins import merge
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
20
from bzrlib.bzrdir import BzrDir
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
21
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
22
from bzrlib.bundle.read_bundle import BundleTree, BundleReader
23
from bzrlib.bundle.serializer import write_bundle
1185.82.90 by Aaron Bentley
Reorganized test suite
24
from bzrlib.diff import internal_diff
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
25
from bzrlib.errors import BzrError, TestamentMismatch
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
26
from bzrlib.merge import Merge3Merger
1185.82.87 by Aaron Bentley
Got symlink adding working
27
from bzrlib.osutils import has_symlinks, sha_file
1185.82.137 by Aaron Bentley
Skip unicode changeset test
28
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
1185.82.66 by Aaron Bentley
Handle new executable files
29
from bzrlib.transform import TreeTransform
1185.82.17 by Aaron Bentley
More API updates
30
from bzrlib.workingtree import WorkingTree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
31
1185.82.90 by Aaron Bentley
Reorganized test suite
32
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
33
class MockTree(object):
34
    def __init__(self):
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
35
        from bzrlib.inventory import RootEntry, ROOT_ID
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
36
        object.__init__(self)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
37
        self.paths = {ROOT_ID: ""}
38
        self.ids = {"": ROOT_ID}
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
39
        self.contents = {}
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
40
        self.root = RootEntry(ROOT_ID)
41
42
    inventory = property(lambda x:x)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
43
44
    def __iter__(self):
45
        return self.paths.iterkeys()
46
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
47
    def __getitem__(self, file_id):
48
        if file_id == self.root.file_id:
49
            return self.root
50
        else:
51
            return self.make_entry(file_id, self.paths[file_id])
52
53
    def parent_id(self, file_id):
54
        from os.path import dirname
55
        parent_dir = dirname(self.paths[file_id])
56
        if parent_dir == "":
57
            return None
58
        return self.ids[parent_dir]
59
60
    def iter_entries(self):
61
        for path, file_id in self.ids.iteritems():
62
            yield path, self[file_id]
63
64
    def get_file_kind(self, file_id):
65
        if file_id in self.contents:
66
            kind = 'file'
67
        else:
68
            kind = 'directory'
69
        return kind
70
71
    def make_entry(self, file_id, path):
72
        from os.path import basename
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
73
        from bzrlib.inventory import (InventoryEntry, InventoryFile
74
                                    , InventoryDirectory, InventoryLink)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
75
        name = basename(path)
76
        kind = self.get_file_kind(file_id)
77
        parent_id = self.parent_id(file_id)
78
        text_sha_1, text_size = self.contents_stats(file_id)
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
79
        if kind == 'directory':
80
            ie = InventoryDirectory(file_id, name, parent_id)
81
        elif kind == 'file':
82
            ie = InventoryFile(file_id, name, parent_id)
83
        elif kind == 'symlink':
84
            ie = InventoryLink(file_id, name, parent_id)
85
        else:
86
            raise BzrError('unknown kind %r' % kind)
0.5.91 by Aaron Bentley
Updated to match API change
87
        ie.text_sha1 = text_sha_1
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
88
        ie.text_size = text_size
89
        return ie
90
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
91
    def add_dir(self, file_id, path):
92
        self.paths[file_id] = path
93
        self.ids[path] = file_id
94
    
95
    def add_file(self, file_id, path, contents):
96
        self.add_dir(file_id, path)
97
        self.contents[file_id] = contents
98
99
    def path2id(self, path):
100
        return self.ids.get(path)
101
102
    def id2path(self, file_id):
103
        return self.paths.get(file_id)
104
105
    def has_id(self, file_id):
106
        return self.id2path(file_id) is not None
107
108
    def get_file(self, file_id):
109
        result = StringIO()
110
        result.write(self.contents[file_id])
111
        result.seek(0,0)
112
        return result
113
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
114
    def contents_stats(self, file_id):
115
        if file_id not in self.contents:
116
            return None, None
117
        text_sha1 = sha_file(self.get_file(file_id))
118
        return text_sha1, len(self.contents[file_id])
119
120
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
121
class BTreeTester(TestCase):
122
    """A simple unittest tester for the BundleTree class."""
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
123
124
    def make_tree_1(self):
125
        mtree = MockTree()
126
        mtree.add_dir("a", "grandparent")
127
        mtree.add_dir("b", "grandparent/parent")
128
        mtree.add_file("c", "grandparent/parent/file", "Hello\n")
129
        mtree.add_dir("d", "grandparent/alt_parent")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
130
        return BundleTree(mtree, ''), mtree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
131
        
132
    def test_renames(self):
133
        """Ensure that file renames have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
134
        btree = self.make_tree_1()[0]
135
        self.assertEqual(btree.old_path("grandparent"), "grandparent")
136
        self.assertEqual(btree.old_path("grandparent/parent"), 
137
                         "grandparent/parent")
138
        self.assertEqual(btree.old_path("grandparent/parent/file"),
139
                         "grandparent/parent/file")
140
141
        self.assertEqual(btree.id2path("a"), "grandparent")
142
        self.assertEqual(btree.id2path("b"), "grandparent/parent")
143
        self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
144
145
        self.assertEqual(btree.path2id("grandparent"), "a")
146
        self.assertEqual(btree.path2id("grandparent/parent"), "b")
147
        self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
148
149
        assert btree.path2id("grandparent2") is None
150
        assert btree.path2id("grandparent2/parent") is None
151
        assert btree.path2id("grandparent2/parent/file") is None
152
153
        btree.note_rename("grandparent", "grandparent2")
154
        assert btree.old_path("grandparent") is None
155
        assert btree.old_path("grandparent/parent") is None
156
        assert btree.old_path("grandparent/parent/file") is None
157
158
        self.assertEqual(btree.id2path("a"), "grandparent2")
159
        self.assertEqual(btree.id2path("b"), "grandparent2/parent")
160
        self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
161
162
        self.assertEqual(btree.path2id("grandparent2"), "a")
163
        self.assertEqual(btree.path2id("grandparent2/parent"), "b")
164
        self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
165
166
        assert btree.path2id("grandparent") is None
167
        assert btree.path2id("grandparent/parent") is None
168
        assert btree.path2id("grandparent/parent/file") is None
169
170
        btree.note_rename("grandparent/parent", "grandparent2/parent2")
171
        self.assertEqual(btree.id2path("a"), "grandparent2")
172
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
173
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
174
175
        self.assertEqual(btree.path2id("grandparent2"), "a")
176
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
177
        self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
178
179
        assert btree.path2id("grandparent2/parent") is None
180
        assert btree.path2id("grandparent2/parent/file") is None
181
182
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
183
                          "grandparent2/parent2/file2")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
184
        self.assertEqual(btree.id2path("a"), "grandparent2")
185
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
186
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
187
188
        self.assertEqual(btree.path2id("grandparent2"), "a")
189
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
190
        self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
191
192
        assert btree.path2id("grandparent2/parent2/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
193
194
    def test_moves(self):
195
        """Ensure that file moves have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
196
        btree = self.make_tree_1()[0]
197
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
198
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
199
        self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
200
        self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
201
        assert btree.path2id("grandparent/parent/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
202
203
    def unified_diff(self, old, new):
204
        out = StringIO()
205
        internal_diff("old", old, "new", new, out)
206
        out.seek(0,0)
207
        return out.read()
208
209
    def make_tree_2(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
210
        btree = self.make_tree_1()[0]
211
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
212
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
213
        assert btree.id2path("e") is None
214
        assert btree.path2id("grandparent/parent/file") is None
215
        btree.note_id("e", "grandparent/parent/file")
216
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
217
218
    def test_adds(self):
219
        """File/inventory adds"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
220
        btree = self.make_tree_2()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
221
        add_patch = self.unified_diff([], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
222
        btree.note_patch("grandparent/parent/file", add_patch)
223
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
224
        btree.note_target('grandparent/parent/symlink', 'venus')
225
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
226
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
227
    def adds_test(self, btree):
228
        self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
229
        self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
230
        self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
231
        self.assertEqual(btree.get_symlink_target('f'), 'venus')
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
232
233
    def test_adds2(self):
234
        """File/inventory adds, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
235
        btree = self.make_tree_2()
236
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
237
        add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
238
        btree.note_patch("grandparent/parent/file", add_patch)
239
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
240
        btree.note_target('grandparent/parent/symlink', 'venus')
241
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
242
243
    def make_tree_3(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
244
        btree, mtree = self.make_tree_1()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
245
        mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
246
        btree.note_rename("grandparent/parent/file", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
247
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
248
        btree.note_rename("grandparent/parent/topping", 
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
249
                          "grandparent/alt_parent/stopping")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
250
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
251
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
252
    def get_file_test(self, btree):
253
        self.assertEqual(btree.get_file("e").read(), "Lemon\n")
254
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
255
256
    def test_get_file(self):
257
        """Get file contents"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
258
        btree = self.make_tree_3()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
259
        mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
260
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
261
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
262
263
    def test_get_file2(self):
264
        """Get file contents, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
265
        btree = self.make_tree_3()
266
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
267
        mod_patch = self.unified_diff([], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
268
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
269
        mod_patch = self.unified_diff([], ["Hello\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
270
        btree.note_patch("grandparent/alt_parent/file", mod_patch)
271
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
272
273
    def test_delete(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
274
        "Deletion by bundle"
275
        btree = self.make_tree_1()[0]
276
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
277
        btree.note_deletion("grandparent/parent/file")
278
        assert btree.id2path("c") is None
279
        assert btree.path2id("grandparent/parent/file") is None
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
280
281
    def sorted_ids(self, tree):
282
        ids = list(tree)
283
        ids.sort()
284
        return ids
285
286
    def test_iteration(self):
287
        """Ensure that iteration through ids works properly"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
288
        btree = self.make_tree_1()[0]
289
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'c', 'd'])
290
        btree.note_deletion("grandparent/parent/file")
291
        btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
292
        btree.note_last_changed("grandparent/alt_parent/fool", 
1185.82.95 by Aaron Bentley
Restore path-orientation of ChangesetTree
293
                                "revisionidiguess")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
294
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'd', 'e'])
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
295
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
296
0.5.97 by Aaron Bentley
Updated tests
297
class CSetTester(TestCaseInTempDir):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
298
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
299
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None,
300
                         message=None):
301
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
302
        Make sure that the text generated is valid, and that it
303
        can be applied against the base, and generate the same information.
304
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
305
        :return: The in-memory bundle 
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
306
        """
307
        from cStringIO import StringIO
308
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
309
        bundle_txt = StringIO()
310
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
311
                               bundle_txt)
312
        bundle_txt.seek(0)
313
        self.assertEqual(bundle_txt.readline(), 
314
                         '# Bazaar revision bundle v0.7\n')
315
        self.assertEqual(bundle_txt.readline(), '#\n')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
316
1185.82.14 by Aaron Bentley
API updates
317
        rev = self.b1.repository.get_revision(rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
318
        self.assertEqual(bundle_txt.readline().decode('utf-8'),
319
                         u'# message:\n')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
320
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
321
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
322
        bundle_txt.seek(0)
323
        # This should also validate the generated bundle 
324
        bundle = BundleReader(bundle_txt)
325
        repository = self.b1.repository
326
        for bundle_rev in bundle.info.real_revisions:
327
            # These really should have already been checked when we read the
328
            # bundle, since it computes the sha1 hash for the revision, which
329
            # only will match if everything is okay, but lets be explicit about
330
            # it
331
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1185.82.33 by Aaron Bentley
Strengthen tests
332
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
333
                      'timestamp', 'timezone', 'message', 'committer', 
334
                      'parent_ids', 'properties'):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
335
                self.assertEqual(getattr(branch_rev, a), 
336
                                 getattr(bundle_rev, a))
337
            self.assertEqual(len(branch_rev.parent_ids), 
338
                             len(bundle_rev.parent_ids))
1185.82.47 by Aaron Bentley
Ensure all intended rev_ids end up in the revision
339
        self.assertEqual(rev_ids, 
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
340
                         [r.revision_id for r in bundle.info.real_revisions])
341
        self.valid_apply_bundle(base_rev_id, bundle,
1185.82.89 by Aaron Bentley
Remove auto_commit stuff
342
                                   checkout_dir=checkout_dir)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
343
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
344
        return bundle
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
345
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
346
    def get_invalid_bundle(self, base_rev_id, rev_id):
347
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
348
        Munge the text so that it's invalid.
349
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
350
        :return: The in-memory bundle
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
351
        """
352
        from cStringIO import StringIO
353
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
354
        bundle_txt = StringIO()
355
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
356
                               bundle_txt)
357
        bundle_txt.seek(0)
358
        open(',,bundle', 'wb').write(bundle_txt.getvalue())
359
        bundle_txt.seek(0)
360
        new_text = bundle_txt.getvalue().replace('executable:no', 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
361
                                               'executable:yes')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
362
        bundle_txt = StringIO(new_text)
363
        bundle = BundleReader(bundle_txt)
364
        self.valid_apply_bundle(base_rev_id, bundle)
365
        return bundle 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
366
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
367
    def get_checkout(self, rev_id, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
368
        """Get a new tree, with the specified revision in it.
369
        """
0.5.102 by John Arbash Meinel
Updated to latest bzr.dev changes (serialization, test cases, etc)
370
        from bzrlib.branch import Branch
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
371
        import tempfile
372
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
373
        if checkout_dir is None:
374
            checkout_dir = tempfile.mkdtemp(prefix='test-branch-', dir='.')
0.5.89 by John Arbash Meinel
Updating for explicitly defined directories.
375
        else:
376
            import os
377
            if not os.path.exists(checkout_dir):
378
                os.mkdir(checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
379
        tree = BzrDir.create_standalone_workingtree(checkout_dir)
380
        s = StringIO()
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
381
        ancestors = write_bundle(self.b1.repository, rev_id, None, s)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
382
        s.seek(0)
1185.82.135 by Aaron Bentley
Ensure that bundles are bytestrings
383
        assert isinstance(s.getvalue(), str), (
384
            "Bundle isn't a bytestring:\n %s..." % repr(s.getvalue())[:40])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
385
        install_bundle(tree.branch.repository, BundleReader(s))
1185.82.41 by Aaron Bentley
More work on installing changesets
386
        for ancestor in ancestors:
387
            old = self.b1.repository.revision_tree(ancestor)
388
            new = tree.branch.repository.revision_tree(ancestor)
389
            for inventory_id in old:
390
                try:
391
                    old_file = old.get_file(inventory_id)
392
                except:
393
                    continue
394
                if old_file is None:
395
                    continue
396
                self.assertEqual(old_file.read(),
397
                                 new.get_file(inventory_id).read())
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
398
        if rev_id is not None:
399
            rh = self.b1.revision_history()
400
            tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
401
            tree.update()
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
402
        return tree
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
403
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
404
    def valid_apply_bundle(self, base_rev_id, reader, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
405
        """Get the base revision, apply the changes, and make
406
        sure everything matches the builtin branch.
407
        """
1185.82.17 by Aaron Bentley
More API updates
408
        to_tree = self.get_checkout(base_rev_id, checkout_dir=checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
409
        repository = to_tree.branch.repository
1185.82.41 by Aaron Bentley
More work on installing changesets
410
        self.assertIs(repository.has_revision(base_rev_id), True)
1185.82.45 by Aaron Bentley
Take ChangesetReader as input to merge_changeset
411
        info = reader.info
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
412
        for rev in info.real_revisions:
413
            self.assert_(not repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
414
                'Revision {%s} present before applying bundle' 
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
415
                % rev.revision_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
416
        merge_bundle(reader, to_tree, True, Merge3Merger, False, False)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
417
418
        for rev in info.real_revisions:
1185.82.17 by Aaron Bentley
More API updates
419
            self.assert_(repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
420
                'Missing revision {%s} after applying bundle' 
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
421
                % rev.revision_id)
422
1185.82.17 by Aaron Bentley
More API updates
423
        self.assert_(to_tree.branch.repository.has_revision(info.target))
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
424
        # Do we also want to verify that all the texts have been added?
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
425
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
426
        self.assert_(info.target in to_tree.pending_merges())
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
427
428
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
429
        rev = info.real_revisions[-1]
1185.82.17 by Aaron Bentley
More API updates
430
        base_tree = self.b1.repository.revision_tree(rev.revision_id)
431
        to_tree = to_tree.branch.repository.revision_tree(rev.revision_id)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
432
        
433
        # TODO: make sure the target tree is identical to base tree
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
434
        #       we might also check the working tree.
435
436
        base_files = list(base_tree.list_files())
437
        to_files = list(to_tree.list_files())
438
        self.assertEqual(len(base_files), len(to_files))
1185.82.66 by Aaron Bentley
Handle new executable files
439
        for base_file, to_file in zip(base_files, to_files):
440
            self.assertEqual(base_file, to_file)
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
441
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
442
        for path, status, kind, fileid, entry in base_files:
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
443
            # Check that the meta information is the same
444
            self.assertEqual(base_tree.get_file_size(fileid),
445
                    to_tree.get_file_size(fileid))
446
            self.assertEqual(base_tree.get_file_sha1(fileid),
447
                    to_tree.get_file_sha1(fileid))
448
            # Check that the contents are the same
449
            # This is pretty expensive
450
            # self.assertEqual(base_tree.get_file(fileid).read(),
451
            #         to_tree.get_file(fileid).read())
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
452
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
453
    def test_bundle(self):
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
454
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
455
        import os, sys
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
456
        pjoin = os.path.join
457
1185.82.14 by Aaron Bentley
API updates
458
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
459
        self.b1 = self.tree1.branch
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
460
461
        open(pjoin('b1/one'), 'wb').write('one\n')
1185.82.14 by Aaron Bentley
API updates
462
        self.tree1.add('one')
463
        self.tree1.commit('add one', rev_id='a@cset-0-1')
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
464
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
465
        bundle = self.get_valid_bundle(None, 'a@cset-0-1')
466
        bundle = self.get_valid_bundle(None, 'a@cset-0-1',
0.5.103 by John Arbash Meinel
Updated to having a changeset specific message.
467
                message='With a specialized message')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
468
469
        # Make sure we can handle files with spaces, tabs, other
470
        # bogus characters
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
471
        self.build_tree([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
472
                'b1/with space.txt'
473
                , 'b1/dir/'
474
                , 'b1/dir/filein subdir.c'
475
                , 'b1/dir/WithCaps.txt'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
476
                , 'b1/dir/trailing space '
0.5.84 by John Arbash Meinel
(broken) problem with removes.
477
                , 'b1/sub/'
478
                , 'b1/sub/sub/'
479
                , 'b1/sub/sub/nonempty.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
480
                # Tabs are not valid in filenames on windows
481
                #'b1/with\ttab.txt'
482
                ])
0.5.84 by John Arbash Meinel
(broken) problem with removes.
483
        open('b1/sub/sub/emptyfile.txt', 'wb').close()
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
484
        open('b1/dir/nolastnewline.txt', 'wb').write('bloop')
1185.82.66 by Aaron Bentley
Handle new executable files
485
        tt = TreeTransform(self.tree1)
486
        tt.new_file('executable', tt.root, '#!/bin/sh\n', 'exe-1', True)
487
        tt.apply()
1185.82.14 by Aaron Bentley
API updates
488
        self.tree1.add([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
489
                'with space.txt'
490
                , 'dir'
491
                , 'dir/filein subdir.c'
492
                , 'dir/WithCaps.txt'
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
493
                , 'dir/trailing space '
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
494
                , 'dir/nolastnewline.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
495
                , 'sub'
496
                , 'sub/sub'
497
                , 'sub/sub/nonempty.txt'
498
                , 'sub/sub/emptyfile.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
499
                ])
1185.82.14 by Aaron Bentley
API updates
500
        self.tree1.commit('add whitespace', rev_id='a@cset-0-2')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
501
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
502
        bundle = self.get_valid_bundle('a@cset-0-1', 'a@cset-0-2')
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
503
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
504
        # Check a rollup bundle 
505
        bundle = self.get_valid_bundle(None, 'a@cset-0-2')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
506
507
        # Now delete entries
1185.82.21 by Aaron Bentley
Stop using deprecated function
508
        self.tree1.remove(
0.5.118 by John Arbash Meinel
Got most of test_changeset to work. Still needs work for Aaron's test code.
509
                ['sub/sub/nonempty.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
510
                , 'sub/sub/emptyfile.txt'
0.5.118 by John Arbash Meinel
Got most of test_changeset to work. Still needs work for Aaron's test code.
511
                , 'sub/sub'
512
                ])
1185.82.68 by Aaron Bentley
Handle execute bit on modified files
513
        tt = TreeTransform(self.tree1)
514
        trans_id = tt.trans_id_tree_file_id('exe-1')
515
        tt.set_executability(False, trans_id)
516
        tt.apply()
1185.82.19 by Aaron Bentley
More API updates
517
        self.tree1.commit('removed', rev_id='a@cset-0-3')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
518
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
519
        bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
520
        self.assertRaises(TestamentMismatch, self.get_invalid_bundle, 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
521
                          'a@cset-0-2', 'a@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
522
        # Check a rollup bundle 
523
        bundle = self.get_valid_bundle(None, 'a@cset-0-3')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
524
525
526
        # Now move the directory
1185.82.19 by Aaron Bentley
More API updates
527
        self.tree1.rename_one('dir', 'sub/dir')
528
        self.tree1.commit('rename dir', rev_id='a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
529
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
530
        bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
531
        # Check a rollup bundle 
532
        bundle = self.get_valid_bundle(None, 'a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
533
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
534
        # Modified files
535
        open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
536
        open('b1/sub/dir/trailing space ', 'ab').write('\nAdding some\nDOS format lines\n')
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
537
        open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
1185.82.19 by Aaron Bentley
More API updates
538
        self.tree1.rename_one('sub/dir/trailing space ', 
539
                              'sub/ start and end space ')
540
        self.tree1.commit('Modified files', rev_id='a@cset-0-5')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
541
        bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
542
543
        # Handle international characters
1185.82.137 by Aaron Bentley
Skip unicode changeset test
544
        try:
545
            f = open(u'b1/with Dod\xe9', 'wb')
546
        except UnicodeEncodeError:
547
            raise TestSkipped("Filesystem doesn't support unicode")
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
548
        f.write((u'A file\n'
549
            u'With international man of mystery\n'
550
            u'William Dod\xe9\n').encode('utf-8'))
1185.82.19 by Aaron Bentley
More API updates
551
        self.tree1.add([u'with Dod\xe9'])
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
552
        # BUG: (sort of) You must set verbose=False, so that python doesn't try
553
        #       and print the name of William Dode as part of the commit
1185.82.19 by Aaron Bentley
More API updates
554
        self.tree1.commit(u'i18n commit from William Dod\xe9', 
555
                          rev_id='a@cset-0-6', committer=u'William Dod\xe9',
556
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
557
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
1185.82.70 by Aaron Bentley
Handle renamed files better
558
        self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
559
        self.tree1.rename_one('with space.txt', 'WithCaps.txt')
560
        self.tree1.rename_one('temp', 'with space.txt')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
561
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-7',
1185.82.70 by Aaron Bentley
Handle renamed files better
562
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
563
        bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
564
        other = self.get_checkout('a@cset-0-6')
565
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
566
        other.commit('rename file', rev_id='a@cset-0-7b')
567
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
568
        self.tree1.commit(u'Merge', rev_id='a@cset-0-8',
569
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
570
        bundle = self.get_valid_bundle('a@cset-0-7', 'a@cset-0-8')
1185.82.72 by Aaron Bentley
Always use leftmost base for changesets
571
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
572
    def test_symlink_bundle(self):
1185.82.87 by Aaron Bentley
Got symlink adding working
573
        if not has_symlinks():
574
            raise TestSkipped("No symlink support")
575
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
576
        self.b1 = self.tree1.branch
577
        tt = TreeTransform(self.tree1)
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
578
        tt.new_symlink('link', tt.root, 'bar/foo', 'link-1')
1185.82.87 by Aaron Bentley
Got symlink adding working
579
        tt.apply()
580
        self.tree1.commit('add symlink', rev_id='l@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
581
        self.get_valid_bundle(None, 'l@cset-0-1')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
582
        tt = TreeTransform(self.tree1)
583
        trans_id = tt.trans_id_tree_file_id('link-1')
584
        tt.adjust_path('link2', tt.root, trans_id)
585
        tt.delete_contents(trans_id)
586
        tt.create_symlink('mars', trans_id)
587
        tt.apply()
588
        self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
589
        self.get_valid_bundle('l@cset-0-1', 'l@cset-0-2')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
590
        tt = TreeTransform(self.tree1)
591
        trans_id = tt.trans_id_tree_file_id('link-1')
592
        tt.delete_contents(trans_id)
593
        tt.create_symlink('jupiter', trans_id)
594
        tt.apply()
595
        self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
596
        self.get_valid_bundle('l@cset-0-2', 'l@cset-0-3')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
597
        tt = TreeTransform(self.tree1)
598
        trans_id = tt.trans_id_tree_file_id('link-1')
599
        tt.delete_contents(trans_id)
600
        tt.apply()
601
        self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
602
        self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
1185.82.96 by Aaron Bentley
Got first binary test passing
603
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
604
    def test_binary_bundle(self):
1185.82.96 by Aaron Bentley
Got first binary test passing
605
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
606
        self.b1 = self.tree1.branch
607
        tt = TreeTransform(self.tree1)
608
        tt.new_file('file', tt.root, '\x00\xff', 'binary-1')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
609
        tt.new_file('file2', tt.root, '\x00\xff', 'binary-2')
1185.82.96 by Aaron Bentley
Got first binary test passing
610
        tt.apply()
611
        self.tree1.commit('add binary', rev_id='b@cset-0-1')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
612
        self.get_valid_bundle(None, 'b@cset-0-1')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
613
        tt = TreeTransform(self.tree1)
614
        trans_id = tt.trans_id_tree_file_id('binary-1')
615
        tt.delete_contents(trans_id)
616
        tt.apply()
617
        self.tree1.commit('delete binary', rev_id='b@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
618
        self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
619
        tt = TreeTransform(self.tree1)
620
        trans_id = tt.trans_id_tree_file_id('binary-2')
621
        tt.adjust_path('file3', tt.root, trans_id)
622
        tt.delete_contents(trans_id)
623
        tt.create_file('filecontents\x00', trans_id)
624
        tt.apply()
625
        self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
626
        self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
627
        tt = TreeTransform(self.tree1)
628
        trans_id = tt.trans_id_tree_file_id('binary-2')
629
        tt.delete_contents(trans_id)
630
        tt.create_file('\x00filecontents', trans_id)
631
        tt.apply()
632
        self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
633
        self.get_valid_bundle('b@cset-0-3', 'b@cset-0-4')
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
634
635
    def test_last_modified(self):
636
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
637
        self.b1 = self.tree1.branch
638
        tt = TreeTransform(self.tree1)
639
        tt.new_file('file', tt.root, 'file', 'file')
640
        tt.apply()
641
        self.tree1.commit('create file', rev_id='a@lmod-0-1')
642
643
        tt = TreeTransform(self.tree1)
644
        trans_id = tt.trans_id_tree_file_id('file')
645
        tt.delete_contents(trans_id)
646
        tt.create_file('file2', trans_id)
647
        tt.apply()
648
        self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
649
650
        other = self.get_checkout('a@lmod-0-1')
651
        tt = TreeTransform(other)
652
        trans_id = tt.trans_id_tree_file_id('file')
653
        tt.delete_contents(trans_id)
654
        tt.create_file('file2', trans_id)
655
        tt.apply()
656
        other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
657
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
658
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
659
                          verbose=False)
660
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
661
        bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')