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