~bzr-pqm/bzr/bzr.dev

2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
16
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
17
from cStringIO import StringIO
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
18
import os
1711.7.34 by John Arbash Meinel
Include a test to ensure bundles handle trailing whitespace.
19
import sys
1711.7.27 by John Arbash Meinel
Investigating why test_bundle fails, something isn't transmitting properly.
20
import tempfile
0.5.66 by John Arbash Meinel
Refactoring, moving test code into test (switching back to assert is None)
21
1910.2.64 by Aaron Bentley
Changes from review
22
from bzrlib import (
1996.3.20 by John Arbash Meinel
[merge] bzr.dev 2063
23
    bzrdir,
24
    errors,
25
    inventory,
26
    repository,
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
27
    revision as _mod_revision,
1910.2.64 by Aaron Bentley
Changes from review
28
    treebuilder,
29
    )
1185.82.40 by Aaron Bentley
Started work on testing install_revisions/handling empty changesets
30
from bzrlib.bzrdir import BzrDir
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
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
45
from bzrlib.osutils import sha_file
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
1018
    def test_across_models(self):
1019
        tree = self.make_simple_tree('knit')
1020
        tree.commit('hello', rev_id='rev1')
1021
        tree.commit('hello', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1022
        bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1023
        repo = self.make_repository('repo', format='dirstate-with-subtree')
1024
        bundle.install_revisions(repo)
1025
        inv = repo.get_inventory('rev2')
1026
        self.assertEqual('rev2', inv.root.revision)
1027
        root_vf = repo.weave_store.get_weave(inv.root.file_id,
1028
                                             repo.get_transaction())
1029
        self.assertEqual(root_vf.versions(), ['rev1', 'rev2'])
1030
1031
    def test_across_models_incompatible(self):
1032
        tree = self.make_simple_tree('dirstate-with-subtree')
1033
        tree.commit('hello', rev_id='rev1')
1034
        tree.commit('hello', rev_id='rev2')
1035
        try:
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1036
            bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1037
        except errors.IncompatibleBundleFormat:
1038
            raise TestSkipped("Format 0.8 doesn't work with knit3")
1039
        repo = self.make_repository('repo', format='knit')
1040
        bundle.install_revisions(repo)
1041
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1042
        bundle = read_bundle(self.create_bundle_text('null:', 'rev2')[0])
2520.4.99 by Aaron Bentley
Test conversion across models
1043
        self.assertRaises(errors.IncompatibleRevision,
1044
                          bundle.install_revisions, repo)
2520.4.97 by Aaron Bentley
Hack in support for inventory conversion
1045
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
1046
    def test_get_merge_request(self):
1047
        tree = self.make_simple_tree()
1048
        tree.commit('hello', rev_id='rev1')
1049
        tree.commit('hello', rev_id='rev2')
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1050
        bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.4.109 by Aaron Bentley
start work on directive cherry-picking
1051
        result = bundle.get_merge_request(tree.branch.repository)
1052
        self.assertEqual((None, 'rev1', 'inapplicable'), result)
1053
2520.5.1 by Aaron Bentley
Test installing revisions with subtrees
1054
    def test_with_subtree(self):
1055
        tree = self.make_branch_and_tree('tree',
1056
                                         format='dirstate-with-subtree')
1057
        self.b1 = tree.branch
1058
        subtree = self.make_branch_and_tree('tree/subtree',
1059
                                            format='dirstate-with-subtree')
1060
        tree.add('subtree')
1061
        tree.commit('hello', rev_id='rev1')
1062
        try:
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1063
            bundle = read_bundle(self.create_bundle_text('null:', 'rev1')[0])
2520.5.1 by Aaron Bentley
Test installing revisions with subtrees
1064
        except errors.IncompatibleBundleFormat:
1065
            raise TestSkipped("Format 0.8 doesn't work with knit3")
1066
        if isinstance(bundle, v09.BundleInfo09):
1067
            raise TestSkipped("Format 0.9 doesn't work with subtrees")
1068
        repo = self.make_repository('repo', format='knit')
1069
        self.assertRaises(errors.IncompatibleRevision,
1070
                          bundle.install_revisions, repo)
1071
        repo2 = self.make_repository('repo2', format='dirstate-with-subtree')
1072
        bundle.install_revisions(repo2)
1073
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1074
    def test_revision_id_with_slash(self):
1075
        self.tree1 = self.make_branch_and_tree('tree')
1076
        self.b1 = self.tree1.branch
1077
        try:
1078
            self.tree1.commit('Revision/id/with/slashes', rev_id='rev/id')
1079
        except ValueError:
1080
            raise TestSkipped("Repository doesn't support revision ids with"
1081
                              " slashes")
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1082
        bundle = self.get_valid_bundle('null:', 'rev/id')
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1083
2520.6.2 by Aaron Bentley
Fix bundle installation wrong-versionedfile bug
1084
    def test_skip_file(self):
1085
        """Make sure we don't accidentally write to the wrong versionedfile"""
1086
        self.tree1 = self.make_branch_and_tree('tree')
1087
        self.b1 = self.tree1.branch
1088
        # rev1 is not present in bundle, done by fetch
1089
        self.build_tree_contents([('tree/file2', 'contents1')])
1090
        self.tree1.add('file2', 'file2-id')
1091
        self.tree1.commit('rev1', rev_id='reva')
1092
        self.build_tree_contents([('tree/file3', 'contents2')])
1093
        # rev2 is present in bundle, and done by fetch
1094
        # having file1 in the bunle causes file1's versionedfile to be opened.
1095
        self.tree1.add('file3', 'file3-id')
1096
        self.tree1.commit('rev2')
1097
        # Updating file2 should not cause an attempt to add to file1's vf
1098
        target = self.tree1.bzrdir.sprout('target').open_workingtree()
1099
        self.build_tree_contents([('tree/file2', 'contents3')])
1100
        self.tree1.commit('rev3', rev_id='rev3')
1101
        bundle = self.get_valid_bundle('reva', 'rev3')
2520.6.5 by Aaron Bentley
Skip for bundle formats that don't provide get_bundle_reader
1102
        if getattr(bundle, 'get_bundle_reader', None) is None:
1103
            raise TestSkipped('Bundle format cannot provide reader')
2520.6.2 by Aaron Bentley
Fix bundle installation wrong-versionedfile bug
1104
        # be sure that file1 comes before file2
1105
        for b, m, k, r, f in bundle.get_bundle_reader().iter_records():
1106
            if f == 'file3-id':
1107
                break
1108
            self.assertNotEqual(f, 'file2-id')
1109
        bundle.install_revisions(target.branch.repository)
1110
2520.4.43 by Aaron Bentley
Fix test suite
1111
1112
class V08BundleTester(BundleTester, TestCaseWithTransport):
2520.4.33 by Aaron Bentley
remove test dependencies on serialization minutia
1113
1114
    format = '0.8'
1115
1116
    def test_bundle_empty_property(self):
1117
        """Test serializing revision properties with an empty value."""
1118
        tree = self.make_branch_and_memory_tree('tree')
1119
        tree.lock_write()
1120
        self.addCleanup(tree.unlock)
1121
        tree.add([''], ['TREE_ROOT'])
1122
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1123
        self.b1 = tree.branch
2520.4.132 by Aaron Bentley
Merge from bzr.dev
1124
        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'.
1125
        self.assertContainsRe(bundle_sio.getvalue(),
1126
                              '# properties:\n'
1127
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1128
                              '#   empty: \n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1129
                              '#   one: two\n'
1130
                             )
1131
        bundle = read_bundle(bundle_sio)
1132
        revision_info = bundle.revisions[0]
1133
        self.assertEqual('rev1', revision_info.revision_id)
1134
        rev = revision_info.as_revision()
1135
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1136
                         rev.properties)
