~bzr-pqm/bzr/bzr.dev

2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
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
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
17
from cStringIO import StringIO
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
18
import os
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
19
import sys
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
20
import tempfile
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
21
1910.2.64 by Aaron Bentley
Changes from review
22
from bzrlib import (
1996.3.20 by John Arbash Meinel
[merge] bzr.dev 2063
23
    bzrdir,
24
    errors,
25
    inventory,
26
    repository,
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
27
    revision as _mod_revision,
1910.2.64 by Aaron Bentley
Changes from review
28
    treebuilder,
29
    )
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
30
from bzrlib.bzrdir import BzrDir
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
31
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
1793.2.3 by Aaron Bentley
Rename read_bundle.py to bundle_data.py
32
from bzrlib.bundle.bundle_data import BundleTree
2520.5.1 by Aaron Bentley
Test installing revisions with subtrees
33
from bzrlib.bundle.serializer import write_bundle, read_bundle, v09, v4
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
34
from bzrlib.bundle.serializer.v08 import BundleSerializerV08
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
35
from bzrlib.bundle.serializer.v09 import BundleSerializerV09
2520.4.72 by Aaron Bentley
Rename format to 4alpha
36
from bzrlib.bundle.serializer.v4 import BundleSerializerV4
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
37
from bzrlib.branch import Branch
1185.82.90 by Aaron Bentley
Reorganized test suite
38
from bzrlib.diff import internal_diff
1910.2.3 by Aaron Bentley
All tests pass
39
from bzrlib.errors import (BzrError, TestamentMismatch, NotABundle, BadBundle, 
40
                           NoSuchFile,)
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
41
from bzrlib.merge import Merge3Merger
2241.1.5 by Martin Pool
Move KnitFormat2 into repofmt
42
from bzrlib.repofmt import knitrepo
1185.82.87 by Aaron Bentley
Got symlink adding working
43
from bzrlib.osutils import has_symlinks, sha_file
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
44
from bzrlib.tests import (TestCaseInTempDir, TestCaseWithTransport,
2520.4.34 by Aaron Bentley
Add signature support
45
                          TestCase, TestSkipped, test_commit)
1185.82.66 by Aaron Bentley
Handle new executable files
46
from bzrlib.transform import TreeTransform
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
47
1185.82.90 by Aaron Bentley
Reorganized test suite
48
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
49
class MockTree(object):
50
    def __init__(self):
1731.1.4 by Aaron Bentley
merge from bzr.dev
51
        from bzrlib.inventory import InventoryDirectory, ROOT_ID
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
52
        object.__init__(self)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
53
        self.paths = {ROOT_ID: ""}
54
        self.ids = {"": ROOT_ID}
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
55
        self.contents = {}
1731.1.4 by Aaron Bentley
merge from bzr.dev
56
        self.root = InventoryDirectory(ROOT_ID, '', None)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
57
58
    inventory = property(lambda x:x)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
59
60
    def __iter__(self):
61
        return self.paths.iterkeys()
62
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
63
    def __getitem__(self, file_id):
64
        if file_id == self.root.file_id:
65
            return self.root
66
        else:
67
            return self.make_entry(file_id, self.paths[file_id])
68
69
    def parent_id(self, file_id):
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
70
        parent_dir = os.path.dirname(self.paths[file_id])
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
71
        if parent_dir == "":
72
            return None
73
        return self.ids[parent_dir]
74
75
    def iter_entries(self):
76
        for path, file_id in self.ids.iteritems():
77
            yield path, self[file_id]
78
79
    def get_file_kind(self, file_id):
80
        if file_id in self.contents:
81
            kind = 'file'
82
        else:
83
            kind = 'directory'
84
        return kind
85
86
    def make_entry(self, file_id, path):
0.5.119 by John Arbash Meinel
Recreated the factory. We really need InventoryEntry.create()
87
        from bzrlib.inventory import (InventoryEntry, InventoryFile
88
                                    , InventoryDirectory, InventoryLink)
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
89
        name = os.path.basename(path)
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
90
        kind = self.get_file_kind(file_id)
91
        parent_id = self.parent_id(file_id)
92
        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()
93
        if kind == 'directory':
94
            ie = InventoryDirectory(file_id, name, parent_id)
95
        elif kind == 'file':
96
            ie = InventoryFile(file_id, name, parent_id)
97
        elif kind == 'symlink':
98
            ie = InventoryLink(file_id, name, parent_id)
99
        else:
100
            raise BzrError('unknown kind %r' % kind)
0.5.91 by Aaron Bentley
Updated to match API change
101
        ie.text_sha1 = text_sha_1
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
102
        ie.text_size = text_size
103
        return ie
104
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
105
    def add_dir(self, file_id, path):
106
        self.paths[file_id] = path
107
        self.ids[path] = file_id
108
    
109
    def add_file(self, file_id, path, contents):
110
        self.add_dir(file_id, path)
111
        self.contents[file_id] = contents
112
113
    def path2id(self, path):
114
        return self.ids.get(path)
115
116
    def id2path(self, file_id):
117
        return self.paths.get(file_id)
118
119
    def has_id(self, file_id):
120
        return self.id2path(file_id) is not None
121
122
    def get_file(self, file_id):
123
        result = StringIO()
124
        result.write(self.contents[file_id])
125
        result.seek(0,0)
126
        return result
127
0.6.1 by Aaron Bentley
Fleshed out MockTree, fixed all test failures
128
    def contents_stats(self, file_id):
129
        if file_id not in self.contents:
130
            return None, None
131
        text_sha1 = sha_file(self.get_file(file_id))
132
        return text_sha1, len(self.contents[file_id])
133
134
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
135
class BTreeTester(TestCase):
136
    """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)
137
138
    def make_tree_1(self):
139
        mtree = MockTree()
140
        mtree.add_dir("a", "grandparent")
141
        mtree.add_dir("b", "grandparent/parent")
142
        mtree.add_file("c", "grandparent/parent/file", "Hello\n")
143
        mtree.add_dir("d", "grandparent/alt_parent")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
144
        return BundleTree(mtree, ''), mtree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
145
        
146
    def test_renames(self):
147
        """Ensure that file renames have the proper effect on children"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
148
        btree = self.make_tree_1()[0]
149
        self.assertEqual(btree.old_path("grandparent"), "grandparent")
150
        self.assertEqual(btree.old_path("grandparent/parent"), 
151
                         "grandparent/parent")
152
        self.assertEqual(btree.old_path("grandparent/parent/file"),
153
                         "grandparent/parent/file")
154
155
        self.assertEqual(btree.id2path("a"), "grandparent")
156
        self.assertEqual(btree.id2path("b"), "grandparent/parent")
157
        self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
158
159
        self.assertEqual(btree.path2id("grandparent"), "a")
160
        self.assertEqual(btree.path2id("grandparent/parent"), "b")
161
        self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
162
163
        assert btree.path2id("grandparent2") is None
164
        assert btree.path2id("grandparent2/parent") is None
165
        assert btree.path2id("grandparent2/parent/file") is None
166
167
        btree.note_rename("grandparent", "grandparent2")
168
        assert btree.old_path("grandparent") is None
169
        assert btree.old_path("grandparent/parent") is None
170
        assert btree.old_path("grandparent/parent/file") is None
171
172
        self.assertEqual(btree.id2path("a"), "grandparent2")
173
        self.assertEqual(btree.id2path("b"), "grandparent2/parent")
174
        self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
175
176
        self.assertEqual(btree.path2id("grandparent2"), "a")
177
        self.assertEqual(btree.path2id("grandparent2/parent"), "b")
178
        self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
179
180
        assert btree.path2id("grandparent") is None
181
        assert btree.path2id("grandparent/parent") is None
182
        assert btree.path2id("grandparent/parent/file") is None
183
184
        btree.note_rename("grandparent/parent", "grandparent2/parent2")
185
        self.assertEqual(btree.id2path("a"), "grandparent2")
186
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
187
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
188
189
        self.assertEqual(btree.path2id("grandparent2"), "a")
190
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
191
        self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
192
193
        assert btree.path2id("grandparent2/parent") is None
194
        assert btree.path2id("grandparent2/parent/file") is None
195
196
        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)
197
                          "grandparent2/parent2/file2")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
198
        self.assertEqual(btree.id2path("a"), "grandparent2")
199
        self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
200
        self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
201
202
        self.assertEqual(btree.path2id("grandparent2"), "a")
203
        self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
204
        self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
205
206
        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)
207
208
    def test_moves(self):
209
        """Ensure that file moves have the proper effect on children"""
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
        self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
214
        self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
215
        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)
216
217
    def unified_diff(self, old, new):
218
        out = StringIO()
219
        internal_diff("old", old, "new", new, out)
220
        out.seek(0,0)
221
        return out.read()
222
223
    def make_tree_2(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
224
        btree = self.make_tree_1()[0]
225
        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)
226
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
227
        assert btree.id2path("e") is None
228
        assert btree.path2id("grandparent/parent/file") is None
229
        btree.note_id("e", "grandparent/parent/file")
230
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
231
232
    def test_adds(self):
233
        """File/inventory adds"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
234
        btree = self.make_tree_2()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
235
        add_patch = self.unified_diff([], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
236
        btree.note_patch("grandparent/parent/file", add_patch)
237
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
238
        btree.note_target('grandparent/parent/symlink', 'venus')
239
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
240
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
241
    def adds_test(self, btree):
242
        self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
243
        self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
244
        self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
245
        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)
246
247
    def test_adds2(self):
248
        """File/inventory adds, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
