/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')
2592.3.214 by Robert Collins
Merge bzr.dev.
64
        tree_b.lock_read()
65
        self.addCleanup(tree_b.unlock)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
66
        tree_b.get_file_text('file1')
67
        rev1 = repo_b.get_revision('rev1')
68
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
69
    def test_supports_rich_root(self):
70
        tree = self.make_branch_and_tree('a')
71
        tree.commit('')
72
        second_revision = tree.commit('')
73
        inv = tree.branch.repository.revision_tree(second_revision).inventory
74
        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.
75
        self.assertEqual(rich_root,
1910.2.63 by Aaron Bentley
Add supports_rich_root member to repository
76
                         tree.branch.repository.supports_rich_root())
77
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
78
    def test_clone_specific_format(self):
79
        """todo"""
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
80
81
    def test_format_initialize_find_open(self):
82
        # loopback test to check the current format initializes to itself.
83
        if not self.repository_format.is_supported():
84
            # unsupported formats are not loopback testable
85
            # because the default open will not open them and
86
            # they may not be initializable.
87
            return
88
        # supported formats must be able to init and open
89
        t = get_transport(self.get_url())
90
        readonly_t = get_transport(self.get_readonly_url())
91
        made_control = self.bzrdir_format.initialize(t.base)
92
        made_repo = self.repository_format.initialize(made_control)
93
        self.assertEqual(made_control, made_repo.bzrdir)
94
95
        # find it via bzrdir opening:
96
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
97
        direct_opened_repo = opened_control.open_repository()
98
        self.assertEqual(direct_opened_repo.__class__, made_repo.__class__)
99
        self.assertEqual(opened_control, direct_opened_repo.bzrdir)