1137
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1138
    def get_bundle_tree(self, bundle, revision_id):
1139
        repository = self.make_repository('repo')
1140
        return bundle.revision_tree(repository, 'revid1')
1141
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1142
    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.
1143
        """Test serializing revision properties with an empty value.
1144
1145
        Older readers had a bug when reading an empty property.
1146
        They assumed that all keys ended in ': \n'. However they would write an
1147
        empty value as ':\n'. This tests make sure that all newer bzr versions
1148
        can handle th second form.
1149
        """
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1150
        tree = self.make_branch_and_memory_tree('tree')
1151
        tree.lock_write()
1152
        self.addCleanup(tree.unlock)
1153
        tree.add([''], ['TREE_ROOT'])
1154
        tree.commit('One', revprops={'one':'two', 'empty':''}, rev_id='rev1')
1155
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1156
        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'.
1157
        txt = bundle_sio.getvalue()
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1158
        loc = txt.find('#   empty: ') + len('#   empty:')
1159
        # Create a new bundle, which strips the trailing space after empty
1160
        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'.
1161
1162
        self.assertContainsRe(bundle_sio.getvalue(),
1163
                              '# properties:\n'
1164
                              '#   branch-nick: tree\n'
2447.1.3 by John Arbash Meinel
Change the default serializer to include a trailing whitespace for empty properties.
1165
                              '#   empty:\n'
2447.1.2 by John Arbash Meinel
Add tests that we handle empty values whether they end in ': \n' or ':\n'.
1166
                              '#   one: two\n'
1167
                             )
