/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2241.1.5 by Martin Pool
Move KnitFormat2 into repofmt
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
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
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
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
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
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
16
17
"""Tests for bzrdir implementations - tests a bzrdir format."""
18
2520.4.54 by Aaron Bentley
Hang a create_bundle method off repository
19
from cStringIO import StringIO
1666.1.6 by Robert Collins
Make knit the default format.
20
import re
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
21
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
22
import bzrlib
1752.2.87 by Andrew Bennetts
Make tests pass.
23
from bzrlib import (
24
    bzrdir,
25
    errors,
26
    remote,
27
    repository,
28
    )
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
29
from bzrlib.delta import TreeDelta
1731.1.33 by Aaron Bentley
Revert no-special-root changes
30
from bzrlib.inventory import Inventory, InventoryDirectory
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
31
from bzrlib.revision import NULL_REVISION
2279.7.9 by Andrew Bennetts
Remove some redundant code pointed out by Robert's review, and remove some unused imports while I'm there.
32
from bzrlib.tests import TestCaseWithTransport, TestSkipped
2485.7.1 by Robert Collins
Relocate TestCaseWithRepository to be more central.
33
from bzrlib.tests.repository_implementations import TestCaseWithRepository
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
34
from bzrlib.transport import get_transport
35
from bzrlib.upgrade import upgrade
36
from bzrlib.workingtree import WorkingTree
37
38
2018.5.66 by Wouter van Heyst
Fix repository test parameterization for RemoteRepository.
39
class TestRepositoryMakeBranchAndTree(TestCaseWithRepository):
40
41
    def test_repository_format(self):
2018.5.119 by Robert Collins
Unbreak TestRepositoryMakeBranchAndTree.
42
        # make sure the repository on tree.branch is of the desired format,
43
        # because developers use this api to setup the tree, branch and 
44
        # repository for their tests: having it now give the right repository
45
        # type would invalidate the tests.
2018.5.66 by Wouter van Heyst
Fix repository test parameterization for RemoteRepository.
46
        tree = self.make_branch_and_tree('repo')
47
        self.assertIsInstance(tree.branch.repository._format,
48
            self.repository_format.__class__)
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
49
50
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
51
class TestRepository(TestCaseWithRepository):
52
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
53
    def test_clone_to_default_format(self):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
54
        #TODO: Test that cloning a repository preserves all the information
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
55
        # such as signatures[not tested yet] etc etc.
56
        # when changing to the current default format.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
57
        tree_a = self.make_branch_and_tree('a')
2381.1.3 by Robert Collins
Review feedback.
58
        self.build_tree(['a/foo'])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
59
        tree_a.add('foo', 'file1')
60
        tree_a.commit('rev1', rev_id='rev1')
61
        bzrdirb = self.make_bzrdir('b')
62
        repo_b = tree_a.branch.repository.clone(bzrdirb)
63
        tree_b = repo_b.revision_tree('rev1')
64
        tree_b.get_file_text('file1')
65
        rev1 = repo_b.get_revision('rev1')
66
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
67
    def test_supports_rich_root(self):
68
        tree = self.make_branch_and_tree('a')
69
        tree.commit('')
70
        second_revision = tree.commit('')
71
        inv = tree.branch.repository.revision_tree(second_revision).inventory
72
        rich_root = (inv.root.revision != second_revision)
2018.5.113 by Robert Collins
Test only fixes from the ported-to-bzr.dev test-correctness branch.
73
        self.assertEqual(rich_root,
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
74
                         tree.branch.repository.supports_rich_root())
75
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
76
    def test_clone_specific_format(self):
77
        """todo"""
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
78
79
    def test_format_initialize_find_open(self):
80
        # loopback test to check the current format initializes to itself.
81
        if not self.repository_format.is_supported():
82
            # unsupported formats are not loopback testable
83
            # because the default open will not open them and
84
            # they may not be initializable.
85
            return
86
        # supported formats must be able to init and open
87
        t = get_transport(self.get_url())
88
        readonly_t = get_transport(self.get_readonly_url())
89
        made_control = self.bzrdir_format.initialize(t.base)
90
        made_repo = self.repository_format.initialize(made_control)
