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