1168
        bundle = read_bundle(bundle_sio)
1169
        revision_info = bundle.revisions[0]
1170
        self.assertEqual('rev1', revision_info.revision_id)
1171
        rev = revision_info.as_revision()
1172
        self.assertEqual({'branch-nick':'tree', 'empty':'', 'one':'two'},
1173
                         rev.properties)
1174
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1175
    def test_bundle_sorted_properties(self):
1176
        """For stability the writer should write properties in sorted order."""
1177
        tree = self.make_branch_and_memory_tree('tree')
1178
        tree.lock_write()
1179
        self.addCleanup(tree.unlock)
1180
1181
        tree.add([''], ['TREE_ROOT'])
1182
        tree.commit('One', rev_id='rev1',
1183
                    revprops={'a':'4', 'b':'3', 'c':'2', 'd':'1'})
1184
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1185
        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.
1186
        self.assertContainsRe(bundle_sio.getvalue(),
1187
                              '# properties:\n'
1188
                              '#   a: 4\n'
1189
                              '#   b: 3\n'
1190
                              '#   branch-nick: tree\n'
1191
                              '#   c: 2\n'
1192
                              '#   d: 1\n'
1193
                             )
2447.1.4 by John Arbash Meinel
Add a test that we properly round-trip unicode properties.
1194
        bundle = read_bundle(bundle_sio)
1195
        revision_info = bundle.revisions[0]
1196
        self.assertEqual('rev1', revision_info.revision_id)
1197
        rev = revision_info.as_revision()
1198
        self.assertEqual({'branch-nick':'tree', 'a':'4', 'b':'3', 'c':'2',
1199
                          'd':'1'}, rev.properties)
1200
1201
    def test_bundle_unicode_properties(self):
1202
        """We should be able to round trip a non-ascii property."""
1203
        tree = self.make_branch_and_memory_tree('tree')
1204
        tree.lock_write()
1205
        self.addCleanup(tree.unlock)
1206
1207
        tree.add([''], ['TREE_ROOT'])
1208
        # Revisions themselves do not require anything about revision property
1209
        # keys, other than that they are a basestring, and do not contain
1210
        # whitespace.
1211
        # However, Testaments assert than they are str(), and thus should not
1212
        # be Unicode.
1213
        tree.commit('One', rev_id='rev1',
1214
                    revprops={'omega':u'\u03a9', 'alpha':u'\u03b1'})
1215
        self.b1 = tree.branch
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
1216
        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.
