/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,
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
26
    graph,
1752.2.87 by Andrew Bennetts
Make tests pass.
27
    remote,
28
    repository,
29
    )
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
30
from bzrlib.delta import TreeDelta
1731.1.33 by Aaron Bentley
Revert no-special-root changes
31
from bzrlib.inventory import Inventory, InventoryDirectory
3047.1.2 by Andrew Bennetts
Directly test that sprouting branches from a HPSS preserves the repository format.
32
from bzrlib.repofmt.weaverepo import (
33
    RepositoryFormat5,
34
    RepositoryFormat6,
35
    RepositoryFormat7,
36
    )
2996.2.3 by Aaron Bentley
Add tests for install_revisions and add_signature
37
from bzrlib.revision import NULL_REVISION, Revision
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
38
from bzrlib.smart import server
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
39
from bzrlib.symbol_versioning import one_two
3023.2.1 by Martin Pool
test_get_data_stream should indicate NotApplicable rather than silently passing
40
from bzrlib.tests import (
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
41
    KnownFailure,
3023.2.1 by Martin Pool
test_get_data_stream should indicate NotApplicable rather than silently passing
42
    TestCaseWithTransport,
43
    TestNotApplicable,
44
    TestSkipped,
45
    )
2485.7.1 by Robert Collins
Relocate TestCaseWithRepository to be more central.
46
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.
47
from bzrlib.transport import get_transport
48
from bzrlib.upgrade import upgrade
49
from bzrlib.workingtree import WorkingTree
50
51
2018.5.66 by Wouter van Heyst
Fix repository test parameterization for RemoteRepository.
52
class TestRepositoryMakeBranchAndTree(TestCaseWithRepository):
53
54
    def test_repository_format(self):
2018.5.119 by Robert Collins
Unbreak TestRepositoryMakeBranchAndTree.
55
        # make sure the repository on tree.branch is of the desired format,
56
        # because developers use this api to setup the tree, branch and 
57
        # repository for their tests: having it now give the right repository
58
        # type would invalidate the tests.
2018.5.66 by Wouter van Heyst
Fix repository test parameterization for RemoteRepository.
59
        tree = self.make_branch_and_tree('repo')
60
        self.assertIsInstance(tree.branch.repository._format,
61
            self.repository_format.__class__)
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
62
63
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
64
class TestRepository(TestCaseWithRepository):
65
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.
66
    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.
67
        #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.
68
        # such as signatures[not tested yet] etc etc.
69
        # when changing to the current default format.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
70
        tree_a = self.make_branch_and_tree('a')
2381.1.3 by Robert Collins
Review feedback.
71
        self.build_tree(['a/foo'])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
72
        tree_a.add('foo', 'file1')
73
        tree_a.commit('rev1', rev_id='rev1')
74
        bzrdirb = self.make_bzrdir('b')
75
        repo_b = tree_a.branch.repository.clone(bzrdirb)
76
        tree_b = repo_b.revision_tree('rev1')
2592.3.214 by Robert Collins
Merge bzr.dev.
77
        tree_b.lock_read()
78
        self.addCleanup(tree_b.unlock)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
79
        tree_b.get_file_text('file1')
80
        rev1 = repo_b.get_revision('rev1')
81
3169.2.1 by Robert Collins
New method ``iter_inventories`` on Repository for access to many
82
    def test_iter_inventories_is_ordered(self):
83
        # just a smoke test
84
        tree = self.make_branch_and_tree('a')
85
        first_revision = tree.commit('')
86
        second_revision = tree.commit('')
87
        tree.lock_read()
88
        self.addCleanup(tree.unlock)
89
        revs = (first_revision, second_revision)
90
        invs = tree.branch.repository.iter_inventories(revs)
91
        for rev_id, inv in zip(revs, invs):
92
            self.assertEqual(rev_id, inv.revision_id)
93
            self.assertIsInstance(inv, Inventory)
94
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
95
    def test_supports_rich_root(self):
96
        tree = self.make_branch_and_tree('a')
97
        tree.commit('')
98
        second_revision = tree.commit('')
99
        inv = tree.branch.repository.revision_tree(second_revision).inventory
100
        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.
101
        self.assertEqual(rich_root,
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
102
                         tree.branch.repository.supports_rich_root())
103
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
104
    def test_clone_specific_format(self):
105
        """todo"""
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
106
107
    def test_format_initialize_find_open(self):
108
        # loopback test to check the current format initializes to itself.
109
        if not self.repository_format.is_supported():
110
            # unsupported formats are not loopback testable
111
            # because the default open will not open them and
112
            # they may not be initializable.
113
            return
114
        # supported formats must be able to init and open
115
        t = get_transport(self.get_url())
116
        readonly_t = get_transport(self.get_readonly_url())
117
        made_control = self.bzrdir_format.initialize(t.base)
118
        made_repo = self.repository_format.initialize(made_control)
119
        self.assertEqual(made_control, made_repo.bzrdir)
120
121
        # find it via bzrdir opening:
122
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
123
        direct_opened_repo = opened_control.open_repository()
124
        self.assertEqual(direct_opened_repo.__class__, made_repo.__class__)
125
        self.assertEqual(opened_control, direct_opened_repo.bzrdir)