249
        btree = self.make_tree_2()
250
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
251
        add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
252
        btree.note_patch("grandparent/parent/file", add_patch)
253
        btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
254
        btree.note_target('grandparent/parent/symlink', 'venus')
255
        self.adds_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
256
257
    def make_tree_3(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
258
        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)
259
        mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
260
        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)
261
                          "grandparent/alt_parent/file")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
262
        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)
263
                          "grandparent/alt_parent/stopping")
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
264
        return btree
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
265
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
266
    def get_file_test(self, btree):
267
        self.assertEqual(btree.get_file("e").read(), "Lemon\n")
268
        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)
269
270
    def test_get_file(self):
271
        """Get file contents"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
272
        btree = self.make_tree_3()
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
273
        mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
274
        btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
275
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
276
277
    def test_get_file2(self):
278
        """Get file contents, with patch-compatibile renames"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
279
        btree = self.make_tree_3()
280
        btree.contents_by_id = False
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
281
        mod_patch = self.unified_diff([], ["Lemon\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
282
        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)
283
        mod_patch = self.unified_diff([], ["Hello\n"])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
284
        btree.note_patch("grandparent/alt_parent/file", mod_patch)
285
        self.get_file_test(btree)
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
286
287
    def test_delete(self):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
288
        "Deletion by bundle"
289
        btree = self.make_tree_1()[0]
290
        self.assertEqual(btree.get_file("c").read(), "Hello\n")
291
        btree.note_deletion("grandparent/parent/file")
292
        assert btree.id2path("c") is None
293
        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)
294
295
    def sorted_ids(self, tree):
296
        ids = list(tree)
297
        ids.sort()
298
        return ids
299
300
    def test_iteration(self):
301
        """Ensure that iteration through ids works properly"""
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
302
        btree = self.make_tree_1()[0]
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
303
        self.assertEqual(self.sorted_ids(btree),
304
            [inventory.ROOT_ID, 'a', 'b', 'c', 'd'])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
305
        btree.note_deletion("grandparent/parent/file")
306
        btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
307
        btree.note_last_changed("grandparent/alt_parent/fool", 
1185.82.95 by Aaron Bentley
Restore path-orientation of ChangesetTree
308
                                "revisionidiguess")
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
309
        self.assertEqual(self.sorted_ids(btree),
310
            [inventory.ROOT_ID, 'a', 'b', 'd', 'e'])
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
311
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
312
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
313
class BundleTester1(TestCaseWithTransport):
314
315
    def test_mismatched_bundle(self):
316
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
317
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
318
        serializer = BundleSerializerV08('0.8')
319
        b = self.make_branch('.', format=format)
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
320
        self.assertRaises(errors.IncompatibleBundleFormat, serializer.write, 
1910.2.49 by Aaron Bentley
Ensure that 0.8 bundles aren't used with KnitRepository2
321
                          b.repository, [], {}, StringIO())
322
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
323
    def test_matched_bundle(self):
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
324
        """Don't raise IncompatibleBundleFormat for knit2 and bundle0.9"""
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
325
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
326
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
327
        serializer = BundleSerializerV09('0.9')
328
        b = self.make_branch('.', format=format)
329
        serializer.write(b.repository, [], {}, StringIO())
330
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
331
    def test_mismatched_model(self):
332
        """Try copying a bundle from knit2 to knit1"""
333
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
334
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
335
        source = self.make_branch_and_tree('source', format=format)
336
        source.commit('one', rev_id='one-id')
337
        source.commit('two', rev_id='two-id')
338
        text = StringIO()
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
339
        write_bundle(source.branch.repository, 'two-id', 'null:', text,
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
340
                     format='0.9')
341
        text.seek(0)
342
343
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
344
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.60 by Aaron Bentley
Ensure that new-model revisions aren't installed into old-model repos
345
        target = self.make_branch('target', format=format)
346
        self.assertRaises(errors.IncompatibleRevision, install_bundle, 
347
                          target.repository, read_bundle(text))
348
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
349
2520.4.43 by Aaron Bentley
Fix test suite
350
class BundleTester(object):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
351
352
    def bzrdir_format(self):
353
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
354
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
355
        return format
356
357
    def make_branch_and_tree(self, path, format=None):
358
        if format is None:
359
            format = self.bzrdir_format()
360
        return TestCaseWithTransport.make_branch_and_tree(self, path, format)
361
362
    def make_branch(self, path, format=None):
363
        if format is None:
364
            format = self.bzrdir_format()
365
        return TestCaseWithTransport.make_branch(self, path, format)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
366
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
367
    def create_bundle_text(self, base_rev_id, rev_id):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
368
        bundle_txt = StringIO()
369
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
370
                               bundle_txt, format=self.format)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
371
        bundle_txt.seek(0)
372
        self.assertEqual(bundle_txt.readline(), 
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
373
                         '# Bazaar revision bundle v%s\n' % self.format)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
374
        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.
375
1185.82.14 by Aaron Bentley
API updates
376
        rev = self.b1.repository.get_revision(rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
377
        self.assertEqual(bundle_txt.readline().decode('utf-8'),
378
                         u'# message:\n')
379
        bundle_txt.seek(0)
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
380
        return bundle_txt, rev_ids
381
382
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None):
383
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
384
        Make sure that the text generated is valid, and that it
385
        can be applied against the base, and generate the same information.
386
        
387
        :return: The in-memory bundle 
388
        """
389
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
390
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
391
        # This should also validate the generated bundle 
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
392
        bundle = read_bundle(bundle_txt)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
393
        repository = self.b1.repository
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
394
        for bundle_rev in bundle.real_revisions:
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
395
            # These really should have already been checked when we read the
396
            # bundle, since it computes the sha1 hash for the revision, which
397
            # only will match if everything is okay, but lets be explicit about
398
            # it
399
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1185.82.33 by Aaron Bentley
Strengthen tests
400
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
401
                      'timestamp', 'timezone', 'message', 'committer', 
402
                      'parent_ids', 'properties'):
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
403
                self.assertEqual(getattr(branch_rev, a), 
404
                                 getattr(bundle_rev, a))
405
            self.assertEqual(len(branch_rev.parent_ids), 
406
                             len(bundle_rev.parent_ids))
1185.82.47 by Aaron Bentley
Ensure all intended rev_ids end up in the revision
407
        self.assertEqual(rev_ids, 
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
408
                         [r.revision_id for r in bundle.real_revisions])
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
409
        self.valid_apply_bundle(base_rev_id, bundle,
1185.82.89 by Aaron Bentley
Remove auto_commit stuff
410
                                   checkout_dir=checkout_dir)
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
411
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
412
        return bundle
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
413
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
414
    def get_invalid_bundle(self, base_rev_id, rev_id):
415
        """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
416
        Munge the text so that it's invalid.
417
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
418
        :return: The in-memory bundle
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
419
        """
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
420
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
421
        new_text = bundle_txt.getvalue().replace('executable:no', 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
422
                                               'executable:yes')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
423
        bundle_txt = StringIO(new_text)
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
424
        bundle = read_bundle(bundle_txt)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
425
        self.valid_apply_bundle(base_rev_id, bundle)
426
        return bundle 
1185.82.118 by Aaron Bentley
Ensure that StrictTestament handles execute bit differences
427
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
428
    def test_non_bundle(self):
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
429
        self.assertRaises(NotABundle, read_bundle, StringIO('#!/bin/sh\n'))
1185.82.139 by Aaron Bentley
Raise NotABundle when a non-bundle is supplied
430
1793.2.7 by Aaron Bentley
Fix reporting of malformed, (especially, crlf) bundles
431
    def test_malformed(self):
432
        self.assertRaises(BadBundle, read_bundle, 
433
                          StringIO('# Bazaar revision bundle v'))
434
435
    def test_crlf_bundle(self):
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
436
        try:
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
437
            read_bundle(StringIO('# Bazaar revision bundle v0.8\r\n'))
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
438
        except BadBundle:
439
            # It is currently permitted for bundles with crlf line endings to
440
            # make read_bundle raise a BadBundle, but this should be fixed.
1793.2.10 by Aaron Bentley
Whitespace/comment fix
441
            # Anything else, especially NotABundle, is an error.
1793.2.9 by Aaron Bentley
Don't use assertNotRaises-- instead, catch BadBundle and pass
442
            pass
443
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
444
    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.
445
        """Get a new tree, with the specified revision in it.
