/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 
374
        # template from the test suite parameterisation.
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
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
529
    def test_implements_revision_graph_can_have_wrong_parents(self):
530
        """All repositories should implement
531
        revision_graph_can_have_wrong_parents, so that check and reconcile can
532
        work correctly.
533
        """
534
        repo = self.make_repository('.')
535
        # This should work, not raise NotImplementedError:
2592.3.214 by Robert Collins
Merge bzr.dev.
536
        if not repo.revision_graph_can_have_wrong_parents():
537
            return
538
        repo.lock_read()
539
        self.addCleanup(repo.unlock)
540
        # This repo must also implement
541
        # _find_inconsistent_revision_parents and
542
        # _check_for_inconsistent_revision_parents.  So calling these
543
        # should not raise NotImplementedError.
544
        list(repo._find_inconsistent_revision_parents())
545
        repo._check_for_inconsistent_revision_parents()
2819.2.4 by Andrew Bennetts
Add a 'revision_graph_can_have_wrong_parents' method to repository.
546
2996.2.4 by Aaron Bentley
Rename function to add_signature_text
547
    def test_add_signature_text(self):
2996.2.3 by Aaron Bentley
Add tests for install_revisions and add_signature
548
        repo = self.make_repository('repo')
549
        repo.lock_write()
550
        self.addCleanup(repo.unlock)
551
        self.addCleanup(repo.commit_write_group)
552
        repo.start_write_group()
553
        inv = Inventory(revision_id='A')
554
        inv.root.revision = 'A'
555
        repo.add_inventory('A', inv, [])
556
        repo.add_revision('A', Revision('A', committer='A', timestamp=0,
557
                          inventory_sha1='', timezone=0, message='A'))
2996.2.4 by Aaron Bentley
Rename function to add_signature_text
558
        repo.add_signature_text('A', 'This might be a signature')
2996.2.3 by Aaron Bentley
Add tests for install_revisions and add_signature
559
        self.assertEqual('This might be a signature',
560
                         repo.get_signature_text('A'))
561
562
    def test_install_revisions(self):
563
        wt = self.make_branch_and_tree('source')
564
        wt.commit('A', allow_pointless=True, rev_id='A')
565
        repo = wt.branch.repository
566
        repo.lock_write()
567
        repo.start_write_group()
568
        repo.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
569
        repo.commit_write_group()
570
        repo.unlock()
571
        repo.lock_read()
572
        self.addCleanup(repo.unlock)
573
        repo2 = self.make_repository('repo2')
574
        revision = repo.get_revision('A')
575
        tree = repo.revision_tree('A')
576
        signature = repo.get_signature_text('A')
577
        repo2.lock_write()
578
        self.addCleanup(repo2.unlock)
579
        repository.install_revisions(repo2, [(revision, tree, signature)])
580
        self.assertEqual(revision, repo2.get_revision('A'))
581
        self.assertEqual(signature, repo2.get_signature_text('A'))
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
582
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
583
    # XXX: this helper duplicated from tests.test_repository
584
    def make_remote_repository(self, path):
585
        """Make a RemoteRepository object backed by a real repository that will
586
        be created at the given path."""
587
        repo = self.make_repository(path)
588
        smart_server = server.SmartTCPServer_for_testing()
589
        smart_server.setUp(self.get_server())
590
        remote_transport = get_transport(smart_server.get_url()).clone(path)
591
        self.addCleanup(smart_server.tearDown)
592
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
593
        remote_repo = remote_bzrdir.open_repository()
594
        return remote_repo
595
3047.1.2 by Andrew Bennetts
Directly test that sprouting branches from a HPSS preserves the repository format.
596
    def test_sprout_from_hpss_preserves_format(self):
597
        """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.
598
        if self.repository_format == RepositoryFormat7():
599
            raise KnownFailure(
600
                "Cannot fetch weaves over smart protocol.")
601
        remote_repo = self.make_remote_repository('remote')
602
        local_bzrdir = self.make_bzrdir('local')
603
        try:
604
            local_repo = remote_repo.sprout(local_bzrdir)
605
        except errors.TransportNotPossible:
606
            raise TestNotApplicable(
607
                "Cannot lock_read old formats like AllInOne over HPSS.")
608
        remote_backing_repo = bzrdir.BzrDir.open(
609
            self.get_vfs_only_url('remote')).open_repository()
610
        self.assertEqual(remote_backing_repo._format, local_repo._format)
611
3047.1.2 by Andrew Bennetts
Directly test that sprouting branches from a HPSS preserves the repository format.
612
    def test_sprout_branch_from_hpss_preserves_repo_format(self):
613
        """branch.sprout from a smart server preserves the repository format.