1217
        self.assertContainsRe(bundle_sio.getvalue(),
1218
                              '# properties:\n'
1219
                              '#   alpha: \xce\xb1\n'
1220
                              '#   branch-nick: tree\n'
1221
                              '#   omega: \xce\xa9\n'
1222
                             )
1223
        bundle = read_bundle(bundle_sio)
1224
        revision_info = bundle.revisions[0]
1225
        self.assertEqual('rev1', revision_info.revision_id)
1226
        rev = revision_info.as_revision()
1227
        self.assertEqual({'branch-nick':'tree', 'omega':u'\u03a9',
1228
                          'alpha':u'\u03b1'}, rev.properties)
2447.1.1 by John Arbash Meinel
For stability and ease of testing, write properties in sorted order.
1229
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1230
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1231
class V09BundleKnit2Tester(V08BundleTester):
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1232
1233
    format = '0.9'
1234
1235
    def bzrdir_format(self):
1236
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
1237
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.50 by Aaron Bentley
start work on format 0.9 serializer
1238
        return format
1239
1240
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1241
class V09BundleKnit1Tester(V08BundleTester):
1242
1243
    format = '0.9'
1244
1245
    def bzrdir_format(self):
1246
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
1247
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.59 by Aaron Bentley
Test 0.9 bundles for knit format1 and knit format2
1248
        return format
1249
1250
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1251
class V4BundleTester(BundleTester, TestCaseWithTransport):
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1252
2520.4.136 by Aaron Bentley
Fix format strings
1253
    format = '4'
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1254
1255
    def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None):
1256
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1257
        Make sure that the text generated is valid, and that it
1258
        can be applied against the base, and generate the same information.
1259
        
1260
        :return: The in-memory bundle 
1261
        """
1262
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1263
1264
        # This should also validate the generated bundle 
1265
        bundle = read_bundle(bundle_txt)
1266
        repository = self.b1.repository
1267
        for bundle_rev in bundle.real_revisions:
1268
            # These really should have already been checked when we read the
1269
            # bundle, since it computes the sha1 hash for the revision, which
1270
            # only will match if everything is okay, but lets be explicit about
1271
            # it
1272
            branch_rev = repository.get_revision(bundle_rev.revision_id)
1273
            for a in ('inventory_sha1', 'revision_id', 'parent_ids',
1274
                      'timestamp', 'timezone', 'message', 'committer', 
1275
                      'parent_ids', 'properties'):
1276
                self.assertEqual(getattr(branch_rev, a), 
1277
                                 getattr(bundle_rev, a))
1278
            self.assertEqual(len(branch_rev.parent_ids), 
1279
                             len(bundle_rev.parent_ids))
2520.4.29 by Aaron Bentley
Reactivate some testing, fix topo_iter
1280
        self.assertEqual(set(rev_ids),
1281
                         set([r.revision_id for r in bundle.real_revisions]))
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1282
        self.valid_apply_bundle(base_rev_id, bundle,
1283
                                   checkout_dir=checkout_dir)
1284
1285
        return bundle
1286
2520.4.34 by Aaron Bentley
Add signature support
1287
    def get_invalid_bundle(self, base_rev_id, rev_id):
1288
        """Create a bundle from base_rev_id -> rev_id in built-in branch.
1289
        Munge the text so that it's invalid.
1290
1291
        :return: The in-memory bundle