446
        """
447
0.5.88 by John Arbash Meinel
Fixed a bug in the rename code, added more tests.
448
        if checkout_dir is None:
449
            checkout_dir = tempfile.mkdtemp(prefix='test-branch-', dir='.')
0.5.89 by John Arbash Meinel
Updating for explicitly defined directories.
450
        else:
451
            if not os.path.exists(checkout_dir):
452
                os.mkdir(checkout_dir)
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
453
        tree = self.make_branch_and_tree(checkout_dir)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
454
        s = StringIO()
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
455
        ancestors = write_bundle(self.b1.repository, rev_id, 'null:', s,
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
456
                                 format=self.format)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
457
        s.seek(0)
1185.82.135 by Aaron Bentley
Ensure that bundles are bytestrings
458
        assert isinstance(s.getvalue(), str), (
459
            "Bundle isn't a bytestring:\n %s..." % repr(s.getvalue())[:40])
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
460
        install_bundle(tree.branch.repository, read_bundle(s))
1185.82.41 by Aaron Bentley
More work on installing changesets
461
        for ancestor in ancestors:
462
            old = self.b1.repository.revision_tree(ancestor)
463
            new = tree.branch.repository.revision_tree(ancestor)
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
464
465
            # Check that there aren't any inventory level changes
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
466
            delta = new.changes_from(old)
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
467
            self.assertFalse(delta.has_changed(),
468
                             'Revision %s not copied correctly.'
469
                             % (ancestor,))
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
470
471
            # Now check that the file contents are all correct
1185.82.41 by Aaron Bentley
More work on installing changesets
472
            for inventory_id in old:
473
                try:
474
                    old_file = old.get_file(inventory_id)
1910.2.3 by Aaron Bentley
All tests pass
475
                except NoSuchFile:
1185.82.41 by Aaron Bentley
More work on installing changesets
476
                    continue
477
                if old_file is None:
478
                    continue
479
                self.assertEqual(old_file.read(),
480
                                 new.get_file(inventory_id).read())
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
481
        if not _mod_revision.is_null(rev_id):
1185.82.44 by Aaron Bentley
Switch to merge_changeset in test suite
482
            rh = self.b1.revision_history()
483
            tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
484
            tree.update()
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
485
            delta = tree.changes_from(self.b1.repository.revision_tree(rev_id))
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
486
            self.assertFalse(delta.has_changed(),
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
487
                             'Working tree has modifications: %s' % delta)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
488
        return tree
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
489
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
490
    def valid_apply_bundle(self, base_rev_id, info, checkout_dir=None):
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
491
        """Get the base revision, apply the changes, and make
492
        sure everything matches the builtin branch.
