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