126
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
127
        self.assertIsInstance(direct_opened_repo._format,
128
                              self.repository_format.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
129
        # find it via Repository.open
130
        opened_repo = repository.Repository.open(readonly_t.base)
131
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
132
        self.assertEqual(made_repo._format.__class__,
133
                         opened_repo._format.__class__)
134
        # if it has a unique id string, can we probe for it ?
135
        try:
136
            self.repository_format.get_format_string()
137
        except NotImplementedError:
138
            return
139
        self.assertEqual(self.repository_format,
140
                         repository.RepositoryFormat.find_format(opened_control))
141
142
    def test_create_repository(self):
1534.6.1 by Robert Collins
allow API creation of shared repositories
143
        # 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.
144
        if not self.bzrdir_format.is_supported():
145
            # unsupported formats are not loopback testable
146
            # because the default open will not open them and
147
            # they may not be initializable.
148
            return
149
        t = get_transport(self.get_url())
150
        made_control = self.bzrdir_format.initialize(t.base)
151
        made_repo = made_control.create_repository()
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
152
        # Check that we have a repository object.
153
        made_repo.has_revision('foo')
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
154
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.1 by Robert Collins
allow API creation of shared repositories
155
        
156
    def test_create_repository_shared(self):
157
        # bzrdir can construct a shared repository.
158
        if not self.bzrdir_format.is_supported():
159
            # unsupported formats are not loopback testable
160
            # because the default open will not open them and
161
            # they may not be initializable.
162
            return
163
        t = get_transport(self.get_url())
164
        made_control = self.bzrdir_format.initialize(t.base)
165
        try:
166
            made_repo = made_control.create_repository(shared=True)
167
        except errors.IncompatibleFormat:
168
            # not all repository formats understand being shared, or
169
            # may only be shared in some circumstances.
170
            return
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
171
        # Check that we have a repository object.
172
        made_repo.has_revision('foo')
1534.6.1 by Robert Collins
allow API creation of shared repositories
173
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
174
        self.assertTrue(made_repo.is_shared())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
175
176
    def test_revision_tree(self):
177
        wt = self.make_branch_and_tree('.')
1731.1.33 by Aaron Bentley
Revert no-special-root changes
178
        wt.set_root_id('fixed-root')
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
179
        wt.commit('lala!', rev_id='revision-1', allow_pointless=True)
180
        tree = wt.branch.repository.revision_tree('revision-1')
1731.1.45 by Aaron Bentley
Merge bzr.dev
181
        self.assertEqual('revision-1', tree.inventory.root.revision) 
182
        expected = InventoryDirectory('fixed-root', '', None)
183
        expected.revision = 'revision-1'
184
        self.assertEqual([('', 'V', 'directory', 'fixed-root', expected)],
1731.1.54 by Aaron Bentley
Fix revision_tree tests
185
                         list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
186
        tree = wt.branch.repository.revision_tree(None)
1731.1.54 by Aaron Bentley
Fix revision_tree tests
187
        self.assertEqual([], list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
188
        tree = wt.branch.repository.revision_tree(NULL_REVISION)
1731.1.54 by Aaron Bentley
Fix revision_tree tests
189
        self.assertEqual([], list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
190
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
191
    def test_get_revision_delta(self):
192
        tree_a = self.make_branch_and_tree('a')
2381.1.3 by Robert Collins
Review feedback.
193
        self.build_tree(['a/foo'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
194
        tree_a.add('foo', 'file1')
195
        tree_a.commit('rev1', rev_id='rev1')
2381.1.3 by Robert Collins
Review feedback.
196
        self.build_tree(['a/vla'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
197
        tree_a.add('vla', 'file2')
198
        tree_a.commit('rev2', rev_id='rev2')
199
200
        delta = tree_a.branch.repository.get_revision_delta('rev1')
201
        self.assertIsInstance(delta, TreeDelta)
202
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
203
        delta = tree_a.branch.repository.get_revision_delta('rev2')
204
        self.assertIsInstance(delta, TreeDelta)
205
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
206
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.
207
    def test_clone_bzrdir_repository_revision(self):
208
        # make a repository with some revisions,
209
        # and clone it, this should not have unreferenced revisions.
210
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
211
        raise TestSkipped('revision limiting is not implemented yet.')
212
213
    def test_clone_repository_basis_revision(self):
214
        raise TestSkipped('the use of a basis should not add noise data to the result.')
215
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
216
    def test_clone_shared_no_tree(self):
217
        # cloning a shared repository keeps it shared
218
        # and preserves the make_working_tree setting.
219
        made_control = self.make_bzrdir('source')
220
        try:
221
            made_repo = made_control.create_repository(shared=True)
222
        except errors.IncompatibleFormat:
223
            # not all repository formats understand being shared, or
224
            # may only be shared in some circumstances.
225
            return
2018.14.2 by Andrew Bennetts
All but one repository_implementation tests for RemoteRepository passing.
226
        try:
227
            made_repo.set_make_working_trees(False)
228
        except NotImplementedError:
2018.5.120 by Robert Collins
The Repository API ``make_working_trees`` is now permitted to return
229
            # the repository does not support having its tree-making flag
230
            # toggled.
231
            return
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
232
        result = made_control.clone(self.get_url('target'))
1752.2.55 by Andrew Bennetts
Replace another isinstance(made_repo, Repository) check.
233
        # Check that we have a repository object.
234
        made_repo.has_revision('foo')
235
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
236
        self.assertEqual(made_control, made_repo.bzrdir)
237
        self.assertTrue(result.open_repository().is_shared())
238
        self.assertFalse(result.open_repository().make_working_trees())
239
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
240
    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.
241
        wt = self.make_branch_and_tree('source')
242
        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.
243
        repo = wt.branch.repository
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
244
        repo.lock_write()
245
        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.
246
        repo.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
247
        repo.commit_write_group()
248
        repo.unlock()
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
249
        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.
250
        try:
251
            old_format = bzrdir.BzrDirFormat.get_default_format()
252
            # This gives metadir branches something they can convert to.
253
            # it would be nice to have a 'latest' vs 'default' concept.
2255.2.208 by Robert Collins
Remove more references to 'experimental' formats.
254
            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.
255
            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.
256
        except errors.UpToDateFormat:
257
            # this is in the most current format already.
258
            return
1910.2.12 by Aaron Bentley
Implement knit repo format 2
259
        except errors.BadConversionTarget, e:
260
            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.
261
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
262
        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.
263
        self.assertEqual(old_signature, new_signature)
264
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
265
    def test_format_description(self):
266
        repo = self.make_repository('.')
267
        text = repo._format.get_format_description()
268
        self.failUnless(len(text))
269
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
270
    def test_format_supports_external_lookups(self):
271
        repo = self.make_repository('.')
272
        self.assertSubset(
273
            [repo._format.supports_external_lookups], (True, False))
274
1666.1.6 by Robert Collins
Make knit the default format.
275
    def assertMessageRoundtrips(self, message):
276
        """Assert that message roundtrips to a repository and back intact."""
277
        tree = self.make_branch_and_tree('.')
278
        tree.commit(message, rev_id='a', allow_pointless=True)
279
        rev = tree.branch.repository.get_revision('a')
280
        # we have to manually escape this as we dont try to
281
        # roundtrip xml invalid characters at this point.
282
        # when escaping is moved to the serialiser, this test
283
        # can check against the literal message rather than
284
        # this escaped version.
285
        escaped_message, escape_count = re.subn(
286
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
287
            lambda match: match.group(0).encode('unicode_escape'),
288
            message)
289
        escaped_message= re.sub('\r', '\n', escaped_message)
290
        self.assertEqual(rev.message, escaped_message)
291
        # insist the class is unicode no matter what came in for 
292
        # consistency.
293
        self.assertIsInstance(rev.message, unicode)
294
295
    def test_commit_unicode_message(self):
296
        # a siple unicode message should be preserved
297
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
298
299
    def test_commit_unicode_control_characters(self):
300
        # a unicode message with control characters should roundtrip too.
301
        self.assertMessageRoundtrips(
302
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
303
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
304
    def test_check_repository(self):
305
        """Check a fairly simple repository's history"""
306
        tree = self.make_branch_and_tree('.')
307
        tree.commit('initial empty commit', rev_id='a-rev',
308
                    allow_pointless=True)
2745.6.39 by Andrew Bennetts
Use scenario in test_check too, and make check actually report inconsistent parents to the end user.
309
        result = tree.branch.repository.check()
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
310
        # writes to log; should accept both verbose or non-verbose
311
        result.report_results(verbose=True)
312
        result.report_results(verbose=False)
313
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
314
    def test_get_revisions(self):
315
        tree = self.make_branch_and_tree('.')
316
        tree.commit('initial empty commit', rev_id='a-rev',
317
                    allow_pointless=True)
318
        tree.commit('second empty commit', rev_id='b-rev',
319
                    allow_pointless=True)
320
        tree.commit('third empty commit', rev_id='c-rev',
321
                    allow_pointless=True)
322
        repo = tree.branch.repository
323
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
324
        revisions = repo.get_revisions(revision_ids)
325
        assert len(revisions) == 3, repr(revisions)
326
        zipped = zip(revisions, revision_ids)
327
        self.assertEqual(len(zipped), 3)
328
        for revision, revision_id in zipped:
329
            self.assertEqual(revision.revision_id, revision_id)
330
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
331
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
332
    def test_root_entry_has_revision(self):
333
        tree = self.make_branch_and_tree('.')
334
        tree.commit('message', rev_id='rev_id')
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
335
        rev_tree = tree.branch.repository.revision_tree(tree.last_revision())
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
336
        self.assertEqual('rev_id', rev_tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
337
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.
338
    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
339
        # Needs testing here because differences between repo and working tree
340
        # basis inventory formats can lead to bugs.
341
        t = self.make_branch_and_tree('.')
342
        b = t.branch
343
        open('a', 'wb').write('a\n')
344
        t.add('a')
345
        t.commit('a', rev_id='r1')
346
347
        t._control_files.get_utf8('basis-inventory-cache')
348
349
        basis_inv = t.basis_tree().inventory
350
        self.assertEquals('r1', basis_inv.revision_id)
351
        
352
        store_inv = b.repository.get_inventory('r1')
353
        self.assertEquals(store_inv._byid, basis_inv._byid)
354
355
        open('b', 'wb').write('b\n')
356
        t.add('b')
357
        t.commit('b', rev_id='r2')
358
359
        t._control_files.get_utf8('basis-inventory-cache')
360
361
        basis_inv_txt = t.read_basis_inventory()
2100.3.15 by Aaron Bentley
get test suite passing
362
        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
363
        self.assertEquals('r2', basis_inv.revision_id)
364
        store_inv = b.repository.get_inventory('r2')
365
366
        self.assertEquals(store_inv._byid, basis_inv._byid)
367
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
368
    def test_upgrade_from_format4(self):
369
        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.
370
        if self.repository_format.get_format_description() \
371
            == "Repository format 4":
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
372
            raise TestSkipped('Cannot convert format-4 to itself')
1752.2.89 by Andrew Bennetts
Skip test_upgrade_from_format4 for RemoteRepositoryFormat.
373
        if isinstance(self.repository_format, remote.RemoteRepositoryFormat):
374
            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
375
        self.build_tree_contents(_upgrade_dir_template)
376
        old_repodir = bzrlib.bzrdir.BzrDir.open_unsupported('.')
377
        old_repo_format = old_repodir.open_repository()._format
378
        format = self.repository_format._matchingbzrdir
379
        try:
380
            format.repository_format = self.repository_format
381
        except AttributeError:
382
            pass
383
        upgrade('.', format)
384
1910.2.37 by Aaron Bentley
Handle empty commits, fix test
385
    def test_pointless_commit(self):
386
        tree = self.make_branch_and_tree('.')
387
        self.assertRaises(errors.PointlessCommit, tree.commit, 'pointless',
388
                          allow_pointless=False)
389
        tree.commit('pointless', allow_pointless=True)
390
2323.5.17 by Martin Pool
Add supports_tree_reference to all repo formats (robert)
391
    def test_format_attributes(self):
392
        """All repository formats should have some basic attributes."""
393
        # create a repository to get a real format instance, not the 
3128.1.3 by Vincent Ladeuil
Since we are there s/parameteris.*/parameteriz&/.
394
        # template from the test suite parameterization.
2323.5.17 by Martin Pool
Add supports_tree_reference to all repo formats (robert)
395
        repo = self.make_repository('.')
396
        repo._format.rich_root_data
397
        repo._format.supports_tree_reference
398
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
399
    def test_get_data_stream_deprecated(self):
400
        # If get_data_stream is present it must be deprecated
401
        tree = self.make_branch_and_tree('t')
402
        self.build_tree(['t/foo'])
403
        tree.add('foo', 'file1')
404
        tree.commit('message', rev_id='rev_id')
405
        repo = tree.branch.repository
406
        try:
407
            stream = self.applyDeprecated(one_two, repo.get_data_stream,
408
                ['rev_id'])
409
        except NotImplementedError:
410
            raise TestNotApplicable("%s doesn't support get_data_stream"
411
                % repo._format)
412
        except AttributeError:
413
            pass
414
415
    def test_get_data_stream_for_search(self):
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
416
        # Make a repo with a revision
417
        tree = self.make_branch_and_tree('t')
418
        self.build_tree(['t/foo'])
419
        tree.add('foo', 'file1')
420
        tree.commit('message', rev_id='rev_id')
421
        repo = tree.branch.repository
422
423
        # Get a data stream (a file-like object) for that revision
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
424
        search = graph.SearchResult(set(['rev_id']), set([NULL_REVISION]), 1,
425
            set(['rev_id']))
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
426
        try:
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
427
            stream = repo.get_data_stream_for_search(search)
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
428
        except NotImplementedError:
3023.2.1 by Martin Pool
test_get_data_stream should indicate NotApplicable rather than silently passing
429
            raise TestNotApplicable("%s doesn't support get_data_stream"
430
                % repo._format)
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
431
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
432
        # The data stream is a iterator that yields (name, versioned_file)
433
        # pairs for:
2535.3.62 by Andrew Bennetts
Cosmetic changes.
434
        #   * the file knit (or knits; if this repo has rich roots there will
435
        #     be a file knit for that as well as for 'file1').
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
436
        #   * the inventory knit
437
        #   * the revisions knit
438
        # in that order.
2535.3.50 by Andrew Bennetts
Use tuple names in data streams rather than concatenated strings.
439
        expected_record_names = [
440
            ('file', 'file1'),
441
            ('inventory',),
442
            ('signatures',),
443
            ('revisions',)]
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
444
        streamed_names = []
2535.3.15 by Andrew Bennetts
Add KnitVersionedFile.get_stream_as_bytes, start smart implementation of RemoteRepository.get_data_stream.
445
        for name, bytes in stream:
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
446
            streamed_names.append(name)
447
448
        if repo.supports_rich_root():
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
449
            # Check for the root versioned file in the stream, then remove it
450
            # from streamed_names so we can compare that with
451
            # expected_record_names.
452
            # Note that the file knits can be in any order, so this test is
453
            # written to allow that.
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
454
            inv = repo.get_inventory('rev_id')
2535.3.50 by Andrew Bennetts
Use tuple names in data streams rather than concatenated strings.
455
            expected_record_name = ('file', inv.root.file_id)
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
456
            self.assertTrue(expected_record_name in streamed_names)
457
            streamed_names.remove(expected_record_name)
458
459
        self.assertEqual(expected_record_names, streamed_names)
460
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
461
    def test_insert_data_stream(self):
462
        tree = self.make_branch_and_tree('source')
463
        self.build_tree(['source/foo'])
464
        tree.add('foo', 'file1')
465
        tree.commit('message', rev_id='rev_id')
466
        source_repo = tree.branch.repository
467
        dest_repo = self.make_repository('dest')
3204.1.2 by Ian Clatworthy
Fix error handling in insert_data_stream (Lukas Lalinsky)
468
        search = dest_repo.search_missing_revision_ids(source_repo,
469
            revision_id='rev_id')
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
470
        try:
3204.1.2 by Ian Clatworthy
Fix error handling in insert_data_stream (Lukas Lalinsky)
471
            stream = source_repo.get_data_stream_for_search(search)
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
472
        except NotImplementedError, e:
473
            # Not all repositories support streaming.
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
474
            self.assertContainsRe(str(e), 'get_data_stream_for_search')
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
475
            raise TestSkipped('This format does not support streaming.')
476
2592.3.214 by Robert Collins
Merge bzr.dev.
477
        dest_repo.lock_write()
478
        try:
479
            dest_repo.start_write_group()
480
            try:
481
                dest_repo.insert_data_stream(stream)
482
            except:
483
                dest_repo.abort_write_group()
484
                raise
485
            else:
486
                dest_repo.commit_write_group()
487
        finally:
488
            dest_repo.unlock()
489
        # reopen to be sure it was added.
490
        dest_repo = dest_repo.bzrdir.open_repository()
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
491
        self.assertTrue(dest_repo.has_revision('rev_id'))
492
3184.5.1 by Lukáš Lalinský
Fix handling of some error cases in insert_data_stream
493
        # insert the same data stream again, should be no-op
3204.1.2 by Ian Clatworthy
Fix error handling in insert_data_stream (Lukas Lalinsky)
494
        stream = source_repo.get_data_stream_for_search(search)
3184.5.1 by Lukáš Lalinský
Fix handling of some error cases in insert_data_stream
495
        dest_repo.lock_write()
496
        try:
497
            dest_repo.start_write_group()
498
            try:
499
                dest_repo.insert_data_stream(stream)
500
            except:
501
                dest_repo.abort_write_group()
502
                raise
503
            else:
504
                dest_repo.commit_write_group()
505
        finally:
506
            dest_repo.unlock()
507
508
        # try to insert data stream with invalid key
509
        stream = [[('bogus-key',), '']]
510
        self.assertRaises(errors.RepositoryDataStreamError,
511
                          dest_repo.insert_data_stream, stream)
512
2520.4.113 by Aaron Bentley
Avoid peeking at Repository._serializer
513
    def test_get_serializer_format(self):
514
        repo = self.make_repository('.')
515
        format = repo.get_serializer_format()
516
        self.assertEqual(repo._serializer.format_num, format)
517
2708.1.7 by Aaron Bentley
Rename extract_files_bytes to iter_files_bytes
518
    def test_iter_files_bytes(self):
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
519
        tree = self.make_branch_and_tree('tree')
520
        self.build_tree_contents([('tree/file1', 'foo'),
521
                                  ('tree/file2', 'bar')])
522
        tree.add(['file1', 'file2'], ['file1-id', 'file2-id'])
523
        tree.commit('rev1', rev_id='rev1')
524
        self.build_tree_contents([('tree/file1', 'baz')])
525
        tree.commit('rev2', rev_id='rev2')
2708.1.11 by Aaron Bentley
Test and tweak error handling
526
        repository = tree.branch.repository
2592.3.214 by Robert Collins
Merge bzr.dev.
527
        repository.lock_read()
528
        self.addCleanup(repository.unlock)
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
529
        extracted = dict((i, ''.join(b)) for i, b in
2708.1.11 by Aaron Bentley
Test and tweak error handling
530
                         repository.iter_files_bytes(
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
531
                         [('file1-id', 'rev1', 'file1-old'),
532
                          ('file1-id', 'rev2', 'file1-new'),
533
                          ('file2-id', 'rev1', 'file2'),
534
                         ]))
535
        self.assertEqual('foo', extracted['file1-old'])
536
        self.assertEqual('bar', extracted['file2'])
537
        self.assertEqual('baz', extracted['file1-new'])
2708.1.11 by Aaron Bentley
Test and tweak error handling
538
        self.assertRaises(errors.RevisionNotPresent, list,
539
                          repository.iter_files_bytes(
540
                          [('file1-id', 'rev3', 'file1-notpresent')]))
2592.3.102 by Robert Collins
Change the iter_files_bytes error to allow either RevisionNotPresent or NoSuchId when requesting a file that was not in the repository at all.
541
        self.assertRaises((errors.RevisionNotPresent, errors.NoSuchId), list,
2708.1.11 by Aaron Bentley
Test and tweak error handling
542
                          repository.iter_files_bytes(
543
                          [('file3-id', 'rev3', 'file1-notpresent')]))
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
544
2535.3.63 by Andrew Bennetts
Add repository implementations test for item_keys_introduced_by.
545
    def test_item_keys_introduced_by(self):
546
        # Make a repo with one revision and one versioned file.
547
        tree = self.make_branch_and_tree('t')
548
        self.build_tree(['t/foo'])
549
        tree.add('foo', 'file1')
550
        tree.commit('message', rev_id='rev_id')
551
        repo = tree.branch.repository
552
553
        # Item keys will be in this order, for maximum convenience for
554
        # generating data to insert into knit repository:
555
        #   * files
556
        #   * inventory
557
        #   * signatures
558
        #   * revisions
559
        expected_item_keys = [
560
            ('file', 'file1', ['rev_id']),
561
            ('inventory', None, ['rev_id']),
562
            ('signatures', None, []),
563
            ('revisions', None, ['rev_id'])]
564
        item_keys = list(repo.item_keys_introduced_by(['rev_id']))
565
        item_keys = [
566
            (kind, file_id, list(versions))
567
            for (kind, file_id, versions) in item_keys]
568
569
        if repo.supports_rich_root():
570
            # Check for the root versioned file in the item_keys, then remove
571
            # it from streamed_names so we can compare that with
572
            # expected_record_names.
573
            # Note that the file keys can be in any order, so this test is
574
            # written to allow that.
575
            inv = repo.get_inventory('rev_id')
576
            root_item_key = ('file', inv.root.file_id, ['rev_id'])
577
            self.assertTrue(root_item_key in item_keys)
578
            item_keys.remove(root_item_key)
579
580
        self.assertEqual(expected_item_keys, item_keys)
581
2850.4.1 by Andrew Bennetts
Add smoketest for repo.get_graph, and fix bug in RemoteRepository.get_graph that it reveals.
582
    def test_get_graph(self):
583
        """Bare-bones smoketest that all repositories implement get_graph."""
584
        repo = self.make_repository('repo')
2592.3.214 by Robert Collins
Merge bzr.dev.
585
        repo.lock_read()
586
        self.addCleanup(repo.unlock)
2850.4.1 by Andrew Bennetts
Add smoketest for repo.get_graph, and fix bug in RemoteRepository.get_graph that it reveals.
587
        repo.get_graph()
588
3146.1.1 by Aaron Bentley
Fix bad ghost handling in KnitParentsProvider
589
    def test_graph_ghost_handling(self):
590
        tree = self.make_branch_and_tree('here')
591
        tree.lock_write()
592
        self.addCleanup(tree.unlock)
593
        tree.commit('initial commit', rev_id='rev1')
594
        tree.add_parent_tree_id('ghost')
595
        tree.commit('commit-with-ghost', rev_id='rev2')
596
        graph = tree.branch.repository.get_graph()
597
        parents = graph.get_parent_map(['ghost', 'rev2'])
598
        self.assertTrue('ghost' not in parents)
3146.1.2 by Aaron Bentley
ParentsProviders now provide tuples of parents, never lists
599
        self.assertEqual(parents['rev2'], ('rev1', 'ghost'))
600
601
    def test_parent_map_type(self):
602
        tree = self.make_branch_and_tree('here')
603
        tree.lock_write()
604
        self.addCleanup(tree.unlock)
605
        tree.commit('initial commit', rev_id='rev1')
606
        tree.commit('next commit', rev_id='rev2')
607
        graph = tree.branch.repository.get_graph()
608
        parents = graph.get_parent_map([NULL_REVISION, 'rev1', 'rev2'])
609
        for value in parents.values():
610
            self.assertIsInstance(value, tuple)
3146.1.1 by Aaron Bentley
Fix bad ghost handling in KnitParentsProvider
611
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
612
    def test_implements_revision_graph_can_have_wrong_parents(self):
613
        """All repositories should implement
614
        revision_graph_can_have_wrong_parents, so that check and reconcile can
615
        work correctly.
616
        """
617
        repo = self.make_repository('.')
618
        # This should work, not raise NotImplementedError:
2592.3.214 by Robert Collins
Merge bzr.dev.
619
        if not repo.revision_graph_can_have_wrong_parents():
620
            return
621
        repo.lock_read()
622
        self.addCleanup(repo.unlock)
623
        # This repo must also implement
624
        # _find_inconsistent_revision_parents and
625
        # _check_for_inconsistent_revision_parents.  So calling these
626
        # should not raise NotImplementedError.
627
        list(repo._find_inconsistent_revision_parents())
628
        repo._check_for_inconsistent_revision_parents()
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
629
2996.2.4 by Aaron Bentley
Rename function to add_signature_text
630
    def test_add_signature_text(self):
2996.2.3 by Aaron Bentley
Add tests for install_revisions and add_signature
631
        repo = self.make_repository('repo')
632
        repo.lock_write()
633
        self.addCleanup(repo.unlock)
634
        self.addCleanup(repo.commit_write_group)
635
        repo.start_write_group()
636
        inv = Inventory(revision_id='A')
637
        inv.root.revision = 'A'
638
        repo.add_inventory('A', inv, [])
639
        repo.add_revision('A', Revision('A', committer='A', timestamp=0,
640
                          inventory_sha1='', timezone=0, message='A'))
2996.2.4 by Aaron Bentley
Rename function to add_signature_text
641
        repo.add_signature_text('A', 'This might be a signature')
2996.2.3 by Aaron Bentley
Add tests for install_revisions and add_signature
642
        self.assertEqual('This might be a signature',
643
                         repo.get_signature_text('A'))
644
645
    def test_install_revisions(self):
646
        wt = self.make_branch_and_tree('source')
647
        wt.commit('A', allow_pointless=True, rev_id='A')
648
        repo = wt.branch.repository
649
        repo.lock_write()
650
        repo.start_write_group()
651
        repo.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
652
        repo.commit_write_group()
653
        repo.unlock()
654
        repo.lock_read()
655
        self.addCleanup(repo.unlock)
656
        repo2 = self.make_repository('repo2')
657
        revision = repo.get_revision('A')
658
        tree = repo.revision_tree('A')
659
        signature = repo.get_signature_text('A')
660
        repo2.lock_write()
661
        self.addCleanup(repo2.unlock)
662
        repository.install_revisions(repo2, [(revision, tree, signature)])
663
        self.assertEqual(revision, repo2.get_revision('A'))
664
        self.assertEqual(signature, repo2.get_signature_text('A'))
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
665
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
666
    # XXX: this helper duplicated from tests.test_repository
667
    def make_remote_repository(self, path):
668
        """Make a RemoteRepository object backed by a real repository that will
669
        be created at the given path."""
670
        repo = self.make_repository(path)
671
        smart_server = server.SmartTCPServer_for_testing()
672
        smart_server.setUp(self.get_server())
673
        remote_transport = get_transport(smart_server.get_url()).clone(path)
674
        self.addCleanup(smart_server.tearDown)
675
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
676
        remote_repo = remote_bzrdir.open_repository()
677
        return remote_repo
678
3047.1.2 by Andrew Bennetts
Directly test that sprouting branches from a HPSS preserves the repository format.
679
    def test_sprout_from_hpss_preserves_format(self):
680
        """repo.sprout from a smart server preserves the repository format."""
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
681
        if self.repository_format == RepositoryFormat7():
682
            raise KnownFailure(
683
                "Cannot fetch weaves over smart protocol.")
684
        remote_repo = self.make_remote_repository('remote')
685
        local_bzrdir = self.make_bzrdir('local')
686
        try:
687
            local_repo = remote_repo.sprout(local_bzrdir)
688
        except errors.TransportNotPossible:
689
            raise TestNotApplicable(
690
                "Cannot lock_read old formats like AllInOne over HPSS.")
691
        remote_backing_repo = bzrdir.BzrDir.open(
692
            self.get_vfs_only_url('remote')).open_repository()
693
        self.assertEqual(remote_backing_repo._format, local_repo._format)
694
3047.1.2 by Andrew Bennetts
Directly test that sprouting branches from a HPSS preserves the repository format.
695
    def test_sprout_branch_from_hpss_preserves_repo_format(self):
696
        """branch.sprout from a smart server preserves the repository format.
697
        """
698
        weave_formats = [RepositoryFormat5(), RepositoryFormat6(),
699
                         RepositoryFormat7()]
700
        if self.repository_format in weave_formats:
701
            raise KnownFailure(
702
                "Cannot fetch weaves over smart protocol.")
703
        remote_repo = self.make_remote_repository('remote')
704
        remote_branch = remote_repo.bzrdir.create_branch()
705
        try:
706
            local_bzrdir = remote_branch.bzrdir.sprout('local')
707
        except errors.TransportNotPossible:
708
            raise TestNotApplicable(
709
                "Cannot lock_read old formats like AllInOne over HPSS.")
710
        local_repo = local_bzrdir.open_repository()
711
        remote_backing_repo = bzrdir.BzrDir.open(
712
            self.get_vfs_only_url('remote')).open_repository()
713
        self.assertEqual(remote_backing_repo._format, local_repo._format)
714
3089.2.1 by Andrew Bennetts
Implement RemoteRepository._make_parents_provider.
715
    def test__make_parents_provider(self):
716
        """Repositories must have a _make_parents_provider method that returns
3099.3.5 by John Arbash Meinel
Update the last couple of places that referred to Provider.get_parents() directly.
717
        an object with a get_parent_map method.
3089.2.1 by Andrew Bennetts
Implement RemoteRepository._make_parents_provider.
718
        """
719
        repo = self.make_repository('repo')
3099.3.5 by John Arbash Meinel
Update the last couple of places that referred to Provider.get_parents() directly.
720
        repo._make_parents_provider().get_parent_map
3089.2.1 by Andrew Bennetts
Implement RemoteRepository._make_parents_provider.
721
3140.1.2 by Aaron Bentley
Add ability to find branches inside repositories
722
    def make_repository_and_foo_bar(self, shared):
723
        made_control = self.make_bzrdir('repository')
724
        repo = made_control.create_repository(shared=shared)
725
        bzrdir.BzrDir.create_branch_convenience(self.get_url('repository/foo'),
726
                                                force_new_repo=False)
727
        bzrdir.BzrDir.create_branch_convenience(self.get_url('repository/bar'),
728
                                                force_new_repo=True)
3140.1.3 by Aaron Bentley
Add support for finding branches to BzrDir
729
        baz = self.make_bzrdir('repository/baz')
730
        qux = self.make_branch('repository/baz/qux')
3140.1.6 by Aaron Bentley
Add test that nested branches are returned
731
        quxx = self.make_branch('repository/baz/qux/quxx')
3140.1.2 by Aaron Bentley
Add ability to find branches inside repositories
732
        return repo
733
734
    def test_find_branches(self):
735
        repo = self.make_repository_and_foo_bar(shared=False)
736
        branches = repo.find_branches()
737
        self.assertContainsRe(branches[-1].base, 'repository/foo/$')
3140.1.6 by Aaron Bentley
Add test that nested branches are returned
738
        self.assertContainsRe(branches[-3].base, 'repository/baz/qux/$')
739
        self.assertContainsRe(branches[-2].base, 'repository/baz/qux/quxx/$')
3140.1.2 by Aaron Bentley
Add ability to find branches inside repositories
740
        # in some formats, creating a repo creates a branch
3140.1.6 by Aaron Bentley
Add test that nested branches are returned
741
        if len(branches) == 6:
742
            self.assertContainsRe(branches[-4].base, 'repository/baz/$')
743
            self.assertContainsRe(branches[-5].base, 'repository/bar/$')
744
            self.assertContainsRe(branches[-6].base, 'repository/$')
745
        else:
746
            self.assertEqual(4, len(branches))
3140.1.3 by Aaron Bentley
Add support for finding branches to BzrDir
747
            self.assertContainsRe(branches[-4].base, 'repository/bar/$')
3140.1.2 by Aaron Bentley
Add ability to find branches inside repositories
748
749
    def test_find_branches_using(self):
750
        try:
751
            repo = self.make_repository_and_foo_bar(shared=True)
752
        except errors.IncompatibleFormat:
753
            raise TestNotApplicable
754
        branches = repo.find_branches(using=True)
755
        self.assertContainsRe(branches[-1].base, 'repository/foo/$')
756
        # in some formats, creating a repo creates a branch
757
        if len(branches) == 2:
758
            self.assertContainsRe(branches[-2].base, 'repository/$')
759
        else:
760
            self.assertEqual(1, len(branches))
761
3140.1.9 by Aaron Bentley
Optimize find_branches for standalone repositories
762
    def test_find_branches_using_standalone(self):
763
        branch = self.make_branch('branch')
764
        contained = self.make_branch('branch/contained')
765
        branches = branch.repository.find_branches(using=True)
766
        self.assertEqual([branch.base], [b.base for b in branches])
767
        branches = branch.repository.find_branches(using=False)
768
        self.assertEqual([branch.base, contained.base],
769
                         [b.base for b in branches])
770
771
    def test_find_branches_using_empty_standalone_repo(self):
772
        repo = self.make_repository('repo')
773
        self.assertFalse(repo.is_shared())
774
        try:
775
            repo.bzrdir.open_branch()
776
        except errors.NotBranchError:
777
            self.assertEqual([], repo.find_branches(using=True))
778
        else:
779
            self.assertEqual([repo.bzrdir.root_transport.base],
780
                             [b.base for b in repo.find_branches(using=True)])
781
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
782
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
783
class TestRepositoryLocking(TestCaseWithRepository):
784
785
    def test_leave_lock_in_place(self):
786
        repo = self.make_repository('r')
787
        # Lock the repository, then use leave_lock_in_place so that when we
788
        # 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.
789
        token = repo.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
790
        try:
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
791
            if token is None:
792
                # This test does not apply, because this repository refuses lock
793
                # tokens.
794
                self.assertRaises(NotImplementedError, repo.leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
795
                return
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
796
            repo.leave_lock_in_place()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
797
        finally:
798
            repo.unlock()
799
        # We should be unable to relock the repo.
800
        self.assertRaises(errors.LockContention, repo.lock_write)
801
802
    def test_dont_leave_lock_in_place(self):
803
        repo = self.make_repository('r')
804
        # Create a lock on disk.
805
        token = repo.lock_write()
806
        try:
807
            if token is None:
808
                # This test does not apply, because this repository refuses lock
809
                # tokens.
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
810
                self.assertRaises(NotImplementedError,
811
                                  repo.dont_leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
812
                return
813
            try:
814
                repo.leave_lock_in_place()
815
            except NotImplementedError:
816
                # This repository doesn't support this API.
817
                return
818
        finally:
819
            repo.unlock()
820
        # Reacquire the lock (with a different repository object) by using the
821
        # token.
822
        new_repo = repo.bzrdir.open_repository()
823
        new_repo.lock_write(token=token)
824
        # Call dont_leave_lock_in_place, so that the lock will be released by
825
        # this instance, even though the lock wasn't originally acquired by it.
826
        new_repo.dont_leave_lock_in_place()
827
        new_repo.unlock()
828
        # Now the repository is unlocked.  Test this by locking it (without a
829
        # token).
830
        repo.lock_write()
831
        repo.unlock()
832
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
833
    def test_lock_read_then_unlock(self):
834
        # Calling lock_read then unlocking should work without errors.
835
        repo = self.make_repository('r')
836
        repo.lock_read()
837
        repo.unlock()
838
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
839
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
840
class TestCaseWithComplexRepository(TestCaseWithRepository):
841
842
    def setUp(self):
843
        super(TestCaseWithComplexRepository, self).setUp()
844
        tree_a = self.make_branch_and_tree('a')
845
        self.bzrdir = tree_a.branch.bzrdir
846
        # 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.
847
        # this may need some generalising for knits.
2592.3.74 by Robert Collins
Test setup fix to use get_inventory_weave rather than control_store.get_weave.
848
        tree_a.lock_write()
849
        try:
850
            tree_a.branch.repository.start_write_group()
851
            inv_file = tree_a.branch.repository.get_inventory_weave()
852
            try:
853
                inv_file.add_lines('orphan', [], [])
854
            except:
855
                tree_a.branch.repository.commit_write_group()
856
                raise
857
            else:
858
                tree_a.branch.repository.abort_write_group()
859
        finally:
860
            tree_a.unlock()
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
861
        # add a real revision 'rev1'
862
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
863
        # add a real revision 'rev2' based on rev1
864
        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.
865
        # 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.
866
        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.
867
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
868
        # 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.
869
        tree_a.add_parent_tree_id('ghost1')
870
        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.
871
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
872
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
873
    def test_revision_trees(self):
874
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
875
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
876
        repository.lock_read()
877
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
878
        trees1 = list(repository.revision_trees(revision_ids))
879
        trees2 = [repository.revision_tree(t) for t in revision_ids]
880
        assert len(trees1) == len(trees2)
881
        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.
882
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
883
1756.3.22 by Aaron Bentley
Tweaks from review
884
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
885
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
886
        repository.lock_read()
887
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
888
        revisions = [repository.get_revision(r) for r in 
889
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
890
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
891
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
892
                   revisions]
893
        assert deltas1 == deltas2
894
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
895
    def test_all_revision_ids(self):
896
        # 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.
897
        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.
898
                         self.bzrdir.open_repository().all_revision_ids())
899
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
900
    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.
901
        # get_ancestry(revision that is in some data but not fully installed
902
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
903
        self.assertRaises(errors.NoSuchRevision,
904
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
905
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
906
    def test_get_unsorted_ancestry(self):
907
        repo = self.bzrdir.open_repository()
908
        self.assertEqual(set(repo.get_ancestry('rev3')),
909
                         set(repo.get_ancestry('rev3', topo_sorted=False)))
910
1590.1.1 by Robert Collins
Improve common_ancestor performance.
911
    def test_get_revision_graph(self):
912
        # 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:
913
        self.assertEqual({'rev1':(),
914
                          'rev2':('rev1', ),
915
                          'rev3':('rev2', ),
916
                          '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.
917
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
918
                         self.bzrdir.open_repository().get_revision_graph(None))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
919
        self.assertEqual({'rev1':()},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
920
                         self.bzrdir.open_repository().get_revision_graph('rev1'))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
921
        self.assertEqual({'rev1':(),
922
                          'rev2':('rev1', )},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
923
                         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.
924
        self.assertRaises(errors.NoSuchRevision,
1590.1.1 by Robert Collins
Improve common_ancestor performance.
925
                          self.bzrdir.open_repository().get_revision_graph,
926
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
927
        # and ghosts are not mentioned
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
928
        self.assertEqual({'rev1':(),
929
                          'rev2':('rev1', ),
930
                          '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.
931
                          },
932
                         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.
933
        # and we can ask for the NULLREVISION graph
934
        self.assertEqual({},
935
            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.
936
937
    def test_get_revision_graph_with_ghosts(self):
938
        # we can get a graph object with roots, ghosts, ancestors and
939
        # descendants.
940
        repo = self.bzrdir.open_repository()
941
        graph = repo.get_revision_graph_with_ghosts([])
942
        self.assertEqual(set(['rev1']), graph.roots)
943
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
944
        self.assertEqual({'rev1':[],
945
                          'rev2':['rev1'],
946
                          'rev3':['rev2', 'ghost1'],
947
                          'rev4':['rev3', 'ghost1', 'ghost2'],
948
                          },
949
                          graph.get_ancestors())
950
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
951
                          'ghost2':{'rev4':1},
952
                          'rev1':{'rev2':1},
953
                          'rev2':{'rev3':1},
954
                          'rev3':{'rev4':1},
955
                          'rev4':{},
956
                          },
957
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
958
        # and we can ask for the NULLREVISION graph
959
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
960
        self.assertEqual({}, graph.get_ancestors())
961
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
962
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
963
    def test_reserved_id(self):
964
        repo = self.make_repository('repository')
2592.3.61 by Robert Collins
Remove inventory.kndx.
965
        repo.lock_write()
966
        repo.start_write_group()
967
        try:
968
            self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
969
                              None, None)
970
            self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
971
                              None)
972
        finally:
973
            repo.abort_write_group()
974
            repo.unlock()
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
975
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
976
977
class TestCaseWithCorruptRepository(TestCaseWithRepository):
978
979
    def setUp(self):
980
        super(TestCaseWithCorruptRepository, self).setUp()
981
        # a inventory with no parents and the revision has parents..
982
        # i.e. a ghost.
983
        repo = self.make_repository('inventory_with_unnecessary_ghost')
2592.3.38 by Robert Collins
All experimental format tests passing again.
984
        repo.lock_write()
985
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
986
        inv = Inventory(revision_id = 'ghost')
987
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
988
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
989
        rev = bzrlib.revision.Revision(timestamp=0,
990
                                       timezone=None,
991
                                       committer="Foo Bar <foo@example.com>",
992
                                       message="Message",
993
                                       inventory_sha1=sha1,
994
                                       revision_id='ghost')
995
        rev.parent_ids = ['the_ghost']
996
        repo.add_revision('ghost', rev)
997
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
998
        inv = Inventory(revision_id = 'the_ghost')
999
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
1000
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
1001
        rev = bzrlib.revision.Revision(timestamp=0,
1002
                                       timezone=None,
1003
                                       committer="Foo Bar <foo@example.com>",
1004
                                       message="Message",
1005
                                       inventory_sha1=sha1,
1006
                                       revision_id='the_ghost')
1007
        rev.parent_ids = []
1008
        repo.add_revision('the_ghost', rev)
1009
        # check its setup usefully
1010
        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.
1011
        self.assertEqual(['ghost'], inv_weave.get_ancestry(['ghost']))
2592.3.38 by Robert Collins
All experimental format tests passing again.
1012
        repo.commit_write_group()
1013
        repo.unlock()
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
1014
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
1015
    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.
1016
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
1017
        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.
1018
        reported_wrong = False
1019
        try:
1020
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
1021
                reported_wrong = True
1022
        except errors.CorruptRepository:
1023
            # caught the bad data:
1024
            return
1025
        if not reported_wrong:
1026
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
1027
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
1028
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
1029
    def test_corrupt_revision_get_revision_reconcile(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
1030
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
1031
        repo = repository.Repository.open(repo_url)
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
1032
        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.
1033
1034
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
1035
# FIXME: document why this is a TestCaseWithTransport rather than a
1036
#        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.
1037
class TestEscaping(TestCaseWithTransport):
1038
    """Test that repositories can be stored correctly on VFAT transports.
1039
    
1040
    Makes sure we have proper escaping of invalid characters, etc.
1041
1042
    It'd be better to test all operations on the FakeVFATTransportDecorator,
1043
    but working trees go straight to the os not through the Transport layer.
1044
    Therefore we build some history first in the regular way and then 
1045
    check it's safe to access for vfat.
1046
    """
1047
1048
    def test_on_vfat(self):
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
1049
        # dont bother with remote repository testing, because this test is
1050
        # about local disk layout/support.
1051
        from bzrlib.remote import RemoteRepositoryFormat
1052
        if isinstance(self.repository_format, RemoteRepositoryFormat):
1053
            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.
1054
        FOO_ID = 'foo<:>ID'
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
1055
        REV_ID = 'revid-1' 
1056
        # this makes a default format repository always, which is wrong: 
1057
        # it should be a TestCaseWithRepository in order to get the 
1058
        # 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.
1059
        wt = self.make_branch_and_tree('repo')
2052.2.1 by Alexander Belchenko
test_on_vfat win32 fix: use binary line-endings
1060
        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.
1061
        # add file with id containing wierd characters
1062
        wt.add(['foo'], [FOO_ID])
1063
        wt.commit('this is my new commit', rev_id=REV_ID)
1064
        # now access over vfat; should be safe
1065
        branch = bzrdir.BzrDir.open('vfat+' + self.get_url('repo')).open_branch()
1066
        revtree = branch.repository.revision_tree(REV_ID)
3015.2.13 by Robert Collins
More lock correctness for the use of get_file_text in repository_implementations.
1067
        revtree.lock_read()
1068
        self.addCleanup(revtree.unlock)
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.
1069
        contents = revtree.get_file_text(FOO_ID)
1070
        self.assertEqual(contents, 'contents of repo/foo\n')
2520.4.54 by Aaron Bentley
Hang a create_bundle method off repository
1071
1072
    def test_create_bundle(self):
1073
        wt = self.make_branch_and_tree('repo')
1074
        self.build_tree(['repo/file1'])
1075
        wt.add('file1')
1076
        wt.commit('file1', rev_id='rev1')
1077
        fileobj = StringIO()
1078
        wt.branch.repository.create_bundle('rev1', NULL_REVISION, fileobj)