493
        """
1185.82.17 by Aaron Bentley
More API updates
494
        to_tree = self.get_checkout(base_rev_id, checkout_dir=checkout_dir)
1908.6.4 by Robert Collins
Update to replaced parent checking api bzrlib/merge.py
495
        original_parents = to_tree.get_parent_ids()
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
496
        repository = to_tree.branch.repository
1927.2.1 by Robert Collins
Alter set_pending_merges to shove the left most merge into the trees last-revision if that is not set. Related bugfixes include basis_tree handling ghosts, de-duping the merges with the last-revision and update changing where and how it adds its pending merge.
497
        original_parents = to_tree.get_parent_ids()
1185.82.41 by Aaron Bentley
More work on installing changesets
498
        self.assertIs(repository.has_revision(base_rev_id), True)
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
499
        for rev in info.real_revisions:
500
            self.assert_(not repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
501
                'Revision {%s} present before applying bundle' 
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
502
                % rev.revision_id)
1793.2.2 by Aaron Bentley
Move BundleReader into v07 serializer
503
        merge_bundle(info, 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.
504
505
        for rev in info.real_revisions:
1185.82.17 by Aaron Bentley
More API updates
506
            self.assert_(repository.has_revision(rev.revision_id),
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
507
                '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.
508
                % rev.revision_id)
509
1185.82.17 by Aaron Bentley
More API updates
510
        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.
511
        # 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.
512
1908.6.4 by Robert Collins
Update to replaced parent checking api bzrlib/merge.py
513
        self.assertEqual(original_parents + [info.target],
514
            to_tree.get_parent_ids())
0.5.86 by John Arbash Meinel
Updated the auto-commit functionality, and adding to pending-merges, more testing.
515
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
516
        rev = info.real_revisions[-1]
1185.82.17 by Aaron Bentley
More API updates
517
        base_tree = self.b1.repository.revision_tree(rev.revision_id)
518
        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.
519
        
520
        # 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.
521
        #       we might also check the working tree.
522
523
        base_files = list(base_tree.list_files())
524
        to_files = list(to_tree.list_files())
525
        self.assertEqual(len(base_files), len(to_files))
1185.82.66 by Aaron Bentley
Handle new executable files
526
        for base_file, to_file in zip(base_files, to_files):
527
            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.
528
0.5.117 by John Arbash Meinel
Almost there. Just need to track down a few remaining bugs.
529
        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.
530
            # Check that the meta information is the same
531
            self.assertEqual(base_tree.get_file_size(fileid),
532
                    to_tree.get_file_size(fileid))
533
            self.assertEqual(base_tree.get_file_sha1(fileid),
534
                    to_tree.get_file_sha1(fileid))
535
            # Check that the contents are the same
536
            # This is pretty expensive
537
            # self.assertEqual(base_tree.get_file(fileid).read(),
538
            #         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.
539
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
540
    def test_bundle(self):
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
541
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.14 by Aaron Bentley
API updates
542
        self.b1 = self.tree1.branch
0.5.78 by John Arbash Meinel
Working on test cases, starting with the empty project issues.
543
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
544
        open('b1/one', 'wb').write('one\n')
1185.82.14 by Aaron Bentley
API updates
545
        self.tree1.add('one')
546
        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.
547
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
548
        bundle = self.get_valid_bundle('null:', 'a@cset-0-1')
0.5.80 by John Arbash Meinel
Starting to write tests for changeset, discovering some errors as I go.
549
550
        # Make sure we can handle files with spaces, tabs, other
551
        # bogus characters
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
552
        self.build_tree([
0.5.84 by John Arbash Meinel
(broken) problem with removes.
553
                'b1/with space.txt'
554
                , 'b1/dir/'
555
                , 'b1/dir/filein subdir.c'
556
                , 'b1/dir/WithCaps.txt'
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
557
                , 'b1/dir/ pre space'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
558
                , 'b1/sub/'
559
                , 'b1/sub/sub/'
560
                , '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
561
                ])
0.5.84 by John Arbash Meinel
(broken) problem with removes.
562
        open('b1/sub/sub/emptyfile.txt', 'wb').close()
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
563
        open('b1/dir/nolastnewline.txt', 'wb').write('bloop')
1185.82.66 by Aaron Bentley
Handle new executable files
564
        tt = TreeTransform(self.tree1)
565
        tt.new_file('executable', tt.root, '#!/bin/sh\n', 'exe-1', True)
566
        tt.apply()
2520.4.84 by Aaron Bentley
Fix heisenbug record-rewriting test
567
        # have to fix length of file-id so that we can predictably rewrite
568
        # a (length-prefixed) record containing it later.
569
        self.tree1.add('with space.txt', 'withspace-id')
1185.82.14 by Aaron Bentley
API updates
570
        self.tree1.add([
2520.4.84 by Aaron Bentley
Fix heisenbug record-rewriting test
571
                  'dir'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
572
                , 'dir/filein subdir.c'
573
                , 'dir/WithCaps.txt'
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
574
                , 'dir/ pre space'
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
575
                , 'dir/nolastnewline.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
576
                , 'sub'
577
                , 'sub/sub'
578
                , 'sub/sub/nonempty.txt'
579
                , 'sub/sub/emptyfile.txt'
0.5.82 by John Arbash Meinel
Lots of changes, changing separators, updating tests, updated ChangesetTree to include text_ids
580
                ])
1185.82.14 by Aaron Bentley
API updates
581
        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.
582
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
583
        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.
584
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
585
        # Check a rollup bundle 
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
586
        bundle = self.get_valid_bundle('null:', 'a@cset-0-2')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
587
588
        # Now delete entries
1185.82.21 by Aaron Bentley
Stop using deprecated function
589
        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.
590
                ['sub/sub/nonempty.txt'
0.5.84 by John Arbash Meinel
(broken) problem with removes.
591
                , '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.
592
                , 'sub/sub'
593
                ])
1185.82.68 by Aaron Bentley
Handle execute bit on modified files
594
        tt = TreeTransform(self.tree1)
595
        trans_id = tt.trans_id_tree_file_id('exe-1')
596
        tt.set_executability(False, trans_id)
597
        tt.apply()
1185.82.19 by Aaron Bentley
More API updates
598
        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.
599
        
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
600
        bundle = self.get_valid_bundle('a@cset-0-2', 'a@cset-0-3')
2520.4.71 by Aaron Bentley
Update test to accept VersionedFileInvalidChecksum instead of TestamentMismatch
601
        self.assertRaises((TestamentMismatch,
602
            errors.VersionedFileInvalidChecksum), self.get_invalid_bundle,
603
            'a@cset-0-2', 'a@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
604
        # Check a rollup bundle 
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
605
        bundle = self.get_valid_bundle('null:', 'a@cset-0-3')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
606
607
        # Now move the directory
1185.82.19 by Aaron Bentley
More API updates
608
        self.tree1.rename_one('dir', 'sub/dir')
609
        self.tree1.commit('rename dir', rev_id='a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
610
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
611
        bundle = self.get_valid_bundle('a@cset-0-3', 'a@cset-0-4')
612
        # Check a rollup bundle 
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
613
        bundle = self.get_valid_bundle('null:', 'a@cset-0-4')
0.5.84 by John Arbash Meinel
(broken) problem with removes.
614
0.5.87 by John Arbash Meinel
Handling international characters, added more test cases.
615
        # Modified files
616
        open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
2520.4.83 by Aaron Bentley
Clean up tests
617
        open('b1/sub/dir/ pre space', 'ab').write(
618
             '\r\nAdding some\r\nDOS format lines\r\n')
0.5.94 by Aaron Bentley
Switched to native patch application, added tests for terminating newlines
619
        open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
1711.7.32 by John Arbash Meinel
Switch from a trailing space to a beginning space, which is supported everywhere.
620
        self.tree1.rename_one('sub/dir/ pre space', 
621
                              'sub/ start space')
1185.82.19 by Aaron Bentley
More API updates
622
        self.tree1.commit('Modified files', rev_id='a@cset-0-5')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
623
        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.
624
1185.82.70 by Aaron Bentley
Handle renamed files better
625
        self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
626
        self.tree1.rename_one('with space.txt', 'WithCaps.txt')
627
        self.tree1.rename_one('temp', 'with space.txt')
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
628
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
629
                          verbose=False)
630
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
631
        other = self.get_checkout('a@cset-0-5')
1910.2.62 by Aaron Bentley
Cleanups
632
        tree1_inv = self.tree1.branch.repository.get_inventory_xml(
633
            'a@cset-0-5')
1910.2.54 by Aaron Bentley
Implement testament format 3 strict
634
        tree2_inv = other.branch.repository.get_inventory_xml('a@cset-0-5')
635
        self.assertEqualDiff(tree1_inv, tree2_inv)
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
636
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
637
        other.commit('rename file', rev_id='a@cset-0-6b')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
638
        self.tree1.merge_from_branch(other.branch)
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
639
        self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
1185.82.70 by Aaron Bentley
Handle renamed files better
640
                          verbose=False)
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
641
        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
642
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
643
    def test_symlink_bundle(self):
1185.82.87 by Aaron Bentley
Got symlink adding working
644
        if not has_symlinks():
645
            raise TestSkipped("No symlink support")
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
646
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.87 by Aaron Bentley
Got symlink adding working
647
        self.b1 = self.tree1.branch
648
        tt = TreeTransform(self.tree1)
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
649
        tt.new_symlink('link', tt.root, 'bar/foo', 'link-1')
1185.82.87 by Aaron Bentley
Got symlink adding working
650
        tt.apply()
651
        self.tree1.commit('add symlink', rev_id='l@cset-0-1')
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
652
        self.get_valid_bundle('null:', 'l@cset-0-1')
1185.82.88 by Aaron Bentley
Get symlink modification, renames and deletion under test
653
        tt = TreeTransform(self.tree1)
654
        trans_id = tt.trans_id_tree_file_id('link-1')
655
        tt.adjust_path('link2', tt.root, trans_id)
656
        tt.delete_contents(trans_id)
657
        tt.create_symlink('mars', trans_id)
658
        tt.apply()
659
        self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
660
        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
661
        tt = TreeTransform(self.tree1)
662
        trans_id = tt.trans_id_tree_file_id('link-1')
663
        tt.delete_contents(trans_id)
664
        tt.create_symlink('jupiter', trans_id)
665
        tt.apply()
666
        self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
667
        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
668
        tt = TreeTransform(self.tree1)
669
        trans_id = tt.trans_id_tree_file_id('link-1')
670
        tt.delete_contents(trans_id)
671
        tt.apply()
672
        self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
673
        self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
1185.82.96 by Aaron Bentley
Got first binary test passing
674
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
675
    def test_binary_bundle(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
676
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.96 by Aaron Bentley
Got first binary test passing
677
        self.b1 = self.tree1.branch
678
        tt = TreeTransform(self.tree1)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
679
        
680
        # Add
681
        tt.new_file('file', tt.root, '\x00\n\x00\r\x01\n\x02\r\xff', 'binary-1')
2520.4.83 by Aaron Bentley
Clean up tests
682
        tt.new_file('file2', tt.root, '\x01\n\x02\r\x03\n\x04\r\xff',
683
            'binary-2')
1185.82.96 by Aaron Bentley
Got first binary test passing
684
        tt.apply()
685
        self.tree1.commit('add binary', rev_id='b@cset-0-1')
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
686
        self.get_valid_bundle('null:', 'b@cset-0-1')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
687
688
        # Delete
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
689
        tt = TreeTransform(self.tree1)
690
        trans_id = tt.trans_id_tree_file_id('binary-1')
691
        tt.delete_contents(trans_id)
692
        tt.apply()
693
        self.tree1.commit('delete binary', rev_id='b@cset-0-2')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
694
        self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
695
696
        # Rename & modify
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
697
        tt = TreeTransform(self.tree1)
698
        trans_id = tt.trans_id_tree_file_id('binary-2')
699
        tt.adjust_path('file3', tt.root, trans_id)
700
        tt.delete_contents(trans_id)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
701
        tt.create_file('file\rcontents\x00\n\x00', trans_id)
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
702
        tt.apply()
703
        self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
704
        self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
705
706
        # Modify
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
707
        tt = TreeTransform(self.tree1)
708
        trans_id = tt.trans_id_tree_file_id('binary-2')
709
        tt.delete_contents(trans_id)
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
710
        tt.create_file('\x00file\rcontents', trans_id)
1185.82.97 by Aaron Bentley
Got binary files working for adds, renames, modifications
711
        tt.apply()
712
        self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
713
        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
714
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
715
        # Rollup
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
716
        self.get_valid_bundle('null:', 'b@cset-0-4')
1848.1.1 by John Arbash Meinel
fix bug in bundle handling of binary files with just '\r' in them.
717
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
718
    def test_last_modified(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
719
        self.tree1 = self.make_branch_and_tree('b1')
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
720
        self.b1 = self.tree1.branch
721
        tt = TreeTransform(self.tree1)
722
        tt.new_file('file', tt.root, 'file', 'file')
723
        tt.apply()
724
        self.tree1.commit('create file', rev_id='a@lmod-0-1')
725
726
        tt = TreeTransform(self.tree1)
727
        trans_id = tt.trans_id_tree_file_id('file')
728
        tt.delete_contents(trans_id)
729
        tt.create_file('file2', trans_id)
730
        tt.apply()
731
        self.tree1.commit('modify text', rev_id='a@lmod-0-2a')
732
733
        other = self.get_checkout('a@lmod-0-1')
734
        tt = TreeTransform(other)
735
        trans_id = tt.trans_id_tree_file_id('file')
736
        tt.delete_contents(trans_id)
737
        tt.create_file('file2', trans_id)
738
        tt.apply()
739
        other.commit('modify text in another tree', rev_id='a@lmod-0-2b')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
740
        self.tree1.merge_from_branch(other.branch)
1185.82.115 by Aaron Bentley
Add test for last-changed special cases
741
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-3',
742
                          verbose=False)
743
        self.tree1.commit(u'Merge', rev_id='a@lmod-0-4')
1185.82.130 by Aaron Bentley
Rename changesets to revision bundles
744
        bundle = self.get_valid_bundle('a@lmod-0-2a', 'a@lmod-0-4')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
745
746
    def test_hide_history(self):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
747
        self.tree1 = self.make_branch_and_tree('b1')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
748
        self.b1 = self.tree1.branch
749
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
750
        open('b1/one', 'wb').write('one\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
751
        self.tree1.add('one')
752
        self.tree1.commit('add file', rev_id='a@cset-0-1')
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
753
        open('b1/one', 'wb').write('two\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
754
        self.tree1.commit('modify', rev_id='a@cset-0-2')
1793.3.1 by John Arbash Meinel
Clean up the bundle tests a little bit.
755
        open('b1/one', 'wb').write('three\n')
1185.84.3 by Aaron Bentley
Hide diffs for old revisions in bundles
756
        self.tree1.commit('modify', rev_id='a@cset-0-3')
757
        bundle_file = StringIO()
758
        rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-3',
1910.2.51 by Aaron Bentley
Bundles now corrupt repositories
759
                               'a@cset-0-1', bundle_file, format=self.format)
2382.1.1 by Ian Clatworthy
Fixes #98510 - bundle selftest fails if email has 'two' embedded
760
        self.assertNotContainsRe(bundle_file.getvalue(), '\btwo\b')
2520.4.32 by Aaron Bentley
Fix test case
761
        self.assertContainsRe(self.get_raw(bundle_file), 'one')
762
        self.assertContainsRe(self.get_raw(bundle_file), 'three')
763
2520.4.75 by Aaron Bentley
Fix traceback on empty bundles.
764
    def test_bundle_same_basis(self):
765
        """Ensure using the basis as the target doesn't cause an error"""
766
        self.tree1 = self.make_branch_and_tree('b1')
767
        self.tree1.commit('add file', rev_id='a@cset-0-1')
768
        bundle_file = StringIO()
769
        rev_ids = write_bundle(self.tree1.branch.repository, 'a@cset-0-1',
770
                               'a@cset-0-1', bundle_file)
771
2520.4.32 by Aaron Bentley
Fix test case
772
    @staticmethod
773
    def get_raw(bundle_file):
774
        return bundle_file.getvalue()
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
775
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
776
    def test_unicode_bundle(self):
777
        # Handle international characters
778
        os.mkdir('b1')
779
        try:
780
            f = open(u'b1/with Dod\xe9', 'wb')
781
        except UnicodeEncodeError:
782
            raise TestSkipped("Filesystem doesn't support unicode")
783
784
        self.tree1 = self.make_branch_and_tree('b1')
785
        self.b1 = self.tree1.branch
786
787
        f.write((u'A file\n'
788
            u'With international man of mystery\n'
789
            u'William Dod\xe9\n').encode('utf-8'))
790
        f.close()
791
2386.1.1 by John Arbash Meinel
Update test_unicode_bundle, since we know how it fails on Mac OSX
792
        self.tree1.add([u'with Dod\xe9'], ['withdod-id'])