1292
        """
1293
        from bzrlib.bundle import serializer
1294
        bundle_txt, rev_ids = self.create_bundle_text(base_rev_id, rev_id)
1295
        new_text = self.get_raw(StringIO(''.join(bundle_txt)))
1296
        new_text = new_text.replace('<file file_id="exe-1"',
1297
                                    '<file executable="y" file_id="exe-1"')
2520.4.143 by Aaron Bentley
Fix invalid bundle test
1298
        new_text = new_text.replace('B222', 'B237')
2520.4.34 by Aaron Bentley
Add signature support
1299
        bundle_txt = StringIO()
2520.4.136 by Aaron Bentley
Fix format strings
1300
        bundle_txt.write(serializer._get_bundle_header('4'))
2520.4.34 by Aaron Bentley
Add signature support
1301
        bundle_txt.write('\n')
2520.4.76 by Aaron Bentley
Move base64-encoding into merge directives
1302
        bundle_txt.write(new_text.encode('bz2'))
2520.4.34 by Aaron Bentley
Add signature support
1303
        bundle_txt.seek(0)
1304
        bundle = read_bundle(bundle_txt)
1305
        self.valid_apply_bundle(base_rev_id, bundle)
1306
        return bundle
1307
2520.4.14 by Aaron Bentley
Get most tests passing, use format header
1308
    def create_bundle_text(self, base_rev_id, rev_id):
1309
        bundle_txt = StringIO()
1310
        rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id, 
1311
                               bundle_txt, format=self.format)
1312
        bundle_txt.seek(0)
1313
        self.assertEqual(bundle_txt.readline(), 
1314
                         '# Bazaar revision bundle v%s\n' % self.format)
1315
        self.assertEqual(bundle_txt.readline(), '#\n')
1316
        rev = self.b1.repository.get_revision(rev_id)
1317
        bundle_txt.seek(0)
1318
        return bundle_txt, rev_ids
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1319
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1320
    def get_bundle_tree(self, bundle, revision_id):
1321
        repository = self.make_repository('repo')
1322
        bundle.install_revisions(repository)
1323
        return repository.revision_tree(revision_id)
1324
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1325
    def test_creation(self):
1326
        tree = self.make_branch_and_tree('tree')
2520.4.8 by Aaron Bentley
Serialize inventory
1327
        self.build_tree_contents([('tree/file', 'contents1\nstatic\n')])
2520.4.6 by Aaron Bentley
Get installation started
1328
        tree.add('file', 'fileid-2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1329
        tree.commit('added file', rev_id='rev1')
2520.4.8 by Aaron Bentley
Serialize inventory
1330
        self.build_tree_contents([('tree/file', 'contents2\nstatic\n')])
2520.4.10 by Aaron Bentley
Enable installation of revisions
1331
        tree.commit('changed file', rev_id='rev2')
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1332
        s = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1333
        serializer = BundleSerializerV4('1.0')
2520.4.8 by Aaron Bentley
Serialize inventory
1334
        serializer.write(tree.branch.repository, ['rev1', 'rev2'], {}, s)
2520.4.5 by Aaron Bentley
Start work on reading mpbundles
1335
        s.seek(0)
2520.4.6 by Aaron Bentley
Get installation started
1336
        tree2 = self.make_branch_and_tree('target')
1337
        target_repo = tree2.branch.repository
1338
        install_bundle(target_repo, serializer.read(s))
1339
        vf = target_repo.weave_store.get_weave('fileid-2',
1340
            target_repo.get_transaction())
2520.4.8 by Aaron Bentley
Serialize inventory
1341
        self.assertEqual('contents1\nstatic\n', vf.get_text('rev1'))
1342
        self.assertEqual('contents2\nstatic\n', vf.get_text('rev2'))
1343
        rtree = target_repo.revision_tree('rev2')
2520.4.9 by Aaron Bentley
Test inventory_vf parents
1344
        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.
1345
        self.assertEqual({'rev2':('rev1',)},
1346
            inventory_vf.get_parent_map(['rev2']))
2520.4.10 by Aaron Bentley
Enable installation of revisions
1347
        self.assertEqual('changed file',
1348
                         target_repo.get_revision('rev2').message)
2520.4.6 by Aaron Bentley
Get installation started
1349
2520.4.32 by Aaron Bentley
Fix test case
1350
    @staticmethod
1351
    def get_raw(bundle_file):
1352
        bundle_file.seek(0)
2520.4.70 by Aaron Bentley
Yank patch-handling functionality
1353
        line = bundle_file.readline()
1354
        line = bundle_file.readline()
2520.4.32 by Aaron Bentley
Fix test case
1355
        lines = bundle_file.readlines()
2520.4.76 by Aaron Bentley
Move base64-encoding into merge directives
1356
        return ''.join(lines).decode('bz2')
2520.4.32 by Aaron Bentley
Fix test case
1357
2520.4.34 by Aaron Bentley
Add signature support
1358
    def test_copy_signatures(self):
1359
        tree_a = self.make_branch_and_tree('tree_a')
1360
        import bzrlib.gpg
1361
        import bzrlib.commit as commit
1362
        oldstrategy = bzrlib.gpg.GPGStrategy
1363
        branch = tree_a.branch
1364
        repo_a = branch.repository
1365
        tree_a.commit("base", allow_pointless=True, rev_id='A')
1366
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
1367
        try:
1368
            from bzrlib.testament import Testament
1369
            # monkey patch gpg signing mechanism
1370
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
1371
            new_config = test_commit.MustSignConfig(branch)
1372
            commit.Commit(config=new_config).commit(message="base",
1373
                                                    allow_pointless=True,
1374
                                                    rev_id='B',
1375
                                                    working_tree=tree_a)
1376
            def sign(text):
1377
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
1378
            self.assertTrue(repo_a.has_signature_for_revision_id('B'))
1379
        finally:
1380
            bzrlib.gpg.GPGStrategy = oldstrategy
1381
        tree_b = self.make_branch_and_tree('tree_b')
1382
        repo_b = tree_b.branch.repository
1383
        s = StringIO()
2520.4.136 by Aaron Bentley
Fix format strings
1384
        serializer = BundleSerializerV4('4')
2520.4.34 by Aaron Bentley
Add signature support
1385
        serializer.write(tree_a.branch.repository, ['A', 'B'], {}, s)
1386
        s.seek(0)
1387
        install_bundle(repo_b, serializer.read(s))
1388
        self.assertTrue(repo_b.has_signature_for_revision_id('B'))
1389
        self.assertEqual(repo_b.get_signature_text('B'),
1390
                         repo_a.get_signature_text('B'))
2520.4.100 by Aaron Bentley
Fix repeat signature installs
1391
        s.seek(0)
1392
        # ensure repeat installs are harmless
1393
        install_bundle(repo_b, serializer.read(s))
2520.4.34 by Aaron Bentley
Add signature support
1394
2520.4.4 by Aaron Bentley
Get basis support for a new bundle format in place
1395
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
1396
class V4WeaveBundleTester(V4BundleTester):
1397
1398
    def bzrdir_format(self):
2520.4.91 by Aaron Bentley
Okay, so I meant metaweave. I think.
1399
        return 'metaweave'
2520.4.90 by Aaron Bentley
Handle \r terminated lines in Weaves properly
1400
1401
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1402
class MungedBundleTester(object):
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1403
1404
    def build_test_bundle(self):
1405
        wt = self.make_branch_and_tree('b1')
1406
1407
        self.build_tree(['b1/one'])
1408
        wt.add('one')
1409
        wt.commit('add one', rev_id='a@cset-0-1')
1410
        self.build_tree(['b1/two'])
1411
        wt.add('two')
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1412
        wt.commit('add two', rev_id='a@cset-0-2',
1413
                  revprops={'branch-nick':'test'})
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1414
1415
        bundle_txt = StringIO()
1416
        rev_ids = write_bundle(wt.branch.repository, 'a@cset-0-2',
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1417
                               'a@cset-0-1', bundle_txt, self.format)
1418
        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
1419
        bundle_txt.seek(0, 0)
1420
        return bundle_txt
1421
1422
    def check_valid(self, bundle):
1423
        """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
