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