793
        self.tree1.commit(u'i18n commit from William Dod\xe9',
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
794
                          rev_id='i18n-1', committer=u'William Dod\xe9')
795
2386.1.1 by John Arbash Meinel
Update test_unicode_bundle, since we know how it fails on Mac OSX
796
        if sys.platform == 'darwin':
2823.1.3 by Vincent Ladeuil
WorkingTree3 unicode related expected failure.
797
            from bzrlib.workingtree import WorkingTree3
798
            if type(self.tree1) is WorkingTree3:
2823.1.11 by Vincent Ladeuil
Review feedback.
799
                self.knownFailure("Bug #141438: fails for WorkingTree3 on OSX")
2823.1.3 by Vincent Ladeuil
WorkingTree3 unicode related expected failure.
800
2386.1.1 by John Arbash Meinel
Update test_unicode_bundle, since we know how it fails on Mac OSX
801
            # On Mac the '\xe9' gets changed to 'e\u0301'
802
            self.assertEqual([u'.bzr', u'with Dode\u0301'],
803
                             sorted(os.listdir(u'b1')))
804
            delta = self.tree1.changes_from(self.tree1.basis_tree())
805
            self.assertEqual([(u'with Dod\xe9', 'withdod-id', 'file')],
806
                             delta.removed)
807
            self.knownFailure("Mac OSX doesn't preserve unicode"
808
                              " combining characters.")
809
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
810
        # Add
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
811
        bundle = self.get_valid_bundle('null:', 'i18n-1')
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
812
813
        # Modified
814
        f = open(u'b1/with Dod\xe9', 'wb')
815
        f.write(u'Modified \xb5\n'.encode('utf8'))
816
        f.close()
817
        self.tree1.commit(u'modified', rev_id='i18n-2')
818
819
        bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
820
        
821
        # Renamed
822
        self.tree1.rename_one(u'with Dod\xe9', u'B\xe5gfors')
823
        self.tree1.commit(u'renamed, the new i18n man', rev_id='i18n-3',
824
                          committer=u'Erik B\xe5gfors')
825
826
        bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
827
828
        # Removed
829
        self.tree1.remove([u'B\xe5gfors'])
830
        self.tree1.commit(u'removed', rev_id='i18n-4')
831
832
        bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
833
834
        # Rollup
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
835
        bundle = self.get_valid_bundle('null:', 'i18n-4')
1711.7.35 by John Arbash Meinel
Factor out i18n bundle tests, so we don't always skip.
836
837
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
838
    def test_whitespace_bundle(self):
839
        if sys.platform in ('win32', 'cygwin'):
840
            raise TestSkipped('Windows doesn\'t support filenames'
841
                              ' with tabs or trailing spaces')
842
        self.tree1 = self.make_branch_and_tree('b1')
843
        self.b1 = self.tree1.branch
844
845
        self.build_tree(['b1/trailing space '])
846
        self.tree1.add(['trailing space '])
847
        # TODO: jam 20060701 Check for handling files with '\t' characters
848
        #       once we actually support them
849
850
        # Added
851
        self.tree1.commit('funky whitespace', rev_id='white-1')
852
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
853
        bundle = self.get_valid_bundle('null:', 'white-1')
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
854
855
        # Modified
856
        open('b1/trailing space ', 'ab').write('add some text\n')
857
        self.tree1.commit('add text', rev_id='white-2')
858
859
        bundle = self.get_valid_bundle('white-1', 'white-2')
860
861
        # Renamed
862
        self.tree1.rename_one('trailing space ', ' start and end space ')
863
        self.tree1.commit('rename', rev_id='white-3')
864
865
        bundle = self.get_valid_bundle('white-2', 'white-3')
866
867
        # Removed
868
        self.tree1.remove([' start and end space '])
869
        self.tree1.commit('removed', rev_id='white-4')
870
871
        bundle = self.get_valid_bundle('white-3', 'white-4')
872
        
873
        # Now test a complet roll-up
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
874
        bundle = self.get_valid_bundle('null:', 'white-4')
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
875
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
876
    def test_alt_timezone_bundle(self):
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
877
        self.tree1 = self.make_branch_and_memory_tree('b1')
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
878
        self.b1 = self.tree1.branch
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
879
        builder = treebuilder.TreeBuilder()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
880
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
881
        self.tree1.lock_write()
882
        builder.start_tree(self.tree1)
883
        builder.build(['newfile'])
884
        builder.finish_tree()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
885
886
        # Asia/Colombo offset = 5 hours 30 minutes
887
        self.tree1.commit('non-hour offset timezone', rev_id='tz-1',
888
                          timezone=19800, timestamp=1152544886.0)
889
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
890
        bundle = self.get_valid_bundle('null:', 'tz-1')
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
891
        
892
        rev = bundle.revisions[0]
893
        self.assertEqual('Mon 2006-07-10 20:51:26.000000000 +0530', rev.date)
894
        self.assertEqual(19800, rev.timezone)
895
        self.assertEqual(1152544886.0, rev.timestamp)
1986.1.2 by Robert Collins
Various changes to allow non-workingtree specific tests to run entirely
896
        self.tree1.unlock()
1793.3.9 by John Arbash Meinel
Add a test to timezone for non integer tz offsets
897
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
898
    def test_bundle_root_id(self):
899
        self.tree1 = self.make_branch_and_tree('b1')
900
        self.b1 = self.tree1.branch