614
        """
615
        weave_formats = [RepositoryFormat5(), RepositoryFormat6(),
616
                         RepositoryFormat7()]
617
        if self.repository_format in weave_formats:
618
            raise KnownFailure(
619
                "Cannot fetch weaves over smart protocol.")
620
        remote_repo = self.make_remote_repository('remote')
621
        remote_branch = remote_repo.bzrdir.create_branch()
622
        try:
623
            local_bzrdir = remote_branch.bzrdir.sprout('local')
624
        except errors.TransportNotPossible:
625
            raise TestNotApplicable(
626
                "Cannot lock_read old formats like AllInOne over HPSS.")
627
        local_repo = local_bzrdir.open_repository()
628
        remote_backing_repo = bzrdir.BzrDir.open(
629
            self.get_vfs_only_url('remote')).open_repository()
630
        self.assertEqual(remote_backing_repo._format, local_repo._format)
631
3089.2.1 by Andrew Bennetts
Implement RemoteRepository._make_parents_provider.
632
    def test__make_parents_provider(self):
633
        """Repositories must have a _make_parents_provider method that returns
634
        an object with a get_parents method.
635
        """
636
        repo = self.make_repository('repo')
637
        repo._make_parents_provider().get_parents
638
3047.1.1 by Andrew Bennetts
Fix for bug 164626, add test that Repository.sprout preserves format.
639
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
640
class TestRepositoryLocking(TestCaseWithRepository):
641
642
    def test_leave_lock_in_place(self):
643
        repo = self.make_repository('r')
644
        # Lock the repository, then use leave_lock_in_place so that when we
645
        # 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.
646
        token = repo.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
647
        try:
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
648
            if token is None:
649
                # This test does not apply, because this repository refuses lock
650
                # tokens.
651
                self.assertRaises(NotImplementedError, repo.leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
652
                return
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
653
            repo.leave_lock_in_place()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
654
        finally:
655
            repo.unlock()
656
        # We should be unable to relock the repo.
657
        self.assertRaises(errors.LockContention, repo.lock_write)
658
659
    def test_dont_leave_lock_in_place(self):
660
        repo = self.make_repository('r')
661
        # Create a lock on disk.
662
        token = repo.lock_write()
663
        try:
664
            if token is None:
665
                # This test does not apply, because this repository refuses lock
666
                # tokens.
2018.5.76 by Andrew Bennetts
Testing that repository.{dont_,}leave_lock_in_place raises NotImplementedError if lock_write returns None.
667
                self.assertRaises(NotImplementedError,
668
                                  repo.dont_leave_lock_in_place)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
669
                return
670
            try:
671
                repo.leave_lock_in_place()
672
            except NotImplementedError:
673
                # This repository doesn't support this API.
674
                return
675
        finally:
676
            repo.unlock()
677
        # Reacquire the lock (with a different repository object) by using the
678
        # token.
679
        new_repo = repo.bzrdir.open_repository()
680
        new_repo.lock_write(token=token)
681
        # Call dont_leave_lock_in_place, so that the lock will be released by
682
        # this instance, even though the lock wasn't originally acquired by it.
683
        new_repo.dont_leave_lock_in_place()
684
        new_repo.unlock()
685
        # Now the repository is unlocked.  Test this by locking it (without a
686
        # token).
687
        repo.lock_write()
688
        repo.unlock()
689
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
690
    def test_lock_read_then_unlock(self):
691
        # Calling lock_read then unlocking should work without errors.
692
        repo = self.make_repository('r')
693
        repo.lock_read()
694
        repo.unlock()
695
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
696
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
697
class TestCaseWithComplexRepository(TestCaseWithRepository):
698
699
    def setUp(self):
700
        super(TestCaseWithComplexRepository, self).setUp()
701
        tree_a = self.make_branch_and_tree('a')
702
        self.bzrdir = tree_a.branch.bzrdir
703
        # 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.
704
        # 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.
705
        tree_a.lock_write()
706
        try:
707
            tree_a.branch.repository.start_write_group()
708
            inv_file = tree_a.branch.repository.get_inventory_weave()
709
            try:
710
                inv_file.add_lines('orphan', [], [])
711
            except:
712
                tree_a.branch.repository.commit_write_group()
713
                raise
714
            else:
715
                tree_a.branch.repository.abort_write_group()
716
        finally:
717
            tree_a.unlock()
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
718
        # add a real revision 'rev1'
719
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
720
        # add a real revision 'rev2' based on rev1
721
        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.
722
        # 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.
723
        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.
724
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
725
        # 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.
726
        tree_a.add_parent_tree_id('ghost1')
727
        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.
728
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
729
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
730
    def test_revision_trees(self):
731
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
732
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
733
        repository.lock_read()
734
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
735
        trees1 = list(repository.revision_trees(revision_ids))
736
        trees2 = [repository.revision_tree(t) for t in revision_ids]
737
        assert len(trees1) == len(trees2)
738
        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.
739
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
740
1756.3.22 by Aaron Bentley
Tweaks from review
741
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
742
        repository = self.bzrdir.open_repository()
2592.3.214 by Robert Collins
Merge bzr.dev.
743
        repository.lock_read()
744
        self.addCleanup(repository.unlock)
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
745
        revisions = [repository.get_revision(r) for r in 
746
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
747
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
748
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
749
                   revisions]
750
        assert deltas1 == deltas2
751
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
752
    def test_all_revision_ids(self):
753
        # 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.
754
        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.
755
                         self.bzrdir.open_repository().all_revision_ids())
756
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
757
    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.
758
        # get_ancestry(revision that is in some data but not fully installed
759
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
760
        self.assertRaises(errors.NoSuchRevision,
761
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
762
2530.1.1 by Aaron Bentley
Make topological sorting optional for get_ancestry
763
    def test_get_unsorted_ancestry(self):
764
        repo = self.bzrdir.open_repository()
765
        self.assertEqual(set(repo.get_ancestry('rev3')),
766
                         set(repo.get_ancestry('rev3', topo_sorted=False)))
767
1590.1.1 by Robert Collins
Improve common_ancestor performance.
768
    def test_get_revision_graph(self):
769
        # 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:
770
        self.assertEqual({'rev1':(),
771
                          'rev2':('rev1', ),
772
                          'rev3':('rev2', ),
773
                          '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.
774
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
775
                         self.bzrdir.open_repository().get_revision_graph(None))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
776
        self.assertEqual({'rev1':()},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
777
                         self.bzrdir.open_repository().get_revision_graph('rev1'))
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
778
        self.assertEqual({'rev1':(),
779
                          'rev2':('rev1', )},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
780
                         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.
781
        self.assertRaises(errors.NoSuchRevision,
1590.1.1 by Robert Collins
Improve common_ancestor performance.
782
                          self.bzrdir.open_repository().get_revision_graph,
783
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
784
        # and ghosts are not mentioned
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
785
        self.assertEqual({'rev1':(),
786
                          'rev2':('rev1', ),
787
                          '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.
788
                          },
789
                         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.
790
        # and we can ask for the NULLREVISION graph
791
        self.assertEqual({},
792
            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.
793
794
    def test_get_revision_graph_with_ghosts(self):
795
        # we can get a graph object with roots, ghosts, ancestors and
796
        # descendants.
797
        repo = self.bzrdir.open_repository()
798
        graph = repo.get_revision_graph_with_ghosts([])
799
        self.assertEqual(set(['rev1']), graph.roots)
800
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
801
        self.assertEqual({'rev1':[],
802
                          'rev2':['rev1'],
803
                          'rev3':['rev2', 'ghost1'],
804
                          'rev4':['rev3', 'ghost1', 'ghost2'],
805
                          },
806
                          graph.get_ancestors())
807
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
808
                          'ghost2':{'rev4':1},
809
                          'rev1':{'rev2':1},
810
                          'rev2':{'rev3':1},
811
                          'rev3':{'rev4':1},
812
                          'rev4':{},
813
                          },
814
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
815
        # and we can ask for the NULLREVISION graph
816
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
817
        self.assertEqual({}, graph.get_ancestors())
818
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
819
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
820
    def test_reserved_id(self):
821
        repo = self.make_repository('repository')
2592.3.61 by Robert Collins
Remove inventory.kndx.
822
        repo.lock_write()
823
        repo.start_write_group()
824
        try:
825
            self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
826
                              None, None)
827
            self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
828
                              None)
829
        finally:
830
            repo.abort_write_group()
831
            repo.unlock()
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
832
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
833
834
class TestCaseWithCorruptRepository(TestCaseWithRepository):
835
836
    def setUp(self):
837
        super(TestCaseWithCorruptRepository, self).setUp()
838
        # a inventory with no parents and the revision has parents..
839
        # i.e. a ghost.
840
        repo = self.make_repository('inventory_with_unnecessary_ghost')
2592.3.38 by Robert Collins
All experimental format tests passing again.
841
        repo.lock_write()
842
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
843
        inv = Inventory(revision_id = 'ghost')
844
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
845
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
846
        rev = bzrlib.revision.Revision(timestamp=0,
847
                                       timezone=None,
848
                                       committer="Foo Bar <foo@example.com>",
849
                                       message="Message",
850
                                       inventory_sha1=sha1,
851
                                       revision_id='ghost')
852
        rev.parent_ids = ['the_ghost']
853
        repo.add_revision('ghost', rev)
854
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
855
        inv = Inventory(revision_id = 'the_ghost')
856
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
857
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
858
        rev = bzrlib.revision.Revision(timestamp=0,
859
                                       timezone=None,
860
                                       committer="Foo Bar <foo@example.com>",
861
                                       message="Message",
862
                                       inventory_sha1=sha1,
863
                                       revision_id='the_ghost')
864
        rev.parent_ids = []
865
        repo.add_revision('the_ghost', rev)
866
        # check its setup usefully
867
        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.
868
        self.assertEqual(['ghost'], inv_weave.get_ancestry(['ghost']))
2592.3.38 by Robert Collins
All experimental format tests passing again.
869
        repo.commit_write_group()
870
        repo.unlock()
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
871
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
872
    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.
873
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
874
        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.
875
        reported_wrong = False
876
        try:
877
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
878
                reported_wrong = True
879
        except errors.CorruptRepository:
880
            # caught the bad data:
881
            return
882
        if not reported_wrong:
883
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
884
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
885
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
886
    def test_corrupt_revision_get_revision_reconcile(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
887
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
888
        repo = repository.Repository.open(repo_url)
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
889
        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.
890
891
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
892
# FIXME: document why this is a TestCaseWithTransport rather than a
893
#        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.
894
class TestEscaping(TestCaseWithTransport):
895
    """Test that repositories can be stored correctly on VFAT transports.