1424
        self.assertEqual(['a@cset-0-2'],
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1425
            [r.revision_id for r in bundle.real_revisions])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1426
1427
    def test_extra_whitespace(self):
1428
        bundle_txt = self.build_test_bundle()
1429
1430
        # Seek to the end of the file
1431
        # Adding one extra newline used to give us
1432
        # TypeError: float() argument must be a string or a number
1433
        bundle_txt.seek(0, 2)
1434
        bundle_txt.write('\n')
1435
        bundle_txt.seek(0)
1436
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1437
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1438
        self.check_valid(bundle)
1439
1440
    def test_extra_whitespace_2(self):
1441
        bundle_txt = self.build_test_bundle()
1442
1443
        # Seek to the end of the file
1444
        # Adding two extra newlines used to give us
1445
        # MalformedPatches: The first line of all patches should be ...
1446
        bundle_txt.seek(0, 2)
1447
        bundle_txt.write('\n\n')
1448
        bundle_txt.seek(0)
1449
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1450
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1451
        self.check_valid(bundle)
1452
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1453
1454
class MungedBundleTesterV09(TestCaseWithTransport, MungedBundleTester):
1455
1456
    format = '0.9'
1457
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1458
    def test_missing_trailing_whitespace(self):
1459
        bundle_txt = self.build_test_bundle()