91
        self.assertEqual(made_control, made_repo.bzrdir)
92
93
        # find it via bzrdir opening:
94
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
95
        direct_opened_repo = opened_control.open_repository()
96
        self.assertEqual(direct_opened_repo.__class__, made_repo.__class__)
97
        self.assertEqual(opened_control, direct_opened_repo.bzrdir)
98
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
99
        self.assertIsInstance(direct_opened_repo._format,
100
                              self.repository_format.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
101
        # find it via Repository.open
102
        opened_repo = repository.Repository.open(readonly_t.base)
103
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
104
        self.assertEqual(made_repo._format.__class__,
105
                         opened_repo._format.__class__)
106
        # if it has a unique id string, can we probe for it ?
107
        try:
108
            self.repository_format.get_format_string()
109
        except NotImplementedError:
110
            return
111
        self.assertEqual(self.repository_format,
112
                         repository.RepositoryFormat.find_format(opened_control))
113
114
    def test_create_repository(self):
1534.6.1 by Robert Collins
allow API creation of shared repositories
115
        # bzrdir can construct a repository for itself.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
116
        if not self.bzrdir_format.is_supported():
117
            # unsupported formats are not loopback testable
118
            # because the default open will not open them and
119
            # they may not be initializable.
120
            return
121
        t = get_transport(self.get_url())
122
        made_control = self.bzrdir_format.initialize(t.base)
123
        made_repo = made_control.create_repository()
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
124
        # Check that we have a repository object.
125
        made_repo.has_revision('foo')
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
126
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.1 by Robert Collins
allow API creation of shared repositories
127
        
128
    def test_create_repository_shared(self):
129
        # bzrdir can construct a shared repository.
130
        if not self.bzrdir_format.is_supported():
131
            # unsupported formats are not loopback testable
132
            # because the default open will not open them and
133
            # they may not be initializable.
134
            return
135
        t = get_transport(self.get_url())
136
        made_control = self.bzrdir_format.initialize(t.base)
137
        try:
138
            made_repo = made_control.create_repository(shared=True)
139
        except errors.IncompatibleFormat:
140
            # not all repository formats understand being shared, or
141
            # may only be shared in some circumstances.
142
            return
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
143
        # Check that we have a repository object.
144
        made_repo.has_revision('foo')
1534.6.1 by Robert Collins
allow API creation of shared repositories
145
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
146
        self.assertTrue(made_repo.is_shared())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
147
148
    def test_revision_tree(self):
149
        wt = self.make_branch_and_tree('.')
1731.1.33 by Aaron Bentley
Revert no-special-root changes
150
        wt.set_root_id('fixed-root')
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
151
        wt.commit('lala!', rev_id='revision-1', allow_pointless=True)
152
        tree = wt.branch.repository.revision_tree('revision-1')
1731.1.45 by Aaron Bentley
Merge bzr.dev
153
        self.assertEqual('revision-1', tree.inventory.root.revision) 
154
        expected = InventoryDirectory('fixed-root', '', None)
155
        expected.revision = 'revision-1'
156
        self.assertEqual([('', 'V', 'directory', 'fixed-root', expected)],
1731.1.54 by Aaron Bentley
Fix revision_tree tests
157
                         list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
158
        tree = wt.branch.repository.revision_tree(None)
1731.1.54 by Aaron Bentley
Fix revision_tree tests
159
        self.assertEqual([], list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
160
        tree = wt.branch.repository.revision_tree(NULL_REVISION)
1731.1.54 by Aaron Bentley
Fix revision_tree tests
161
        self.assertEqual([], list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
162
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
163
    def test_get_revision_delta(self):
164
        tree_a = self.make_branch_and_tree('a')
2381.1.3 by Robert Collins
Review feedback.
165
        self.build_tree(['a/foo'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
166
        tree_a.add('foo', 'file1')
167
        tree_a.commit('rev1', rev_id='rev1')
2381.1.3 by Robert Collins
Review feedback.
168
        self.build_tree(['a/vla'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
169
        tree_a.add('vla', 'file2')
170
        tree_a.commit('rev2', rev_id='rev2')
171
172
        delta = tree_a.branch.repository.get_revision_delta('rev1')
173
        self.assertIsInstance(delta, TreeDelta)
174
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
175
        delta = tree_a.branch.repository.get_revision_delta('rev2')
176
        self.assertIsInstance(delta, TreeDelta)
177
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
178
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
179
    def test_clone_bzrdir_repository_revision(self):
180
        # make a repository with some revisions,
181
        # and clone it, this should not have unreferenced revisions.
182
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
183
        raise TestSkipped('revision limiting is not implemented yet.')
184
185
    def test_clone_repository_basis_revision(self):
186
        raise TestSkipped('the use of a basis should not add noise data to the result.')
187
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
188
    def test_clone_shared_no_tree(self):
189
        # cloning a shared repository keeps it shared
190
        # and preserves the make_working_tree setting.
191
        made_control = self.make_bzrdir('source')
192
        try:
193
            made_repo = made_control.create_repository(shared=True)
194
        except errors.IncompatibleFormat:
195
            # not all repository formats understand being shared, or
196
            # may only be shared in some circumstances.
197
            return
2018.14.2 by Andrew Bennetts
All but one repository_implementation tests for RemoteRepository passing.
198
        try:
199
            made_repo.set_make_working_trees(False)
200
        except NotImplementedError:
2018.5.120 by Robert Collins
The Repository API ``make_working_trees`` is now permitted to return
201
            # the repository does not support having its tree-making flag
202
            # toggled.
203
            return
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
204
        result = made_control.clone(self.get_url('target'))
1752.2.55 by Andrew Bennetts
Replace another isinstance(made_repo, Repository) check.
205
        # Check that we have a repository object.
206
        made_repo.has_revision('foo')
207
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
208
        self.assertEqual(made_control, made_repo.bzrdir)
209
        self.assertTrue(result.open_repository().is_shared())
210
        self.assertFalse(result.open_repository().make_working_trees())
211
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
212
    def test_upgrade_preserves_signatures(self):
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
213
        wt = self.make_branch_and_tree('source')
214
        wt.commit('A', allow_pointless=True, rev_id='A')
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
215
        repo = wt.branch.repository
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
216
        repo.lock_write()
217
        repo.start_write_group()
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
218
        repo.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
219
        repo.commit_write_group()
220
        repo.unlock()
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
221
        old_signature = repo.get_signature_text('A')
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
222
        try:
223
            old_format = bzrdir.BzrDirFormat.get_default_format()
224
            # This gives metadir branches something they can convert to.
225
            # it would be nice to have a 'latest' vs 'default' concept.
2255.2.208 by Robert Collins
Remove more references to 'experimental' formats.
226
            format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
227
            upgrade(repo.bzrdir.root_transport.base, format=format)
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
228
        except errors.UpToDateFormat:
229
            # this is in the most current format already.
230
            return
1910.2.12 by Aaron Bentley
Implement knit repo format 2
231
        except errors.BadConversionTarget, e:
232
            raise TestSkipped(str(e))
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
233
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
234
        new_signature = wt.branch.repository.get_signature_text('A')
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
235
        self.assertEqual(old_signature, new_signature)
236
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
237
    def test_exposed_versioned_files_are_marked_dirty(self):
238
        repo = self.make_repository('.')
239
        repo.lock_write()
240
        inv = repo.get_inventory_weave()
241
        repo.unlock()
242
        self.assertRaises(errors.OutSideTransaction, inv.add_lines, 'foo', [], [])
243
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
244
    def test_format_description(self):
245
        repo = self.make_repository('.')
246
        text = repo._format.get_format_description()
247
        self.failUnless(len(text))
248
1666.1.6 by Robert Collins
Make knit the default format.
249
    def assertMessageRoundtrips(self, message):
250
        """Assert that message roundtrips to a repository and back intact."""
251
        tree = self.make_branch_and_tree('.')
252
        tree.commit(message, rev_id='a', allow_pointless=True)
253
        rev = tree.branch.repository.get_revision('a')
254
        # we have to manually escape this as we dont try to
255
        # roundtrip xml invalid characters at this point.
256
        # when escaping is moved to the serialiser, this test
257
        # can check against the literal message rather than
258
        # this escaped version.
259
        escaped_message, escape_count = re.subn(
260
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
261
            lambda match: match.group(0).encode('unicode_escape'),
262
            message)
263
        escaped_message= re.sub('\r', '\n', escaped_message)
264
        self.assertEqual(rev.message, escaped_message)
265
        # insist the class is unicode no matter what came in for 
266
        # consistency.
267
        self.assertIsInstance(rev.message, unicode)
268
269
    def test_commit_unicode_message(self):
270
        # a siple unicode message should be preserved
271
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
272
273
    def test_commit_unicode_control_characters(self):
274
        # a unicode message with control characters should roundtrip too.
275
        self.assertMessageRoundtrips(
276
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
277
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
278
    def test_check_repository(self):
279
        """Check a fairly simple repository's history"""
280
        tree = self.make_branch_and_tree('.')
281
        tree.commit('initial empty commit', rev_id='a-rev',
282
                    allow_pointless=True)
283
        result = tree.branch.repository.check(['a-rev'])
284
        # writes to log; should accept both verbose or non-verbose
285
        result.report_results(verbose=True)
286
        result.report_results(verbose=False)
287
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
288
    def test_get_revisions(self):
289
        tree = self.make_branch_and_tree('.')
290
        tree.commit('initial empty commit', rev_id='a-rev',
291
                    allow_pointless=True)
292
        tree.commit('second empty commit', rev_id='b-rev',
293
                    allow_pointless=True)
294
        tree.commit('third empty commit', rev_id='c-rev',
295
                    allow_pointless=True)
296
        repo = tree.branch.repository
297
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
298
        revisions = repo.get_revisions(revision_ids)
299
        assert len(revisions) == 3, repr(revisions)
300
        zipped = zip(revisions, revision_ids)
301
        self.assertEqual(len(zipped), 3)
302
        for revision, revision_id in zipped:
303
            self.assertEqual(revision.revision_id, revision_id)
304
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
305
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
306
    def test_root_entry_has_revision(self):
307
        tree = self.make_branch_and_tree('.')
308
        tree.commit('message', rev_id='rev_id')
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
309
        rev_tree = tree.branch.repository.revision_tree(tree.last_revision())
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
310
        self.assertEqual('rev_id', rev_tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
311
2255.7.64 by Robert Collins
Disabled test_repository.test_create_basis_inventory, a test that tests tree behaviour in the wrong place - its future is being discussed.
312
    def DISABLED_DELETE_OR_FIX_BEFORE_MERGE_test_create_basis_inventory(self):
1910.2.31 by Aaron Bentley
Fix bugs in basis inventory handling, change filename
313
        # Needs testing here because differences between repo and working tree
314
        # basis inventory formats can lead to bugs.
315
        t = self.make_branch_and_tree('.')
316
        b = t.branch
317
        open('a', 'wb').write('a\n')
318
        t.add('a')
319
        t.commit('a', rev_id='r1')
320
321
        t._control_files.get_utf8('basis-inventory-cache')
322
323
        basis_inv = t.basis_tree().inventory
324
        self.assertEquals('r1', basis_inv.revision_id)
325
        
326
        store_inv = b.repository.get_inventory('r1')
327
        self.assertEquals(store_inv._byid, basis_inv._byid)
328
329
        open('b', 'wb').write('b\n')
330
        t.add('b')
331
        t.commit('b', rev_id='r2')
332
333
        t._control_files.get_utf8('basis-inventory-cache')
334
335
        basis_inv_txt = t.read_basis_inventory()
2100.3.15 by Aaron Bentley
get test suite passing
336
        basis_inv = bzrlib.xml7.serializer_v7.read_inventory_from_string(basis_inv_txt)
1910.2.31 by Aaron Bentley
Fix bugs in basis inventory handling, change filename
337
        self.assertEquals('r2', basis_inv.revision_id)
338
        store_inv = b.repository.get_inventory('r2')
339
340
        self.assertEquals(store_inv._byid, basis_inv._byid)
341
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
342
    def test_upgrade_from_format4(self):
343
        from bzrlib.tests.test_upgrade import _upgrade_dir_template
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
344
        if self.repository_format.get_format_description() \
345
            == "Repository format 4":
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
346
            raise TestSkipped('Cannot convert format-4 to itself')
1752.2.89 by Andrew Bennetts
Skip test_upgrade_from_format4 for RemoteRepositoryFormat.
347
        if isinstance(self.repository_format, remote.RemoteRepositoryFormat):
348
            return # local conversion to/from RemoteObjects is irrelevant.
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
349
        self.build_tree_contents(_upgrade_dir_template)
350
        old_repodir = bzrlib.bzrdir.BzrDir.open_unsupported('.')
351
        old_repo_format = old_repodir.open_repository()._format
352
        format = self.repository_format._matchingbzrdir
353
        try:
354
            format.repository_format = self.repository_format
355
        except AttributeError:
356
            pass
357
        upgrade('.', format)
358
1910.2.37 by Aaron Bentley
Handle empty commits, fix test
359
    def test_pointless_commit(self):
360
        tree = self.make_branch_and_tree('.')
361
        self.assertRaises(errors.PointlessCommit, tree.commit, 'pointless',
362
                          allow_pointless=False)
363
        tree.commit('pointless', allow_pointless=True)
364
2323.5.17 by Martin Pool
Add supports_tree_reference to all repo formats (robert)
365
    def test_format_attributes(self):
366
        """All repository formats should have some basic attributes."""
367
        # create a repository to get a real format instance, not the 
368
        # template from the test suite parameterisation.
369
        repo = self.make_repository('.')
370
        repo._format.rich_root_data
371
        repo._format.supports_tree_reference
372
2520.4.113 by Aaron Bentley
Avoid peeking at Repository._serializer
373
    def test_get_serializer_format(self):
374
        repo = self.make_repository('.')
375
        format = repo.get_serializer_format()
376
        self.assertEqual(repo._serializer.format_num, format)
377
2708.1.7 by Aaron Bentley
Rename extract_files_bytes to iter_files_bytes
378
    def test_iter_files_bytes(self):
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
379
        tree = self.make_branch_and_tree('tree')
380
        self.build_tree_contents([('tree/file1', 'foo'),
381
                                  ('tree/file2', 'bar')])
382
        tree.add(['file1', 'file2'], ['file1-id', 'file2-id'])
383
        tree.commit('rev1', rev_id='rev1')
384
        self.build_tree_contents([('tree/file1', 'baz')])
385
        tree.commit('rev2', rev_id='rev2')
2708.1.11 by Aaron Bentley
Test and tweak error handling
386
        repository = tree.branch.repository
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
387
        extracted = dict((i, ''.join(b)) for i, b in
2708.1.11 by Aaron Bentley
Test and tweak error handling
388
                         repository.iter_files_bytes(
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
389
                         [('file1-id', 'rev1', 'file1-old'),
390
                          ('file1-id', 'rev2', 'file1-new'),
391
                          ('file2-id', 'rev1', 'file2'),
392
                         ]))
393
        self.assertEqual('foo', extracted['file1-old'])
394
        self.assertEqual('bar', extracted['file2'])
395
        self.assertEqual('baz', extracted['file1-new'])
2708.1.11 by Aaron Bentley
Test and tweak error handling
396
        self.assertRaises(errors.RevisionNotPresent, list,
397
                          repository.iter_files_bytes(
398
                          [('file1-id', 'rev3', 'file1-notpresent')]))
399
        self.assertRaises(errors.NoSuchId, list,
400
                          repository.iter_files_bytes(
401
                          [('file3-id', 'rev3', 'file1-notpresent')]))
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
402
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
403
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
404
class TestRepositoryLocking(TestCaseWithRepository):
405
406
    def test_leave_lock_in_place(self):
407
        repo = self.make_repository('r')
408
        # Lock the repository, then use leave_lock_in_place so that when we
409
        # unlock the repository the lock is still held on disk.
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
410
        token = repo.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
411
        try:
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
412
            if token is None:
413
                # This test does not apply, because this repository refuses lock
414
                # tokens.
415
                self.assertRaises(NotImplementedError, repo.leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
416
                return
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
417
            repo.leave_lock_in_place()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
418
        finally:
419
            repo.unlock()
420
        # We should be unable to relock the repo.
421
        self.assertRaises(errors.LockContention, repo.lock_write)
422
423
    def test_dont_leave_lock_in_place(self):
424
        repo = self.make_repository('r')
425
        # Create a lock on disk.
426
        token = repo.lock_write()
427
        try:
428
            if token is None:
429
                # This test does not apply, because this repository refuses lock
430
                # tokens.
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
431
                self.assertRaises(NotImplementedError,
432
                                  repo.dont_leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
433
                return
434
            try:
435
                repo.leave_lock_in_place()
436
            except NotImplementedError:
437
                # This repository doesn't support this API.
438
                return
439
        finally:
440
            repo.unlock()
441
        # Reacquire the lock (with a different repository object) by using the
442
        # token.
443
        new_repo = repo.bzrdir.open_repository()
444
        new_repo.lock_write(token=token)
445
        # Call dont_leave_lock_in_place, so that the lock will be released by
446
        # this instance, even though the lock wasn't originally acquired by it.
447
        new_repo.dont_leave_lock_in_place()
448
        new_repo.unlock()
449
        # Now the repository is unlocked.  Test this by locking it (without a
450
        # token).
451
        repo.lock_write()
452
        repo.unlock()
453
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
454
    def test_lock_read_then_unlock(self):
455
        # Calling lock_read then unlocking should work without errors.
456
        repo = self.make_repository('r')
457
        repo.lock_read()
458
        repo.unlock()
459
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
460
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
461
class TestCaseWithComplexRepository(TestCaseWithRepository):
462
463
    def setUp(self):
464
        super(TestCaseWithComplexRepository, self).setUp()
465
        tree_a = self.make_branch_and_tree('a')
466
        self.bzrdir = tree_a.branch.bzrdir
467
        # add a corrupt inventory 'orphan'
1534.1.34 by Robert Collins
Move missing_revision_ids from Repository to InterRepository, and eliminate the now unused Repository._compatible_formats method.
468
        # this may need some generalising for knits.
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
469
        inv_file = tree_a.branch.repository.control_weaves.get_weave(
470
            'inventory', 
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
471
            tree_a.branch.repository.get_transaction())
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
472
        inv_file.add_lines('orphan', [], [])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
473
        # add a real revision 'rev1'
474
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
475
        # add a real revision 'rev2' based on rev1
476
        tree_a.commit('rev2', rev_id='rev2', allow_pointless=True)
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
477
        # add a reference to a ghost
1908.6.7 by Robert Collins
Remove all users of set_pending_merges and add_pending_merge except tests that they work correctly.
478
        tree_a.add_parent_tree_id('ghost1')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
479
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
480
        # add another reference to a ghost, and a second ghost.
1908.6.7 by Robert Collins
Remove all users of set_pending_merges and add_pending_merge except tests that they work correctly.
481
        tree_a.add_parent_tree_id('ghost1')
482
        tree_a.add_parent_tree_id('ghost2')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
483
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
484
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
485
    def test_revision_trees(self):
486
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
487
        repository = self.bzrdir.open_repository()
488
        trees1 = list(repository.revision_trees(revision_ids))
489
        trees2 = [repository.revision_tree(t) for t in revision_ids]
490
        assert len(trees1) == len(trees2)
491
        for tree1, tree2 in zip(trees1, trees2):
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
492
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
493
1756.3.22 by Aaron Bentley
Tweaks from review
494
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
495
        repository = self.bzrdir.open_repository()
496
        revisions = [repository.get_revision(r) for r in 
497
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
498
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
499
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
500
                   revisions]
501
        assert deltas1 == deltas2
502
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
503
    def test_all_revision_ids(self):
504
        # all_revision_ids -> all revisions
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
505
        self.assertEqual(['rev1', 'rev2', 'rev3', 'rev4'],
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
506
                         self.bzrdir.open_repository().all_revision_ids())
507
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
508
    def test_get_ancestry_missing_revision(self):
1534.1.34 by Robert Collins
Move missing_revision_ids from Repository to InterRepository, and eliminate the now unused Repository._compatible_formats method.
509
        # get_ancestry(revision that is in some data but not fully installed
510
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
511
        self.assertRaises(errors.NoSuchRevision,
512
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
513
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
514
    def test_get_unsorted_ancestry(self):
515
        repo = self.bzrdir.open_repository()
516
        self.assertEqual(set(repo.get_ancestry('rev3')),
517
                         set(repo.get_ancestry('rev3', topo_sorted=False)))
518
1590.1.1 by Robert Collins
Improve common_ancestor performance.
519
    def test_get_revision_graph(self):
520
        # we can get a mapping of id->parents for the entire revision graph or bits thereof.
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
521
        self.assertEqual({'rev1':(),
522
                          'rev2':('rev1', ),
523
                          'rev3':('rev2', ),
524
                          'rev4':('rev3', ),
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
525
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
526
                         self.bzrdir.open_repository().get_revision_graph(None))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
527
        self.assertEqual({'rev1':()},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
528
                         self.bzrdir.open_repository().get_revision_graph('rev1'))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
529
        self.assertEqual({'rev1':(),
530
                          'rev2':('rev1', )},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
531
                         self.bzrdir.open_repository().get_revision_graph('rev2'))
2279.7.9 by Andrew Bennetts
Remove some redundant code pointed out by Robert's review, and remove some unused imports while I'm there.
532
        self.assertRaises(errors.NoSuchRevision,
1590.1.1 by Robert Collins
Improve common_ancestor performance.
533
                          self.bzrdir.open_repository().get_revision_graph,
534
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
535
        # and ghosts are not mentioned
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
536
        self.assertEqual({'rev1':(),
537
                          'rev2':('rev1', ),
538
                          'rev3':('rev2', ),
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
539
                          },
540
                         self.bzrdir.open_repository().get_revision_graph('rev3'))
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
541
        # and we can ask for the NULLREVISION graph
542
        self.assertEqual({},
543
            self.bzrdir.open_repository().get_revision_graph(NULL_REVISION))
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
544
545
    def test_get_revision_graph_with_ghosts(self):
546
        # we can get a graph object with roots, ghosts, ancestors and
547
        # descendants.
548
        repo = self.bzrdir.open_repository()
549
        graph = repo.get_revision_graph_with_ghosts([])
550
        self.assertEqual(set(['rev1']), graph.roots)
551
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
552
        self.assertEqual({'rev1':[],
553
                          'rev2':['rev1'],
554
                          'rev3':['rev2', 'ghost1'],
555
                          'rev4':['rev3', 'ghost1', 'ghost2'],
556
                          },
557
                          graph.get_ancestors())
558
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
559
                          'ghost2':{'rev4':1},
560
                          'rev1':{'rev2':1},
561
                          'rev2':{'rev3':1},
562
                          'rev3':{'rev4':1},
563
                          'rev4':{},
564
                          },
565
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
566
        # and we can ask for the NULLREVISION graph
567
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
568
        self.assertEqual({}, graph.get_ancestors())
569
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
570
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
571
    def test_reserved_id(self):
572
        repo = self.make_repository('repository')
573
        self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
574
                          None, None)
575
        self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
576
                          None)
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
577
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
578
579
class TestCaseWithCorruptRepository(TestCaseWithRepository):
580
581
    def setUp(self):
582
        super(TestCaseWithCorruptRepository, self).setUp()
583
        # a inventory with no parents and the revision has parents..
584
        # i.e. a ghost.
585
        repo = self.make_repository('inventory_with_unnecessary_ghost')
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
586
        repo.lock_write()
587
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
588
        inv = Inventory(revision_id = 'ghost')
589
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
590
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
591
        rev = bzrlib.revision.Revision(timestamp=0,
592
                                       timezone=None,
593
                                       committer="Foo Bar <foo@example.com>",
594
                                       message="Message",
595
                                       inventory_sha1=sha1,
596
                                       revision_id='ghost')
597
        rev.parent_ids = ['the_ghost']
598
        repo.add_revision('ghost', rev)
599
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
600
        inv = Inventory(revision_id = 'the_ghost')
601
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
602
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
603
        rev = bzrlib.revision.Revision(timestamp=0,
604
                                       timezone=None,
605
                                       committer="Foo Bar <foo@example.com>",
606
                                       message="Message",
607
                                       inventory_sha1=sha1,
608
                                       revision_id='the_ghost')
609
        rev.parent_ids = []
610
        repo.add_revision('the_ghost', rev)
611
        # check its setup usefully
612
        inv_weave = repo.get_inventory_weave()
1563.2.30 by Robert Collins
Remove all but fetch references to revision_store, making the repository references that are weave specific use the RevisionTextStore.text_store attribute.
613
        self.assertEqual(['ghost'], inv_weave.get_ancestry(['ghost']))
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
614
        repo.commit_write_group()
615
        repo.unlock()
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
616
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
617
    def test_corrupt_revision_access_asserts_if_reported_wrong(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
618
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
619
        repo = repository.Repository.open(repo_url)
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
620
        reported_wrong = False
621
        try:
622
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
623
                reported_wrong = True
624
        except errors.CorruptRepository:
625
            # caught the bad data:
626
            return
627
        if not reported_wrong:
628
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
629
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
630
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
631
    def test_corrupt_revision_get_revision_reconcile(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
632
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
633
        repo = repository.Repository.open(repo_url)
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
634
        repo.get_revision_reconcile('ghost')
1986.1.1 by Robert Collins
Move test_branch_on_vfat into a repository implementation test, to ensure that all repository formats are safe on vfat.
635
636
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
637
# FIXME: document why this is a TestCaseWithTransport rather than a
638
#        TestCaseWithRepository
1986.1.1 by Robert Collins
Move test_branch_on_vfat into a repository implementation test, to ensure that all repository formats are safe on vfat.
639
class TestEscaping(TestCaseWithTransport):
640
    """Test that repositories can be stored correctly on VFAT transports.
641
    
642
    Makes sure we have proper escaping of invalid characters, etc.
643
644
    It'd be better to test all operations on the FakeVFATTransportDecorator,
645
    but working trees go straight to the os not through the Transport layer.
646
    Therefore we build some history first in the regular way and then 
647
    check it's safe to access for vfat.
648
    """
649
650
    def test_on_vfat(self):
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
651
        # dont bother with remote repository testing, because this test is
652
        # about local disk layout/support.
653
        from bzrlib.remote import RemoteRepositoryFormat
654
        if isinstance(self.repository_format, RemoteRepositoryFormat):
655
            return
1986.1.1 by Robert Collins
Move test_branch_on_vfat into a repository implementation test, to ensure that all repository formats are safe on vfat.
656
        FOO_ID = 'foo<:>ID'
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
657
        REV_ID = 'revid-1' 
658
        # this makes a default format repository always, which is wrong: 
659
        # it should be a TestCaseWithRepository in order to get the 
660
        # default format.
1986.1.1 by Robert Collins
Move test_branch_on_vfat into a repository implementation test, to ensure that all repository formats are safe on vfat.
661
        wt = self.make_branch_and_tree('repo')
2052.2.1 by Alexander Belchenko
test_on_vfat win32 fix: use binary line-endings
662
        self.build_tree(["repo/foo"], line_endings='binary')
1986.1.1 by Robert Collins
Move test_branch_on_vfat into a repository implementation test, to ensure that all repository formats are safe on vfat.
663
        # add file with id containing wierd characters
664
        wt.add(['foo'], [FOO_ID])
665
        wt.commit('this is my new commit', rev_id=REV_ID)
666
        # now access over vfat; should be safe
667
        branch = bzrdir.BzrDir.open('vfat+' + self.get_url('repo')).open_branch()
668
        revtree = branch.repository.revision_tree(REV_ID)
669
        contents = revtree.get_file_text(FOO_ID)
670
        self.assertEqual(contents, 'contents of repo/foo\n')
2520.4.54 by Aaron Bentley
Hang a create_bundle method off repository
671
672
    def test_create_bundle(self):
673
        wt = self.make_branch_and_tree('repo')
674
        self.build_tree(['repo/file1'])
675
        wt.add('file1')
676
        wt.commit('file1', rev_id='rev1')
677
        fileobj = StringIO()
678
        wt.branch.repository.create_bundle('rev1', NULL_REVISION, fileobj)