901
        self.tree1.commit('message', rev_id='revid1')
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
902
        bundle = self.get_valid_bundle('null:', 'revid1')
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
903
        tree = self.get_bundle_tree(bundle, 'revid1')
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
904
        self.assertEqual('revid1', tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
905
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
906
    def test_install_revisions(self):
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
907
        self.tree1 = self.make_branch_and_tree('b1')
908
        self.b1 = self.tree1.branch
909
        self.tree1.commit('message', rev_id='rev2a')
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
910
        bundle = self.get_valid_bundle('null:', 'rev2a')
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
911
        branch2 = self.make_branch('b2')
912
        self.assertFalse(branch2.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
913
        target_revision = bundle.install_revisions(branch2.repository)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
914
        self.assertTrue(branch2.repository.has_revision('rev2a'))
1551.14.9 by Aaron Bentley
rename get_target_revision to install_revisions
915
        self.assertEqual('rev2a', target_revision)
1551.14.4 by Aaron Bentley
Change bundle reader and merge directive to both be 'mergeables'
916
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
917
    def test_bundle_empty_property(self):
918
        """Test serializing revision properties with an empty value."""
919
        tree = self.make_branch_and_memory_tree('tree')
920
        tree.lock_write()
921
        self.addCleanup(tree.unlock)
922
        tree.add([''], ['TREE_ROOT'])
923
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
924
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
925
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
926
        bundle = read_bundle(bundle_sio)
927
        revision_info = bundle.revisions[0]
928
        self.assertEqual('rev1', revision_info.revision_id)
929
        rev = revision_info.as_revision()
930
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
931
                         rev.properties)
932
933
    def test_bundle_sorted_properties(self):
934
        """For stability the writer should write properties in sorted order."""
935
        tree = self.make_branch_and_memory_tree('tree')
936
        tree.lock_write()
937
        self.addCleanup(tree.unlock)
938
939
        tree.add([''], ['TREE_ROOT'])
940
        tree.commit('One', rev_id='rev1',
941
                    revprops={'a':'4', 'b':'3', 'c':'2', 'd':'1'})
942
        self.b1 = tree.branch
2520.4.132 by Aaron Bentley
Merge from bzr.dev
943
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
944
        bundle = read_bundle(bundle_sio)
945
        revision_info = bundle.revisions[0]
946
        self.assertEqual('rev1', revision_info.revision_id)
947
        rev = revision_info.as_revision()
948
        self.assertEqual({'branch-nick':'tree', 'a':'4', 'b':'3', 'c':'2',
949
                          'd':'1'}, rev.properties)
950
951
    def test_bundle_unicode_properties(self):
952
        """We should be able to round trip a non-ascii property."""
953
        tree = self.make_branch_and_memory_tree('tree')
954
        tree.lock_write()
955
        self.addCleanup(tree.unlock)
956
957
        tree.add([''], ['TREE_ROOT'])
958
        # Revisions themselves do not require anything about revision property
959
        # keys, other than that they are a basestring, and do not contain
960
        # whitespace.
961
        # However, Testaments assert than they are str(), and thus should not
962
        # be Unicode.
963
        tree.commit('One', rev_id='rev1',
964
                    revprops={'omega':u'\u03a9', 'alpha':u'\u03b1'})
965
        self.b1 = tree.branch
2520.4.132 by Aaron Bentley
Merge from bzr.dev
966
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
967
        bundle = read_bundle(bundle_sio)
968
        revision_info = bundle.revisions[0]
969
        self.assertEqual('rev1', revision_info.revision_id)
970
        rev = revision_info.as_revision()
971
        self.assertEqual({'branch-nick':'tree', 'omega':u'\u03a9',
972
                          'alpha':u'\u03b1'}, rev.properties)
973
2520.4.43 by Aaron Bentley
Fix test suite
974
    def test_bundle_with_ghosts(self):
975
        tree = self.make_branch_and_tree('tree')
976
        self.b1 = tree.branch
977
        self.build_tree_contents([('tree/file', 'content1')])
978
        tree.add(['file'])
979
        tree.commit('rev1')
980
        self.build_tree_contents([('tree/file', 'content2')])
981
        tree.add_parent_tree_id('ghost')
982
        tree.commit('rev2', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
983
        bundle = self.get_valid_bundle('null:', 'rev2')
2520.4.43 by Aaron Bentley
Fix test suite
984
2520.4.97 by Aaron Bentley
Hack in support for inventory conversion
985
    def make_simple_tree(self, format=None):
986
        tree = self.make_branch_and_tree('b1', format=format)
987
        self.b1 = tree.branch
988
        self.build_tree(['b1/file'])
989
        tree.add('file')
990
        return tree
991
992
    def test_across_serializers(self):
993
        tree = self.make_simple_tree('knit')
994
        tree.commit('hello', rev_id='rev1')
2520.4.98 by Aaron Bentley
Support inventory conversion with parents
995
        tree.commit('hello', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
996
        bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
2520.4.97 by Aaron Bentley
Hack in support for inventory conversion
997
        repo = self.make_repository('repo', format='dirstate-with-subtree')
998
        bundle.install_revisions(repo)
2520.4.98 by Aaron Bentley
Support inventory conversion with parents
999
        inv_text = repo.get_inventory_xml('rev2')
2520.4.97 by Aaron Bentley
Hack in support for inventory conversion
1000
        self.assertNotContainsRe(inv_text, 'format="5"')
2520.4.99 by Aaron Bentley
Test conversion across models
1001
        self.assertContainsRe(inv_text, 'format="7"')
1002
1003
    def test_across_models(self):
1004
        tree = self.make_simple_tree('knit')
1005
        tree.commit('hello', rev_id='rev1')
1006
        tree.commit('hello', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1007
        bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1008
        repo = self.make_repository('repo', format='dirstate-with-subtree')
1009
        bundle.install_revisions(repo)
1010
        inv = repo.get_inventory('rev2')
1011
        self.assertEqual('rev2', inv.root.revision)
1012
        root_vf = repo.weave_store.get_weave(inv.root.file_id,
1013
                                             repo.get_transaction())
1014
        self.assertEqual(root_vf.versions(), ['rev1', 'rev2'])
1015
1016
    def test_across_models_incompatible(self):
1017
        tree = self.make_simple_tree('dirstate-with-subtree')
1018
        tree.commit('hello', rev_id='rev1')
1019
        tree.commit('hello', rev_id='rev2')
1020
        try:
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1021
            bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1022
        except errors.IncompatibleBundleFormat:
1023
            raise TestSkipped("Format 0.8 doesn't work with knit3")
1024
        repo = self.make_repository('repo', format='knit')
1025
        bundle.install_revisions(repo)
1026
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1027
        bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1028
        self.assertRaises(errors.IncompatibleRevision,
1029
                          bundle.install_revisions, repo)
2520.4.97 by Aaron Bentley
Hack in support for inventory conversion
1030
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
1031
    def test_get_merge_request(self):
1032
        tree = self.make_simple_tree()
1033
        tree.commit('hello', rev_id='rev1')
1034
        tree.commit('hello', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1035
        bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
1036
        result = bundle.get_merge_request(tree.branch.repository)
1037
        self.assertEqual((None, 'rev1', 'inapplicable'), result)
1038
2520.5.1 by Aaron Bentley
Test installing revisions with subtrees
1039
    def test_with_subtree(self):
1040
        tree = self.make_branch_and_tree('tree',
1041
                                         format='dirstate-with-subtree')
1042
        self.b1 = tree.branch
1043
        subtree = self.make_branch_and_tree('tree/subtree',
1044
                                            format='dirstate-with-subtree')
1045
        tree.add('subtree')
1046
        tree.commit('hello', rev_id='rev1')
1047
        try:
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1048
            bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.5.1 by Aaron Bentley
Test installing revisions with subtrees
1049
        except errors.IncompatibleBundleFormat:
1050
            raise TestSkipped("Format 0.8 doesn't work with knit3")
1051
        if isinstance(bundle, v09.BundleInfo09):
1052
            raise TestSkipped("Format 0.9 doesn't work with subtrees")
1053
        repo = self.make_repository('repo', format='knit')
1054
        self.assertRaises(errors.IncompatibleRevision,
1055
                          bundle.install_revisions, repo)
1056
        repo2 = self.make_repository('repo2', format='dirstate-with-subtree')
1057
        bundle.install_revisions(repo2)
1058
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1059
    def test_revision_id_with_slash(self):
1060
        self.tree1 = self.make_branch_and_tree('tree')
1061
        self.b1 = self.tree1.branch
1062
        try:
1063
            self.tree1.commit('Revision/id/with/slashes', rev_id='rev/id')
1064
        except ValueError:
1065
            raise TestSkipped("Repository doesn't support revision ids with"
1066
                              " slashes")
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1067
        bundle = self.get_valid_bundle('null:', 'rev/id')
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1068
2520.6.2 by Aaron Bentley
Fix bundle installation wrong-versionedfile bug
1069
    def test_skip_file(self):
1070
        """Make sure we don't accidentally write to the wrong versionedfile"""
1071
        self.tree1 = self.make_branch_and_tree('tree')
1072
        self.b1 = self.tree1.branch
1073
        # rev1 is not present in bundle, done by fetch
1074
        self.build_tree_contents([('tree/file2', 'contents1')])
1075
        self.tree1.add('file2', 'file2-id')
1076
        self.tree1.commit('rev1', rev_id='reva')
1077
        self.build_tree_contents([('tree/file3', 'contents2')])
1078
        # rev2 is present in bundle, and done by fetch
1079
        # having file1 in the bunle causes file1's versionedfile to be opened.
1080
        self.tree1.add('file3', 'file3-id')
1081
        self.tree1.commit('rev2')
1082
        # Updating file2 should not cause an attempt to add to file1's vf
1083
        target = self.tree1.bzrdir.sprout('target').open_workingtree()
1084
        self.build_tree_contents([('tree/file2', 'contents3')])
1085
        self.tree1.commit('rev3', rev_id='rev3')
1086
        bundle = self.get_valid_bundle('reva', 'rev3')
2520.6.5 by Aaron Bentley
Skip for bundle formats that don't provide get_bundle_reader
1087
        if getattr(bundle, 'get_bundle_reader', None) is None:
1088
            raise TestSkipped('Bundle format cannot provide reader')
2520.6.2 by Aaron Bentley
Fix bundle installation wrong-versionedfile bug
1089
        # be sure that file1 comes before file2
1090
        for b, m, k, r, f in bundle.get_bundle_reader().iter_records():
1091
            if f == 'file3-id':
1092
                break
1093
            self.assertNotEqual(f, 'file2-id')
1094
        bundle.install_revisions(target.branch.repository)
1095
2520.4.43 by Aaron Bentley
Fix test suite
1096
1097
class V08BundleTester(BundleTester, TestCaseWithTransport):
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
1098
1099
    format = '0.8'
1100
1101
    def test_bundle_empty_property(self):
1102
        """Test serializing revision properties with an empty value."""
1103
        tree = self.make_branch_and_memory_tree('tree')
1104
        tree.lock_write()
1105
        self.addCleanup(tree.unlock)
1106
        tree.add([''], ['TREE_ROOT'])
1107
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1108
        self.b1 = tree.branch
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1109
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1110
        self.assertContainsRe(bundle_sio.getvalue(),
1111
                              '# properties:\n'
1112
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1113
                              '#   empty: \n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1114
                              '#   one: two\n'
1115
                             )
1116
        bundle = read_bundle(bundle_sio)
1117
        revision_info = bundle.revisions[0]
1118
        self.assertEqual('rev1', revision_info.revision_id)
1119
        rev = revision_info.as_revision()
1120
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1121
                         rev.properties)
1122
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1123
    def get_bundle_tree(self, bundle, revision_id):
1124
        repository = self.make_repository('repo')
1125
        return bundle.revision_tree(repository, 'revid1')
1126
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1127
    def test_bundle_empty_property_alt(self):
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1128
        """Test serializing revision properties with an empty value.
1129
1130
        Older readers had a bug when reading an empty property.
1131
        They assumed that all keys ended in ': \n'. However they would write an
1132
        empty value as ':\n'. This tests make sure that all newer bzr versions
1133
        can handle th second form.
1134
        """
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1135
        tree = self.make_branch_and_memory_tree('tree')
1136
        tree.lock_write()
1137
        self.addCleanup(tree.unlock)
1138
        tree.add([''], ['TREE_ROOT'])
1139
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1140
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1141
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1142
        txt = bundle_sio.getvalue()
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1143
        loc = txt.find('#   empty: ') + len('#   empty:')
1144
        # Create a new bundle, which strips the trailing space after empty
1145
        bundle_sio = StringIO(txt[:loc] + txt[loc+1:])
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1146
1147
        self.assertContainsRe(bundle_sio.getvalue(),
1148
                              '# properties:\n'
1149
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1150
                              '#   empty:\n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1151
                              '#   one: two\n'
1152
                             )
1153
        bundle = read_bundle(bundle_sio)
1154
        revision_info = bundle.revisions[0]
1155
        self.assertEqual('rev1', revision_info.revision_id)
1156
        rev = revision_info.as_revision()
1157
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1158
                         rev.properties)
1159
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1160
    def test_bundle_sorted_properties(self):
1161
        """For stability the writer should write properties in sorted order."""
1162
        tree = self.make_branch_and_memory_tree('tree')
1163
        tree.lock_write()
1164
        self.addCleanup(tree.unlock)
1165
1166
        tree.add([''], ['TREE_ROOT'])
1167
        tree.commit('One', rev_id='rev1',
1168
                    revprops={'a':'4', 'b':'3', 'c':'2', 'd':'1'})
1169
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1170
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1171
        self.assertContainsRe(bundle_sio.getvalue(),
1172
                              '# properties:\n'
1173
                              '#   a: 4\n'
1174
                              '#   b: 3\n'
1175
                              '#   branch-nick: tree\n'
1176
                              '#   c: 2\n'
1177
                              '#   d: 1\n'
1178
                             )
2447.1.4 by John Arbash Meinel
Add a test that we properly round-trip unicode properties.
1179
        bundle = read_bundle(bundle_sio)
1180
        revision_info = bundle.revisions[0]
1181
        self.assertEqual('rev1', revision_info.revision_id)
1182
        rev = revision_info.as_revision()
1183
        self.assertEqual({'branch-nick':'tree', 'a':'4', 'b':'3', 'c':'2',
1184
                          'd':'1'}, rev.properties)
1185
1186
    def test_bundle_unicode_properties(self):
1187
        """We should be able to round trip a non-ascii property."""
1188
        tree = self.make_branch_and_memory_tree('tree')
1189
        tree.lock_write()
1190
        self.addCleanup(tree.unlock)
1191
1192
        tree.add([''], ['TREE_ROOT'])
1193
        # Revisions themselves do not require anything about revision property
1194
        # keys, other than that they are a basestring, and do not contain
1195
        # whitespace.
1196
        # However, Testaments assert than they are str(), and thus should not
1197
        # be Unicode.
1198
        tree.commit('One', rev_id='rev1',
1199
                    revprops={'omega':u'\u03a9', 'alpha':u'\u03b1'})
1200
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1201
        bundle_sio, revision_ids = self.create_bundle_text('null:', 'rev1')
2447.1.4 by John Arbash Meinel
Add a test that we properly round-trip unicode properties.
1202
        self.assertContainsRe(bundle_sio.getvalue(),
1203
                              '# properties:\n'
1204
                              '#   alpha: \xce\xb1\n'
1205
                              '#   branch-nick: tree\n'
1206
                              '#   omega: \xce\xa9\n'
1207
                             )
1208
        bundle = read_bundle(bundle_sio)
1209
        revision_info = bundle.revisions[0]
1210
        self.assertEqual('rev1', revision_info.revision_id)
1211
        rev = revision_info.as_revision()
1212
        self.assertEqual({'branch-nick':'tree', 'omega':u'\u03a9',
1213
                          'alpha':u'\u03b1'}, rev.properties)
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1214
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1215
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1216
class V09BundleKnit2Tester(V08BundleTester):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1217
1218
    format = '0.9'
1219
1220
    def bzrdir_format(self):
1221
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
1222
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1223
        return format
1224
1225
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1226
class V09BundleKnit1Tester(V08BundleTester):
1227
1228
    format = '0.9'
1229
1230
    def bzrdir_format(self):
1231
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1232
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1233
        return format
1234
1235
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1236
class V4BundleTester(BundleTester, TestCaseWithTransport):
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1237
2520.4.136 by Aaron Bentley
Fix format strings
1238
    format = '4'
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1239
1240
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None):
1241
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1242
        Make sure that the text generated is valid, and that it
1243
        can be applied against the base, and generate the same information.
1244
        
1245
        :return: The in-memory bundle 
1246
        """
1247
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1248
1249
        # This should also validate the generated bundle 
1250
        bundle = read_bundle(bundle_txt)
1251
        repository = self.b1.repository
1252
        for bundle_rev in bundle.real_revisions:
1253
            # These really should have already been checked when we read the
1254
            # bundle, since it computes the sha1 hash for the revision, which
1255
            # only will match if everything is okay, but lets be explicit about
1256
            # it
1257
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1258
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
1259
                      'timestamp', 'timezone', 'message', 'committer', 
1260
                      'parent_ids', 'properties'):
1261
                self.assertEqual(getattr(branch_rev, a), 
1262
                                 getattr(bundle_rev, a))
1263
            self.assertEqual(len(branch_rev.parent_ids), 
1264
                             len(bundle_rev.parent_ids))
2520.4.29 by Aaron Bentley
Reactivate some testing, fix topo_iter
1265
        self.assertEqual(set(rev_ids),
1266
                         set([r.revision_id for r in bundle.real_revisions]))
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1267
        self.valid_apply_bundle(base_rev_id, bundle,
1268
                                   checkout_dir=checkout_dir)
1269
1270
        return bundle
1271
2520.4.34 by Aaron Bentley
Add signature support
1272
    def get_invalid_bundle(self, base_rev_id, rev_id):
1273
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1274
        Munge the text so that it's invalid.
1275
1276
        :return: The in-memory bundle
1277
        """
1278
        from bzrlib.bundle import serializer
1279
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1280
        new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1281
        new_text = new_text.replace('<file file_id="exe-1"',
1282
                                    '<file executable="y" file_id="exe-1"')
2520.4.143 by Aaron Bentley
Fix invalid bundle test
1283
        new_text = new_text.replace('B222', 'B237')
2520.4.34 by Aaron Bentley
Add signature support
1284
        bundle_txt = StringIO()
2520.4.136 by Aaron Bentley
Fix format strings
1285
        bundle_txt.write(serializer._get_bundle_header('4'))
2520.4.34 by Aaron Bentley
Add signature support
1286
        bundle_txt.write('\n')
2520.4.76 by Aaron Bentley
Move base64-encoding into merge directives
1287
        bundle_txt.write(new_text.encode('bz2'))
2520.4.34 by Aaron Bentley
Add signature support
1288
        bundle_txt.seek(0)
1289
        bundle = read_bundle(bundle_txt)
1290
        self.valid_apply_bundle(base_rev_id, bundle)
1291
        return bundle
1292
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1293
    def create_bundle_text(self, base_rev_id, rev_id):
1294
        bundle_txt = StringIO()
1295
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
1296
                               bundle_txt, format=self.format)
1297
        bundle_txt.seek(0)
1298
        self.assertEqual(bundle_txt.readline(), 
1299
                         '# Bazaar revision bundle v%s\n' % self.format)
1300
        self.assertEqual(bundle_txt.readline(), '#\n')
1301
        rev = self.b1.repository.get_revision(rev_id)
1302
        bundle_txt.seek(0)
1303
        return bundle_txt, rev_ids
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1304
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1305
    def get_bundle_tree(self, bundle, revision_id):
1306
        repository = self.make_repository('repo')
1307
        bundle.install_revisions(repository)
1308
        return repository.revision_tree(revision_id)
1309
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1310
    def test_creation(self):
1311
        tree = self.make_branch_and_tree('tree')
2520.4.8 by Aaron Bentley
Serialize inventory
1312
        self.build_tree_contents([('tree/file', 'contents1\nstatic\n')])
2520.4.6 by Aaron Bentley
Get installation started
1313
        tree.add('file', 'fileid-2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1314
        tree.commit('added file', rev_id='rev1')
2520.4.8 by Aaron Bentley
Serialize inventory
1315
        self.build_tree_contents([('tree/file', 'contents2\nstatic\n')])
2520.4.10 by Aaron Bentley
Enable installation of revisions
1316
        tree.commit('changed file', rev_id='rev2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1317
        s = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1318
        serializer = BundleSerializerV4('1.0')
2520.4.8 by Aaron Bentley
Serialize inventory
1319
        serializer.write(tree.branch.repository, ['rev1', 'rev2'], {}, s)
2520.4.5 by Aaron Bentley
Start work on reading mpbundles
1320
        s.seek(0)
2520.4.6 by Aaron Bentley
Get installation started
1321
        tree2 = self.make_branch_and_tree('target')
1322
        target_repo = tree2.branch.repository
1323
        install_bundle(target_repo, serializer.read(s))
1324
        vf = target_repo.weave_store.get_weave('fileid-2',
1325
            target_repo.get_transaction())
2520.4.8 by Aaron Bentley
Serialize inventory
1326
        self.assertEqual('contents1\nstatic\n', vf.get_text('rev1'))
1327
        self.assertEqual('contents2\nstatic\n', vf.get_text('rev2'))
1328
        rtree = target_repo.revision_tree('rev2')
2520.4.9 by Aaron Bentley
Test inventory_vf parents
1329
        inventory_vf = target_repo.get_inventory_weave()
1330
        self.assertEqual(['rev1'], inventory_vf.get_parents('rev2'))
2520.4.10 by Aaron Bentley
Enable installation of revisions
1331
        self.assertEqual('changed file',
1332
                         target_repo.get_revision('rev2').message)
2520.4.6 by Aaron Bentley
Get installation started
1333
2520.4.32 by Aaron Bentley
Fix test case
1334
    @staticmethod
1335
    def get_raw(bundle_file):
1336
        bundle_file.seek(0)
2520.4.70 by Aaron Bentley
Yank patch-handling functionality
1337
        line = bundle_file.readline()
1338
        line = bundle_file.readline()
2520.4.32 by Aaron Bentley
Fix test case
1339
        lines = bundle_file.readlines()
2520.4.76 by Aaron Bentley
Move base64-encoding into merge directives
1340
        return ''.join(lines).decode('bz2')
2520.4.32 by Aaron Bentley
Fix test case
1341
2520.4.34 by Aaron Bentley
Add signature support
1342
    def test_copy_signatures(self):
1343
        tree_a = self.make_branch_and_tree('tree_a')
1344
        import bzrlib.gpg
1345
        import bzrlib.commit as commit
1346
        oldstrategy = bzrlib.gpg.GPGStrategy
1347
        branch = tree_a.branch
1348
        repo_a = branch.repository
1349
        tree_a.commit("base", allow_pointless=True, rev_id='A')
1350
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
1351
        try:
1352
            from bzrlib.testament import Testament
1353
            # monkey patch gpg signing mechanism
1354
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
1355
            new_config = test_commit.MustSignConfig(branch)
1356
            commit.Commit(config=new_config).commit(message="base",
1357
                                                    allow_pointless=True,
1358
                                                    rev_id='B',
1359
                                                    working_tree=tree_a)
1360
            def sign(text):
1361
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1362
            self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1363
        finally:
1364
            bzrlib.gpg.GPGStrategy = oldstrategy
1365
        tree_b = self.make_branch_and_tree('tree_b')
1366
        repo_b = tree_b.branch.repository
1367
        s = StringIO()
2520.4.136 by Aaron Bentley
Fix format strings
1368
        serializer = BundleSerializerV4('4')
2520.4.34 by Aaron Bentley
Add signature support
1369
        serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1370
        s.seek(0)
1371
        install_bundle(repo_b, serializer.read(s))
1372
        self.assertTrue(repo_b.has_signature_for_revision_id('B'))
1373
        self.assertEqual(repo_b.get_signature_text('B'),
1374
                         repo_a.get_signature_text('B'))
2520.4.100 by Aaron Bentley
Fix repeat signature installs
1375
        s.seek(0)
1376
        # ensure repeat installs are harmless
1377
        install_bundle(repo_b, serializer.read(s))
2520.4.34 by Aaron Bentley
Add signature support
1378
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1379
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
1380
class V4WeaveBundleTester(V4BundleTester):
1381
1382
    def bzrdir_format(self):
2520.4.91 by Aaron Bentley
Okay, so I meant metaweave. I think.
1383
        return 'metaweave'
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
1384
1385
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1386
class MungedBundleTester(object):
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1387
1388
    def build_test_bundle(self):
1389
        wt = self.make_branch_and_tree('b1')
1390
1391
        self.build_tree(['b1/one'])
1392
        wt.add('one')
1393
        wt.commit('add one', rev_id='a@cset-0-1')
1394
        self.build_tree(['b1/two'])
1395
        wt.add('two')
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1396
        wt.commit('add two', rev_id='a@cset-0-2',
1397
                  revprops={'branch-nick':'test'})
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1398
1399
        bundle_txt = StringIO()
1400
        rev_ids = write_bundle(wt.branch.repository, 'a@cset-0-2',
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1401
                               'a@cset-0-1', bundle_txt, self.format)
1402
        self.assertEqual(set(['a@cset-0-2']), set(rev_ids))
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1403
        bundle_txt.seek(0, 0)
1404
        return bundle_txt
1405
1406
    def check_valid(self, bundle):
1407
        """Check that after whatever munging, the final object is valid."""
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1408
        self.assertEqual(['a@cset-0-2'],
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1409
            [r.revision_id for r in bundle.real_revisions])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1410
1411
    def test_extra_whitespace(self):
1412
        bundle_txt = self.build_test_bundle()
1413
1414
        # Seek to the end of the file
1415
        # Adding one extra newline used to give us
1416
        # TypeError: float() argument must be a string or a number
1417
        bundle_txt.seek(0, 2)
1418
        bundle_txt.write('\n')
1419
        bundle_txt.seek(0)
1420
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1421
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1422
        self.check_valid(bundle)
1423
1424
    def test_extra_whitespace_2(self):
1425
        bundle_txt = self.build_test_bundle()
1426
1427
        # Seek to the end of the file
1428
        # Adding two extra newlines used to give us
1429
        # MalformedPatches: The first line of all patches should be ...
1430
        bundle_txt.seek(0, 2)
1431
        bundle_txt.write('\n\n')
1432
        bundle_txt.seek(0)
1433
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1434
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1435
        self.check_valid(bundle)
1436
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1437
1438
class MungedBundleTesterV09(TestCaseWithTransport, MungedBundleTester):
1439
1440
    format = '0.9'
1441
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1442
    def test_missing_trailing_whitespace(self):
1443
        bundle_txt = self.build_test_bundle()
1444
1445
        # Remove a trailing newline, it shouldn't kill the parser
1446
        raw = bundle_txt.getvalue()
1447
        # The contents of the bundle don't have to be this, but this
1448
        # test is concerned with the exact case where the serializer
1449
        # creates a blank line at the end, and fails if that
1450
        # line is stripped
1451
        self.assertEqual('\n\n', raw[-2:])
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1452
        bundle_txt = StringIO(raw[:-1])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1453
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1454
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1455
        self.check_valid(bundle)
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1456
1793.3.16 by John Arbash Meinel
Add tests to ensure that we gracefully handle opening and trailing non-bundle text.
1457
    def test_opening_text(self):
1458
        bundle_txt = self.build_test_bundle()
1459
1460
        bundle_txt = StringIO("Some random\nemail comments\n"
1461
                              + bundle_txt.getvalue())
1462
1463
        bundle = read_bundle(bundle_txt)
1464
        self.check_valid(bundle)
1465
1466
    def test_trailing_text(self):
1467
        bundle_txt = self.build_test_bundle()
1468
1469
        bundle_txt = StringIO(bundle_txt.getvalue() +
1470
                              "Some trailing\nrandom\ntext\n")
1471
1472
        bundle = read_bundle(bundle_txt)
1473
        self.check_valid(bundle)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1474
1475
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1476
class MungedBundleTesterV4(TestCaseWithTransport, MungedBundleTester):
1477
2520.4.136 by Aaron Bentley
Fix format strings
1478
    format = '4'
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1479
1480
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1481
class TestBundleWriterReader(TestCase):
1482
1483
    def test_roundtrip_record(self):
1484
        fileobj = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1485
        writer = v4.BundleWriter(fileobj)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1486
        writer.begin()
2520.4.95 by Aaron Bentley
Add support for header/info records
1487
        writer.add_info_record(foo='bar')
1488
        writer._add_record("Record body", {'parents': ['1', '3'],
1489
            'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1490
        writer.end()
1491
        fileobj.seek(0)
2520.4.148 by Aaron Bentley
Updates from review
1492
        reader = v4.BundleReader(fileobj, stream_input=True)
2520.4.145 by Aaron Bentley
Add memory_friendly toggle, be memory-unfriendly for merge directives
1493
        record_iter = reader.iter_records()
1494
        record = record_iter.next()
1495
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1496
            'info', None, None), record)
1497
        record = record_iter.next()
1498
        self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1499
                          'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1500
                          record)
1501
1502
    def test_roundtrip_record_memory_hungry(self):
1503
        fileobj = StringIO()
1504
        writer = v4.BundleWriter(fileobj)
1505
        writer.begin()
1506
        writer.add_info_record(foo='bar')
1507
        writer._add_record("Record body", {'parents': ['1', '3'],
1508
            'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
1509
        writer.end()
1510
        fileobj.seek(0)
2520.4.148 by Aaron Bentley
Updates from review
1511
        reader = v4.BundleReader(fileobj, stream_input=False)
2520.4.145 by Aaron Bentley
Add memory_friendly toggle, be memory-unfriendly for merge directives
1512
        record_iter = reader.iter_records()
2520.4.95 by Aaron Bentley
Add support for header/info records
1513
        record = record_iter.next()
1514
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1515
            'info', None, None), record)
1516
        record = record_iter.next()
1517
        self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1518
                          'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1519
                          record)
1520
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1521
    def test_encode_name(self):
2520.4.95 by Aaron Bentley
Add support for header/info records
1522
        self.assertEqual('revision/rev1',
1523
            v4.BundleWriter.encode_name('revision', 'rev1'))
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1524
        self.assertEqual('file/rev//1/file-id-1',
1525
            v4.BundleWriter.encode_name('file', 'rev/1', 'file-id-1'))
2520.4.95 by Aaron Bentley
Add support for header/info records
1526
        self.assertEqual('info',
1527
            v4.BundleWriter.encode_name('info', None, None))
1528
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1529
    def test_decode_name(self):
2520.4.95 by Aaron Bentley
Add support for header/info records
1530
        self.assertEqual(('revision', 'rev1', None),
1531
            v4.BundleReader.decode_name('revision/rev1'))
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1532
        self.assertEqual(('file', 'rev/1', 'file-id-1'),
1533
            v4.BundleReader.decode_name('file/rev//1/file-id-1'))
2520.4.95 by Aaron Bentley
Add support for header/info records
1534
        self.assertEqual(('info', None, None),
1535
                         v4.BundleReader.decode_name('info'))
2520.4.131 by Aaron Bentley
Raise BadBundle for records with wrong number of names
1536
1537
    def test_too_many_names(self):
1538
        fileobj = StringIO()
1539
        writer = v4.BundleWriter(fileobj)
1540
        writer.begin()
1541
        writer.add_info_record(foo='bar')
1542
        writer._container.add_bytes_record('blah', ['two', 'names'])
1543
        writer.end()
1544
        fileobj.seek(0)
1545
        record_iter = v4.BundleReader(fileobj).iter_records()
1546
        record = record_iter.next()
1547
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1548
            'info', None, None), record)
1549
        self.assertRaises(BadBundle, record_iter.next)