1460
1461
        # Remove a trailing newline, it shouldn't kill the parser
1462
        raw = bundle_txt.getvalue()
1463
        # The contents of the bundle don't have to be this, but this
1464
        # test is concerned with the exact case where the serializer
1465
        # creates a blank line at the end, and fails if that
1466
        # line is stripped
1467
        self.assertEqual('\n\n', raw[-2:])
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1468
        bundle_txt = StringIO(raw[:-1])
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1469
1793.3.4 by John Arbash Meinel
[merge] bzr.dev 1804 and fix conflicts.
1470
        bundle = read_bundle(bundle_txt)
1793.3.2 by John Arbash Meinel
(failing) add some tests which munge trailing whitespace
1471
        self.check_valid(bundle)
1793.3.14 by John Arbash Meinel
Actually fix the bug with missing trailing newline bug #49182
1472
1793.3.16 by John Arbash Meinel
Add tests to ensure that we gracefully handle opening and trailing non-bundle text.
1473
    def test_opening_text(self):
1474
        bundle_txt = self.build_test_bundle()
1475
1476
        bundle_txt = StringIO("Some random\nemail comments\n"
1477
                              + bundle_txt.getvalue())
1478
1479
        bundle = read_bundle(bundle_txt)
1480
        self.check_valid(bundle)
1481
1482
    def test_trailing_text(self):
1483
        bundle_txt = self.build_test_bundle()
1484
1485
        bundle_txt = StringIO(bundle_txt.getvalue() +
1486
                              "Some trailing\nrandom\ntext\n")
1487
1488
        bundle = read_bundle(bundle_txt)
1489
        self.check_valid(bundle)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1490
1491
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1492
class MungedBundleTesterV4(TestCaseWithTransport, MungedBundleTester):
1493
2520.4.136 by Aaron Bentley
Fix format strings
1494
    format = '4'
2520.4.79 by Aaron Bentley
Fixed up not-really-relevant munging tests
1495
1496
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1497
class TestBundleWriterReader(TestCase):
1498
1499
    def test_roundtrip_record(self):
1500
        fileobj = StringIO()
2520.4.72 by Aaron Bentley
Rename format to 4alpha
1501
        writer = v4.BundleWriter(fileobj)
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1502
        writer.begin()
2520.4.95 by Aaron Bentley
Add support for header/info records
1503
        writer.add_info_record(foo='bar')
1504
        writer._add_record("Record body", {'parents': ['1', '3'],
1505
            'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
2520.4.56 by Aaron Bentley
Begin adding support for arbitrary metadata
1506
        writer.end()
1507
        fileobj.seek(0)
2520.4.148 by Aaron Bentley
Updates from review
1508
        reader = v4.BundleReader(fileobj, stream_input=True)
2520.4.145 by Aaron Bentley
Add memory_friendly toggle, be memory-unfriendly for merge directives
1509
        record_iter = reader.iter_records()
1510
        record = record_iter.next()
1511
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1512
            'info', None, None), record)
1513
        record = record_iter.next()
1514
        self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1515
                          'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1516
                          record)
1517
1518
    def test_roundtrip_record_memory_hungry(self):
1519
        fileobj = StringIO()