100
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
101
        self.assertIsInstance(direct_opened_repo._format,
102
                              self.repository_format.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
103
        # find it via Repository.open
104
        opened_repo = repository.Repository.open(readonly_t.base)
105
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
106
        self.assertEqual(made_repo._format.__class__,
107
                         opened_repo._format.__class__)
108
        # if it has a unique id string, can we probe for it ?
109
        try:
110
            self.repository_format.get_format_string()
111
        except NotImplementedError:
112
            return
113
        self.assertEqual(self.repository_format,
114
                         repository.RepositoryFormat.find_format(opened_control))
115
116
    def test_create_repository(self):
1534.6.1 by Robert Collins
allow API creation of shared repositories
117
        # 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.
118
        if not self.bzrdir_format.is_supported():
119
            # unsupported formats are not loopback testable
120
            # because the default open will not open them and
121
            # they may not be initializable.
122
            return
123
        t = get_transport(self.get_url())
124
        made_control = self.bzrdir_format.initialize(t.base)
125
        made_repo = made_control.create_repository()
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
126
        # Check that we have a repository object.
127
        made_repo.has_revision('foo')
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
128
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.1 by Robert Collins
allow API creation of shared repositories
129
        
130
    def test_create_repository_shared(self):
131
        # bzrdir can construct a shared repository.
132
        if not self.bzrdir_format.is_supported():
133
            # unsupported formats are not loopback testable
134
            # because the default open will not open them and
135
            # they may not be initializable.
136
            return
137
        t = get_transport(self.get_url())
138
        made_control = self.bzrdir_format.initialize(t.base)
139
        try:
140
            made_repo = made_control.create_repository(shared=True)
141
        except errors.IncompatibleFormat:
142
            # not all repository formats understand being shared, or
143
            # may only be shared in some circumstances.
144
            return
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
145
        # Check that we have a repository object.
146
        made_repo.has_revision('foo')
1534.6.1 by Robert Collins
allow API creation of shared repositories
147
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
148
        self.assertTrue(made_repo.is_shared())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
149
150
    def test_revision_tree(self):
151
        wt = self.make_branch_and_tree('.')
1731.1.33 by Aaron Bentley
Revert no-special-root changes
152
        wt.set_root_id('fixed-root')
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
153
        wt.commit('lala!', rev_id='revision-1', allow_pointless=True)
154
        tree = wt.branch.repository.revision_tree('revision-1')
1731.1.45 by Aaron Bentley
Merge bzr.dev
155
        self.assertEqual('revision-1', tree.inventory.root.revision) 
156
        expected = InventoryDirectory('fixed-root', '', None)
157
        expected.revision = 'revision-1'
158
        self.assertEqual([('', 'V', 'directory', 'fixed-root', expected)],
1731.1.54 by Aaron Bentley
Fix revision_tree tests
159
                         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(None)
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
        tree = wt.branch.repository.revision_tree(NULL_REVISION)
1731.1.54 by Aaron Bentley
Fix revision_tree tests
163
        self.assertEqual([], list(tree.list_files(include_root=True)))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
164
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
165
    def test_get_revision_delta(self):
166
        tree_a = self.make_branch_and_tree('a')
2381.1.3 by Robert Collins
Review feedback.
167
        self.build_tree(['a/foo'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
168
        tree_a.add('foo', 'file1')
169
        tree_a.commit('rev1', rev_id='rev1')
2381.1.3 by Robert Collins
Review feedback.
170
        self.build_tree(['a/vla'])
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
171
        tree_a.add('vla', 'file2')
172
        tree_a.commit('rev2', rev_id='rev2')
173
174
        delta = tree_a.branch.repository.get_revision_delta('rev1')
175
        self.assertIsInstance(delta, TreeDelta)
176
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
177
        delta = tree_a.branch.repository.get_revision_delta('rev2')
178
        self.assertIsInstance(delta, TreeDelta)
179
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
180
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.
181
    def test_clone_bzrdir_repository_revision(self):
182
        # make a repository with some revisions,
183
        # and clone it, this should not have unreferenced revisions.
184
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
185
        raise TestSkipped('revision limiting is not implemented yet.')
186
187
    def test_clone_repository_basis_revision(self):
188
        raise TestSkipped('the use of a basis should not add noise data to the result.')
189
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
190
    def test_clone_shared_no_tree(self):
191
        # cloning a shared repository keeps it shared
192
        # and preserves the make_working_tree setting.
193
        made_control = self.make_bzrdir('source')
194
        try:
195
            made_repo = made_control.create_repository(shared=True)
196
        except errors.IncompatibleFormat:
197
            # not all repository formats understand being shared, or
198
            # may only be shared in some circumstances.
199
            return
2018.14.2 by Andrew Bennetts
All but one repository_implementation tests for RemoteRepository passing.
200
        try:
201
            made_repo.set_make_working_trees(False)
202
        except NotImplementedError:
2018.5.120 by Robert Collins
The Repository API ``make_working_trees`` is now permitted to return
203
            # the repository does not support having its tree-making flag
204
            # toggled.
205
            return
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
206
        result = made_control.clone(self.get_url('target'))
1752.2.55 by Andrew Bennetts
Replace another isinstance(made_repo, Repository) check.
207
        # Check that we have a repository object.
208
        made_repo.has_revision('foo')
209
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
210
        self.assertEqual(made_control, made_repo.bzrdir)
211
        self.assertTrue(result.open_repository().is_shared())
212
        self.assertFalse(result.open_repository().make_working_trees())
213
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
214
    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.
215
        wt = self.make_branch_and_tree('source')
216
        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.
217
        repo = wt.branch.repository
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
218
        repo.lock_write()
219
        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.
220
        repo.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
221
        repo.commit_write_group()
222
        repo.unlock()
2018.5.90 by Andrew Bennetts
Fix test_upgrade_preserves_signatures; it incorrectly assumed that upgrade(wt, ...) would necessarily affect the repository.
223
        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.
224
        try:
225
            old_format = bzrdir.BzrDirFormat.get_default_format()
226
            # This gives metadir branches something they can convert to.
227
            # it would be nice to have a 'latest' vs 'default' concept.
2255.2.208 by Robert Collins
Remove more references to 'experimental' formats.
228
            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.
229
            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.
230
        except errors.UpToDateFormat:
231
            # this is in the most current format already.
232
            return
1910.2.12 by Aaron Bentley
Implement knit repo format 2
233
        except errors.BadConversionTarget, e:
234
            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.
235
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
236
        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.
237
        self.assertEqual(old_signature, new_signature)
238
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
239
    def test_format_description(self):
240
        repo = self.make_repository('.')
241
        text = repo._format.get_format_description()
242
        self.failUnless(len(text))
243
1666.1.6 by Robert Collins
Make knit the default format.
244
    def assertMessageRoundtrips(self, message):
245
        """Assert that message roundtrips to a repository and back intact."""
246
        tree = self.make_branch_and_tree('.')
247
        tree.commit(message, rev_id='a', allow_pointless=True)
248
        rev = tree.branch.repository.get_revision('a')
249
        # we have to manually escape this as we dont try to
250
        # roundtrip xml invalid characters at this point.
251
        # when escaping is moved to the serialiser, this test
252
        # can check against the literal message rather than
253
        # this escaped version.
254
        escaped_message, escape_count = re.subn(
255
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
256
            lambda match: match.group(0).encode('unicode_escape'),
257
            message)
258
        escaped_message= re.sub('\r', '\n', escaped_message)
259
        self.assertEqual(rev.message, escaped_message)
260
        # insist the class is unicode no matter what came in for 
261
        # consistency.
262
        self.assertIsInstance(rev.message, unicode)
263
264
    def test_commit_unicode_message(self):
265
        # a siple unicode message should be preserved
266
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
267
268
    def test_commit_unicode_control_characters(self):
269
        # a unicode message with control characters should roundtrip too.
270
        self.assertMessageRoundtrips(
271
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
272
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
273
    def test_check_repository(self):
274
        """Check a fairly simple repository's history"""
275
        tree = self.make_branch_and_tree('.')
276
        tree.commit('initial empty commit', rev_id='a-rev',
277
                    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.
278
        result = tree.branch.repository.check()
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
279
        # writes to log; should accept both verbose or non-verbose
280
        result.report_results(verbose=True)
281
        result.report_results(verbose=False)
282
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
283
    def test_get_revisions(self):
284
        tree = self.make_branch_and_tree('.')
285
        tree.commit('initial empty commit', rev_id='a-rev',
286
                    allow_pointless=True)
287
        tree.commit('second empty commit', rev_id='b-rev',
288
                    allow_pointless=True)
289
        tree.commit('third empty commit', rev_id='c-rev',
290
                    allow_pointless=True)
291
        repo = tree.branch.repository
292
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
293
        revisions = repo.get_revisions(revision_ids)
294
        assert len(revisions) == 3, repr(revisions)
295
        zipped = zip(revisions, revision_ids)
296
        self.assertEqual(len(zipped), 3)
297
        for revision, revision_id in zipped:
298
            self.assertEqual(revision.revision_id, revision_id)
299
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
300
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
301
    def test_root_entry_has_revision(self):
302
        tree = self.make_branch_and_tree('.')
303
        tree.commit('message', rev_id='rev_id')
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
304
        rev_tree = tree.branch.repository.revision_tree(tree.last_revision())
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
305
        self.assertEqual('rev_id', rev_tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
306
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.
307
    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
308
        # Needs testing here because differences between repo and working tree
309
        # basis inventory formats can lead to bugs.
310
        t = self.make_branch_and_tree('.')
311
        b = t.branch
312
        open('a', 'wb').write('a\n')
313
        t.add('a')
314
        t.commit('a', rev_id='r1')
315
316
        t._control_files.get_utf8('basis-inventory-cache')
317
318
        basis_inv = t.basis_tree().inventory
319
        self.assertEquals('r1', basis_inv.revision_id)
320
        
321
        store_inv = b.repository.get_inventory('r1')
322
        self.assertEquals(store_inv._byid, basis_inv._byid)
323
324
        open('b', 'wb').write('b\n')
325
        t.add('b')
326
        t.commit('b', rev_id='r2')
327
328
        t._control_files.get_utf8('basis-inventory-cache')
329
330
        basis_inv_txt = t.read_basis_inventory()
2100.3.15 by Aaron Bentley
get test suite passing
331
        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
332
        self.assertEquals('r2', basis_inv.revision_id)
333
        store_inv = b.repository.get_inventory('r2')
334
335
        self.assertEquals(store_inv._byid, basis_inv._byid)
336
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
337
    def test_upgrade_from_format4(self):
338
        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.
339
        if self.repository_format.get_format_description() \
340
            == "Repository format 4":
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
341
            raise TestSkipped('Cannot convert format-4 to itself')
1752.2.89 by Andrew Bennetts
Skip test_upgrade_from_format4 for RemoteRepositoryFormat.
342
        if isinstance(self.repository_format, remote.RemoteRepositoryFormat):
343
            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
344
        self.build_tree_contents(_upgrade_dir_template)
345
        old_repodir = bzrlib.bzrdir.BzrDir.open_unsupported('.')
346
        old_repo_format = old_repodir.open_repository()._format
347
        format = self.repository_format._matchingbzrdir
348
        try:
349
            format.repository_format = self.repository_format
350
        except AttributeError:
351
            pass
352
        upgrade('.', format)
353
1910.2.37 by Aaron Bentley
Handle empty commits, fix test
354
    def test_pointless_commit(self):
355
        tree = self.make_branch_and_tree('.')
356
        self.assertRaises(errors.PointlessCommit, tree.commit, 'pointless',
357
                          allow_pointless=False)
358
        tree.commit('pointless', allow_pointless=True)
359
2323.5.17 by Martin Pool
Add supports_tree_reference to all repo formats (robert)
360
    def test_format_attributes(self):
361
        """All repository formats should have some basic attributes."""
362
        # create a repository to get a real format instance, not the 
363
        # template from the test suite parameterisation.
364
        repo = self.make_repository('.')
365
        repo._format.rich_root_data
366
        repo._format.supports_tree_reference
367
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
368
    def test_get_data_stream(self):
369
        # Make a repo with a revision
370
        tree = self.make_branch_and_tree('t')
371
        self.build_tree(['t/foo'])
372
        tree.add('foo', 'file1')
373
        tree.commit('message', rev_id='rev_id')
374
        repo = tree.branch.repository
375
376
        # Get a data stream (a file-like object) for that revision
377
        try:
378
            stream = repo.get_data_stream(['rev_id'])
379
        except NotImplementedError:
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
380
            # Not all repositories support streaming.
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
381
            return
382
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
383
        # The data stream is a iterator that yields (name, versioned_file)
384
        # pairs for:
2535.3.62 by Andrew Bennetts
Cosmetic changes.
385
        #   * the file knit (or knits; if this repo has rich roots there will
386
        #     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.
387
        #   * the inventory knit
388
        #   * the revisions knit
389
        # in that order.
2535.3.50 by Andrew Bennetts
Use tuple names in data streams rather than concatenated strings.
390
        expected_record_names = [
391
            ('file', 'file1'),
392
            ('inventory',),
393
            ('signatures',),
394
            ('revisions',)]
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
395
        streamed_names = []
2535.3.15 by Andrew Bennetts
Add KnitVersionedFile.get_stream_as_bytes, start smart implementation of RemoteRepository.get_data_stream.
396
        for name, bytes in stream:
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
397
            streamed_names.append(name)
398
399
        if repo.supports_rich_root():
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
400
            # Check for the root versioned file in the stream, then remove it
401
            # from streamed_names so we can compare that with
402
            # expected_record_names.
403
            # Note that the file knits can be in any order, so this test is
404
            # written to allow that.
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
405
            inv = repo.get_inventory('rev_id')
2535.3.50 by Andrew Bennetts
Use tuple names in data streams rather than concatenated strings.
406
            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.
407
            self.assertTrue(expected_record_name in streamed_names)
408
            streamed_names.remove(expected_record_name)
409
410
        self.assertEqual(expected_record_names, streamed_names)
411
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
412
    def test_insert_data_stream(self):
413
        tree = self.make_branch_and_tree('source')
414
        self.build_tree(['source/foo'])
415
        tree.add('foo', 'file1')
416
        tree.commit('message', rev_id='rev_id')
417
        source_repo = tree.branch.repository
418
        dest_repo = self.make_repository('dest')
419
        try:
420
            stream = source_repo.get_data_stream(['rev_id'])
421
        except NotImplementedError, e:
422
            # Not all repositories support streaming.
423
            self.assertContainsRe(str(e), 'get_data_stream')
424
            raise TestSkipped('This format does not support streaming.')
425
2592.3.214 by Robert Collins
Merge bzr.dev.
426
        dest_repo.lock_write()
427
        try:
428
            dest_repo.start_write_group()
429
            try:
430
                dest_repo.insert_data_stream(stream)
431
            except:
432
                dest_repo.abort_write_group()
433
                raise
434
            else:
435
                dest_repo.commit_write_group()
436
        finally:
437
            dest_repo.unlock()
438
        # reopen to be sure it was added.
439
        dest_repo = dest_repo.bzrdir.open_repository()
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
440
        self.assertTrue(dest_repo.has_revision('rev_id'))
441
2520.4.113 by Aaron Bentley
Avoid peeking at Repository._serializer
442
    def test_get_serializer_format(self):
443
        repo = self.make_repository('.')
444
        format = repo.get_serializer_format()
445
        self.assertEqual(repo._serializer.format_num, format)
446
2708.1.7 by Aaron Bentley
Rename extract_files_bytes to iter_files_bytes
447
    def test_iter_files_bytes(self):
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
448
        tree = self.make_branch_and_tree('tree')
449
        self.build_tree_contents([('tree/file1', 'foo'),
450
                                  ('tree/file2', 'bar')])
451
        tree.add(['file1', 'file2'], ['file1-id', 'file2-id'])
452
        tree.commit('rev1', rev_id='rev1')
453
        self.build_tree_contents([('tree/file1', 'baz')])
454
        tree.commit('rev2', rev_id='rev2')
2708.1.11 by Aaron Bentley
Test and tweak error handling
455
        repository = tree.branch.repository
2592.3.214 by Robert Collins
Merge bzr.dev.
456
        repository.lock_read()
457
        self.addCleanup(repository.unlock)
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
458
        extracted = dict((i, ''.join(b)) for i, b in
2708.1.11 by Aaron Bentley
Test and tweak error handling
459
                         repository.iter_files_bytes(
2708.1.6 by Aaron Bentley
Turn extract_files_bytes into an iterator
460
                         [('file1-id', 'rev1', 'file1-old'),
461
                          ('file1-id', 'rev2', 'file1-new'),
462
                          ('file2-id', 'rev1', 'file2'),
463
                         ]))
464
        self.assertEqual('foo', extracted['file1-old'])
465
        self.assertEqual('bar', extracted['file2'])
466
        self.assertEqual('baz', extracted['file1-new'])
2708.1.11 by Aaron Bentley
Test and tweak error handling
467
        self.assertRaises(errors.RevisionNotPresent, list,
468
                          repository.iter_files_bytes(
469
                          [('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.
470
        self.assertRaises((errors.RevisionNotPresent, errors.NoSuchId), list,
2708.1.11 by Aaron Bentley
Test and tweak error handling
471
                          repository.iter_files_bytes(
472
                          [('file3-id', 'rev3', 'file1-notpresent')]))
2708.1.3 by Aaron Bentley
Implement extract_files_bytes on Repository
473
2535.3.63 by Andrew Bennetts
Add repository implementations test for item_keys_introduced_by.
474
    def test_item_keys_introduced_by(self):
475
        # Make a repo with one revision and one versioned file.
476
        tree = self.make_branch_and_tree('t')
477
        self.build_tree(['t/foo'])
478
        tree.add('foo', 'file1')
479
        tree.commit('message', rev_id='rev_id')
480
        repo = tree.branch.repository
481
482
        # Item keys will be in this order, for maximum convenience for
483
        # generating data to insert into knit repository:
484
        #   * files
485
        #   * inventory
486
        #   * signatures
487
        #   * revisions
488
        expected_item_keys = [
489
            ('file', 'file1', ['rev_id']),
490
            ('inventory', None, ['rev_id']),
491
            ('signatures', None, []),
492
            ('revisions', None, ['rev_id'])]
493
        item_keys = list(repo.item_keys_introduced_by(['rev_id']))
494
        item_keys = [
495
            (kind, file_id, list(versions))
496
            for (kind, file_id, versions) in item_keys]
497
498
        if repo.supports_rich_root():
499
            # Check for the root versioned file in the item_keys, then remove
500
            # it from streamed_names so we can compare that with
501
            # expected_record_names.
502
            # Note that the file keys can be in any order, so this test is
503
            # written to allow that.
504
            inv = repo.get_inventory('rev_id')
505
            root_item_key = ('file', inv.root.file_id, ['rev_id'])
506
            self.assertTrue(root_item_key in item_keys)
507
            item_keys.remove(root_item_key)
508
509
        self.assertEqual(expected_item_keys, item_keys)
510
2850.4.1 by Andrew Bennetts
Add smoketest for repo.get_graph, and fix bug in RemoteRepository.get_graph that it reveals.
511
    def test_get_graph(self):
512
        """Bare-bones smoketest that all repositories implement get_graph."""
513
        repo = self.make_repository('repo')
2592.3.214 by Robert Collins
Merge bzr.dev.
514
        repo.lock_read()
515
        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.
516
        repo.get_graph()
517
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
518
    def test_implements_revision_graph_can_have_wrong_parents(self):
519
        """All repositories should implement
520
        revision_graph_can_have_wrong_parents, so that check and reconcile can
521
        work correctly.
522
        """
523
        repo = self.make_repository('.')
524
        # This should work, not raise NotImplementedError:
2592.3.214 by Robert Collins
Merge bzr.dev.
525
        if not repo.revision_graph_can_have_wrong_parents():
526
            return
527
        repo.lock_read()
528
        self.addCleanup(repo.unlock)
529
        # This repo must also implement
530
        # _find_inconsistent_revision_parents and
531
        # _check_for_inconsistent_revision_parents.  So calling these
532
        # should not raise NotImplementedError.
533
        list(repo._find_inconsistent_revision_parents())
534
        repo._check_for_inconsistent_revision_parents()
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
535
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
536
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
537
class TestRepositoryLocking(TestCaseWithRepository):
538
539
    def test_leave_lock_in_place(self):
540
        repo = self.make_repository('r')
541
        # Lock the repository, then use leave_lock_in_place so that when we
542
        # 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.
543
        token = repo.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
544
        try:
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
545
            if token is None:
546
                # This test does not apply, because this repository refuses lock
547
                # tokens.
548
                self.assertRaises(NotImplementedError, repo.leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
549
                return
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
550
            repo.leave_lock_in_place()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
551
        finally:
552
            repo.unlock()
553
        # We should be unable to relock the repo.
554
        self.assertRaises(errors.LockContention, repo.lock_write)
555
556
    def test_dont_leave_lock_in_place(self):
557
        repo = self.make_repository('r')
558
        # Create a lock on disk.
559
        token = repo.lock_write()
560
        try:
561
            if token is None:
562
                # This test does not apply, because this repository refuses lock
563
                # tokens.
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
564
                self.assertRaises(NotImplementedError,
565
                                  repo.dont_leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
566
                return
567
            try:
568
                repo.leave_lock_in_place()
569
            except NotImplementedError:
570
                # This repository doesn't support this API.
571
                return
572
        finally:
573
            repo.unlock()
574
        # Reacquire the lock (with a different repository object) by using the
575
        # token.
576
        new_repo = repo.bzrdir.open_repository()
577
        new_repo.lock_write(token=token)
578
        # Call dont_leave_lock_in_place, so that the lock will be released by
579
        # this instance, even though the lock wasn't originally acquired by it.
580
        new_repo.dont_leave_lock_in_place()
581
        new_repo.unlock()
582
        # Now the repository is unlocked.  Test this by locking it (without a
583
        # token).
584
        repo.lock_write()
585
        repo.unlock()
586
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
587
    def test_lock_read_then_unlock(self):
588
        # Calling lock_read then unlocking should work without errors.
589
        repo = self.make_repository('r')
590
        repo.lock_read()
591
        repo.unlock()
592
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
593
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
594
class TestCaseWithComplexRepository(TestCaseWithRepository):
595
596
    def setUp(self):
597
        super(TestCaseWithComplexRepository, self).setUp()
598
        tree_a = self.make_branch_and_tree('a')
599
        self.bzrdir = tree_a.branch.bzrdir
600
        # 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.
601
        # 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.
602
        tree_a.lock_write()
603
        try:
604
            tree_a.branch.repository.start_write_group()
605
            inv_file = tree_a.branch.repository.get_inventory_weave()
606
            try:
607
                inv_file.add_lines('orphan', [], [])
608
            except:
609
                tree_a.branch.repository.commit_write_group()
610
                raise
611
            else:
612
                tree_a.branch.repository.abort_write_group()
613
        finally:
614
            tree_a.unlock()
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
615
        # add a real revision 'rev1'
616
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
617
        # add a real revision 'rev2' based on rev1
618
        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.
619
        # 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.
620
        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.
621
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
622
        # 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.
623
        tree_a.add_parent_tree_id('ghost1')
624
        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.
625
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
626
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
627
    def test_revision_trees(self):
628
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
629
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
630
        repository.lock_read()
631
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
632
        trees1 = list(repository.revision_trees(revision_ids))
633
        trees2 = [repository.revision_tree(t) for t in revision_ids]
634
        assert len(trees1) == len(trees2)
635
        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.
636
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
637
1756.3.22 by Aaron Bentley
Tweaks from review
638
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
639
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
640
        repository.lock_read()
641
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
642
        revisions = [repository.get_revision(r) for r in 
643
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
644
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
645
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
646
                   revisions]
647
        assert deltas1 == deltas2
648
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
649
    def test_all_revision_ids(self):
650
        # 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.
651
        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.
652
                         self.bzrdir.open_repository().all_revision_ids())
653
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
654
    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.
655
        # get_ancestry(revision that is in some data but not fully installed
656
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
657
        self.assertRaises(errors.NoSuchRevision,
658
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
659
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
660
    def test_get_unsorted_ancestry(self):
661
        repo = self.bzrdir.open_repository()
662
        self.assertEqual(set(repo.get_ancestry('rev3')),
663
                         set(repo.get_ancestry('rev3', topo_sorted=False)))
664
1590.1.1 by Robert Collins
Improve common_ancestor performance.
665
    def test_get_revision_graph(self):
666
        # 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:
667
        self.assertEqual({'rev1':(),
668
                          'rev2':('rev1', ),
669
                          'rev3':('rev2', ),
670
                          '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.
671
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
672
                         self.bzrdir.open_repository().get_revision_graph(None))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
673
        self.assertEqual({'rev1':()},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
674
                         self.bzrdir.open_repository().get_revision_graph('rev1'))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
675
        self.assertEqual({'rev1':(),
676
                          'rev2':('rev1', )},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
677
                         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.
678
        self.assertRaises(errors.NoSuchRevision,
1590.1.1 by Robert Collins
Improve common_ancestor performance.
679
                          self.bzrdir.open_repository().get_revision_graph,
680
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
681
        # and ghosts are not mentioned
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
682
        self.assertEqual({'rev1':(),
683
                          'rev2':('rev1', ),
684
                          '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.
685
                          },
686
                         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.
687
        # and we can ask for the NULLREVISION graph
688
        self.assertEqual({},
689
            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.
690
691
    def test_get_revision_graph_with_ghosts(self):
692
        # we can get a graph object with roots, ghosts, ancestors and
693
        # descendants.
694
        repo = self.bzrdir.open_repository()
695
        graph = repo.get_revision_graph_with_ghosts([])
696
        self.assertEqual(set(['rev1']), graph.roots)
697
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
698
        self.assertEqual({'rev1':[],
699
                          'rev2':['rev1'],
700
                          'rev3':['rev2', 'ghost1'],
701
                          'rev4':['rev3', 'ghost1', 'ghost2'],
702
                          },
703
                          graph.get_ancestors())
704
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
705
                          'ghost2':{'rev4':1},
706
                          'rev1':{'rev2':1},
707
                          'rev2':{'rev3':1},
708
                          'rev3':{'rev4':1},
709
                          'rev4':{},
710
                          },
711
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
712
        # and we can ask for the NULLREVISION graph
713
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
714
        self.assertEqual({}, graph.get_ancestors())
715
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
716
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
717
    def test_reserved_id(self):
718
        repo = self.make_repository('repository')
2592.3.61 by Robert Collins
Remove inventory.kndx.
719
        repo.lock_write()
720
        repo.start_write_group()
721
        try:
722
            self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
723
                              None, None)
724
            self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
725
                              None)
726
        finally:
727
            repo.abort_write_group()
728
            repo.unlock()
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
729
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
730
731
class TestCaseWithCorruptRepository(TestCaseWithRepository):
732
733
    def setUp(self):
734
        super(TestCaseWithCorruptRepository, self).setUp()
735
        # a inventory with no parents and the revision has parents..
736
        # i.e. a ghost.
737
        repo = self.make_repository('inventory_with_unnecessary_ghost')
2592.3.38 by Robert Collins
All experimental format tests passing again.
738
        repo.lock_write()
739
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
740
        inv = Inventory(revision_id = 'ghost')
741
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
742
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
743
        rev = bzrlib.revision.Revision(timestamp=0,
744
                                       timezone=None,
745
                                       committer="Foo Bar <foo@example.com>",
746
                                       message="Message",
747
                                       inventory_sha1=sha1,
748
                                       revision_id='ghost')
749
        rev.parent_ids = ['the_ghost']
750
        repo.add_revision('ghost', rev)
751
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
752
        inv = Inventory(revision_id = 'the_ghost')
753
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
754
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
755
        rev = bzrlib.revision.Revision(timestamp=0,
756
                                       timezone=None,
757
                                       committer="Foo Bar <foo@example.com>",
758
                                       message="Message",
759
                                       inventory_sha1=sha1,
760
                                       revision_id='the_ghost')
761
        rev.parent_ids = []
762
        repo.add_revision('the_ghost', rev)
763
        # check its setup usefully
764
        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.
765
        self.assertEqual(['ghost'], inv_weave.get_ancestry(['ghost']))
2592.3.38 by Robert Collins
All experimental format tests passing again.
766
        repo.commit_write_group()
767
        repo.unlock()
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
768
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
769
    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.
770
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
771
        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.
772
        reported_wrong = False
773
        try:
774
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
775
                reported_wrong = True
776
        except errors.CorruptRepository:
777
            # caught the bad data:
778
            return
779
        if not reported_wrong:
780
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
781
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
782
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
783
    def test_corrupt_revision_get_revision_reconcile(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
784
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
785
        repo = repository.Repository.open(repo_url)
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
786
        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.
787
788
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
789
# FIXME: document why this is a TestCaseWithTransport rather than a
790
#        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.
791
class TestEscaping(TestCaseWithTransport):
792
    """Test that repositories can be stored correctly on VFAT transports.
793
    
794
    Makes sure we have proper escaping of invalid characters, etc.
795
796
    It'd be better to test all operations on the FakeVFATTransportDecorator,
797
    but working trees go straight to the os not through the Transport layer.
798
    Therefore we build some history first in the regular way and then 
799
    check it's safe to access for vfat.
800
    """
801
802
    def test_on_vfat(self):
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
803
        # dont bother with remote repository testing, because this test is
804
        # about local disk layout/support.
805
        from bzrlib.remote import RemoteRepositoryFormat
806
        if isinstance(self.repository_format, RemoteRepositoryFormat):
807
            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.
808
        FOO_ID = 'foo<:>ID'
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
809
        REV_ID = 'revid-1' 
810
        # this makes a default format repository always, which is wrong: 
811
        # it should be a TestCaseWithRepository in order to get the 
812
        # 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.
813
        wt = self.make_branch_and_tree('repo')
2052.2.1 by Alexander Belchenko
test_on_vfat win32 fix: use binary line-endings
814
        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.
815
        # add file with id containing wierd characters
816
        wt.add(['foo'], [FOO_ID])
817
        wt.commit('this is my new commit', rev_id=REV_ID)
818
        # now access over vfat; should be safe
819
        branch = bzrdir.BzrDir.open('vfat+' + self.get_url('repo')).open_branch()
820
        revtree = branch.repository.revision_tree(REV_ID)
821
        contents = revtree.get_file_text(FOO_ID)
822
        self.assertEqual(contents, 'contents of repo/foo\n')
2520.4.54 by Aaron Bentley
Hang a create_bundle method off repository
823
824
    def test_create_bundle(self):
825
        wt = self.make_branch_and_tree('repo')
826
        self.build_tree(['repo/file1'])
827
        wt.add('file1')
828
        wt.commit('file1', rev_id='rev1')
829
        fileobj = StringIO()
830
        wt.branch.repository.create_bundle('rev1', NULL_REVISION, fileobj)