896
    
897
    Makes sure we have proper escaping of invalid characters, etc.
898
899
    It'd be better to test all operations on the FakeVFATTransportDecorator,
900
    but working trees go straight to the os not through the Transport layer.
901
    Therefore we build some history first in the regular way and then 
902
    check it's safe to access for vfat.
903
    """
904
905
    def test_on_vfat(self):
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
906
        # dont bother with remote repository testing, because this test is
907
        # about local disk layout/support.
908
        from bzrlib.remote import RemoteRepositoryFormat
909
        if isinstance(self.repository_format, RemoteRepositoryFormat):
910
            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.
911
        FOO_ID = 'foo<:>ID'
2018.5.29 by Robert Collins
Dont run the vfat repository test on RemoteRepositories as there is no point.
912
        REV_ID = 'revid-1' 
913
        # this makes a default format repository always, which is wrong: 
914
        # it should be a TestCaseWithRepository in order to get the 
915
        # 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.
916
        wt = self.make_branch_and_tree('repo')
2052.2.1 by Alexander Belchenko
test_on_vfat win32 fix: use binary line-endings
917
        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.
918
        # add file with id containing wierd characters
919
        wt.add(['foo'], [FOO_ID])
920
        wt.commit('this is my new commit', rev_id=REV_ID)
921
        # now access over vfat; should be safe
922
        branch = bzrdir.BzrDir.open('vfat+' + self.get_url('repo')).open_branch()
923
        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.
924
        revtree.lock_read()
925
        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.
926
        contents = revtree.get_file_text(FOO_ID)
927
        self.assertEqual(contents, 'contents of repo/foo\n')
2520.4.54 by Aaron Bentley
Hang a create_bundle method off repository
928
929
    def test_create_bundle(self):
930
        wt = self.make_branch_and_tree('repo')
931
        self.build_tree(['repo/file1'])
932
        wt.add('file1')
933
        wt.commit('file1', rev_id='rev1')
934
        fileobj = StringIO()
935
        wt.branch.repository.create_bundle('rev1', NULL_REVISION, fileobj)