1520
        writer = v4.BundleWriter(fileobj)
1521
        writer.begin()
1522
        writer.add_info_record(foo='bar')
1523
        writer._add_record("Record body", {'parents': ['1', '3'],
1524
            'storage_kind':'fulltext'}, 'file', 'revid', 'fileid')
1525
        writer.end()
1526
        fileobj.seek(0)
2520.4.148 by Aaron Bentley
Updates from review
1527
        reader = v4.BundleReader(fileobj, stream_input=False)
2520.4.145 by Aaron Bentley
Add memory_friendly toggle, be memory-unfriendly for merge directives
1528
        record_iter = reader.iter_records()
2520.4.95 by Aaron Bentley
Add support for header/info records
1529
        record = record_iter.next()
1530
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1531
            'info', None, None), record)
1532
        record = record_iter.next()
1533
        self.assertEqual(("Record body", {'storage_kind': 'fulltext',
1534
                          'parents': ['1', '3']}, 'file', 'revid', 'fileid'),
1535
                          record)
1536
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1537
    def test_encode_name(self):
2520.4.95 by Aaron Bentley
Add support for header/info records
1538
        self.assertEqual('revision/rev1',
1539
            v4.BundleWriter.encode_name('revision', 'rev1'))
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1540
        self.assertEqual('file/rev//1/file-id-1',
1541
            v4.BundleWriter.encode_name('file', 'rev/1', 'file-id-1'))
2520.4.95 by Aaron Bentley
Add support for header/info records
1542
        self.assertEqual('info',
1543
            v4.BundleWriter.encode_name('info', None, None))
1544
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1545
    def test_decode_name(self):
2520.4.95 by Aaron Bentley
Add support for header/info records
1546
        self.assertEqual(('revision', 'rev1', None),
1547
            v4.BundleReader.decode_name('revision/rev1'))
2520.4.127 by Aaron Bentley
Fix up name encoding to handle revision-ids with slashes
1548
        self.assertEqual(('file', 'rev/1', 'file-id-1'),
1549
            v4.BundleReader.decode_name('file/rev//1/file-id-1'))
2520.4.95 by Aaron Bentley
Add support for header/info records
1550
        self.assertEqual(('info', None, None),
1551
                         v4.BundleReader.decode_name('info'))
2520.4.131 by Aaron Bentley
Raise BadBundle for records with wrong number of names
1552
1553
    def test_too_many_names(self):
1554
        fileobj = StringIO()
1555
        writer = v4.BundleWriter(fileobj)
1556
        writer.begin()
1557
        writer.add_info_record(foo='bar')
1558
        writer._container.add_bytes_record('blah', ['two', 'names'])
1559
        writer.end()
1560
        fileobj.seek(0)
1561
        record_iter = v4.BundleReader(fileobj).iter_records()
1562
        record = record_iter.next()
1563
        self.assertEqual((None, {'foo': 'bar', 'storage_kind': 'header'},
1564
            'info', None, None), record)
1565
        self.assertRaises(BadBundle, record_iter.next)
3251.4.11 by Aaron Bentley
Fix wrong local lookups
1566
1567
1568
class TestReadMergeableFromUrl(TestCaseWithTransport):
1569
1570
    def test_read_mergeable_skips_local(self):
1571
        """A local bundle named like the URL should not be read.
1572
        """
1573
        out, wt = test_read_bundle.create_bundle_file(self)
1574
        class FooService(object):
1575
            """A directory service that always returns source"""
1576
1577
            def look_up(self, name, url):
1578
                return 'source'
3251.4.12 by Aaron Bentley
Updates from review
1579
        directories.register('foo:', FooService, 'Testing directory service')
3251.4.11 by Aaron Bentley
Fix wrong local lookups
1580
        self.addCleanup(lambda: directories.remove('foo:'))
1581
        self.build_tree_contents([('./foo:bar', out.getvalue())])
1582
        self.assertRaises(errors.NotABundle, read_mergeable_from_url,
1583
                          'foo:bar')