/brz/remove-bazaar

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