/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
1
# Copyright (C) 2005, 2006 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
19
import os
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
import sys
22
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.
23
import bzrlib
1773.4.3 by Martin Pool
[merge] bzr.dev
24
from bzrlib import bzrdir, errors, repository
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
25
from bzrlib.branch import Branch, needs_read_lock, needs_write_lock
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
26
from bzrlib.delta import TreeDelta
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
27
from bzrlib.errors import (FileExists,
28
                           NoSuchRevision,
29
                           NoSuchFile,
30
                           UninitializableFormat,
31
                           NotBranchError,
32
                           )
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
33
from bzrlib.inventory import Inventory
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
34
from bzrlib.revision import NULL_REVISION
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
35
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
36
from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
37
from bzrlib.trace import mutter
38
import bzrlib.transactions as transactions
39
from bzrlib.transport import get_transport
40
from bzrlib.upgrade import upgrade
41
from bzrlib.workingtree import WorkingTree
42
43
44
class TestCaseWithRepository(TestCaseWithBzrDir):
45
46
    def setUp(self):
47
        super(TestCaseWithRepository, self).setUp()
48
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
49
    def make_branch(self, relpath, format=None):
50
        repo = self.make_repository(relpath, format=None)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
51
        return repo.bzrdir.create_branch()
52
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
53
    def make_repository(self, relpath, format=None):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
54
        made_control = self.make_bzrdir(relpath)
55
        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.
56
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.
57
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
58
class TestRepository(TestCaseWithRepository):
59
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.
60
    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.
61
        #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.
62
        # such as signatures[not tested yet] etc etc.
63
        # when changing to the current default format.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
64
        tree_a = self.make_branch_and_tree('a')
65
        self.build_tree(['a/foo'])
66
        tree_a.add('foo', 'file1')
67
        tree_a.commit('rev1', rev_id='rev1')
68
        bzrdirb = self.make_bzrdir('b')
69
        repo_b = tree_a.branch.repository.clone(bzrdirb)
70
        tree_b = repo_b.revision_tree('rev1')
71
        tree_b.get_file_text('file1')
72
        rev1 = repo_b.get_revision('rev1')
73
74
    def test_clone_specific_format(self):
75
        """todo"""
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
76
77
    def test_format_initialize_find_open(self):
78
        # loopback test to check the current format initializes to itself.
79
        if not self.repository_format.is_supported():
80
            # unsupported formats are not loopback testable
81
            # because the default open will not open them and
82
            # they may not be initializable.
83
            return
84
        # supported formats must be able to init and open
85
        t = get_transport(self.get_url())
86
        readonly_t = get_transport(self.get_readonly_url())
87
        made_control = self.bzrdir_format.initialize(t.base)
88
        made_repo = self.repository_format.initialize(made_control)
89
        self.failUnless(isinstance(made_repo, repository.Repository))
90
        self.assertEqual(made_control, made_repo.bzrdir)
91
92
        # find it via bzrdir opening:
93
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
94
        direct_opened_repo = opened_control.open_repository()
95
        self.assertEqual(direct_opened_repo.__class__, made_repo.__class__)
96
        self.assertEqual(opened_control, direct_opened_repo.bzrdir)
97
98
        self.failUnless(isinstance(direct_opened_repo._format,
99
                        self.repository_format.__class__))
100
        # find it via Repository.open
101
        opened_repo = repository.Repository.open(readonly_t.base)
102
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
103
        self.assertEqual(made_repo._format.__class__,
104
                         opened_repo._format.__class__)
105
        # if it has a unique id string, can we probe for it ?
106
        try:
107
            self.repository_format.get_format_string()
108
        except NotImplementedError:
109
            return
110
        self.assertEqual(self.repository_format,
111
                         repository.RepositoryFormat.find_format(opened_control))
112
113
    def test_create_repository(self):
1534.6.1 by Robert Collins
allow API creation of shared repositories
114
        # 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.
115
        if not self.bzrdir_format.is_supported():
116
            # unsupported formats are not loopback testable
117
            # because the default open will not open them and
118
            # they may not be initializable.
119
            return
120
        t = get_transport(self.get_url())
121
        made_control = self.bzrdir_format.initialize(t.base)
122
        made_repo = made_control.create_repository()
123
        self.failUnless(isinstance(made_repo, repository.Repository))
124
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.1 by Robert Collins
allow API creation of shared repositories
125
        
126
    def test_create_repository_shared(self):
127
        # bzrdir can construct a shared repository.
128
        if not self.bzrdir_format.is_supported():
129
            # unsupported formats are not loopback testable
130
            # because the default open will not open them and
131
            # they may not be initializable.
132
            return
133
        t = get_transport(self.get_url())
134
        made_control = self.bzrdir_format.initialize(t.base)
135
        try:
136
            made_repo = made_control.create_repository(shared=True)
137
        except errors.IncompatibleFormat:
138
            # not all repository formats understand being shared, or
139
            # may only be shared in some circumstances.
140
            return
141
        self.failUnless(isinstance(made_repo, repository.Repository))
142
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
143
        self.assertTrue(made_repo.is_shared())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
144
145
    def test_revision_tree(self):
146
        wt = self.make_branch_and_tree('.')
147
        wt.commit('lala!', rev_id='revision-1', allow_pointless=True)
148
        tree = wt.branch.repository.revision_tree('revision-1')
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
149
        self.assertEqual(list(tree.list_files()), [])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
150
        tree = wt.branch.repository.revision_tree(None)
1852.5.1 by Robert Collins
Deprecate EmptyTree in favour of using Repository.revision_tree.
151
        self.assertEqual([], list(tree.list_files()))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
152
        tree = wt.branch.repository.revision_tree(NULL_REVISION)
1852.5.1 by Robert Collins
Deprecate EmptyTree in favour of using Repository.revision_tree.
153
        self.assertEqual([], list(tree.list_files()))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
154
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.
155
    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.
156
        # smoke test fetch to ensure that the convenience function works.
157
        # it is defined as a convenience function with the underlying 
158
        # functionality provided by an InterRepository
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
159
        tree_a = self.make_branch_and_tree('a')
160
        self.build_tree(['a/foo'])
161
        tree_a.add('foo', 'file1')
162
        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.
163
        # fetch with a default limit (grab everything)
164
        repo = bzrdir.BzrDir.create_repository(self.get_url('b'))
1910.2.26 by Aaron Bentley
Fix up some test cases
165
        if (tree_a.branch.repository._format.rich_root_data and not
166
            repo._format.rich_root_data):
167
            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.
168
        repo.fetch(tree_a.branch.repository,
169
                   revision_id=None,
170
                   pb=bzrlib.progress.DummyProgress())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
171
1910.2.17 by Aaron Bentley
Get fetching from 1 to 2 under test
172
    def test_fetch_knit2(self):
173
        tree_a = self.make_branch_and_tree('a')
174
        self.build_tree(['a/foo'])
175
        tree_a.add('foo', 'file1')
176
        tree_a.commit('rev1', rev_id='rev1')
177
        # fetch with a default limit (grab everything)
178
        f = bzrdir.BzrDirMetaFormat1()
179
        f._repository_format = repository.RepositoryFormatKnit2()
180
        os.mkdir('b')
181
        b_bzrdir = f.initialize(self.get_url('b'))
182
        repo = b_bzrdir.create_repository()
183
        repo.fetch(tree_a.branch.repository,
184
                   revision_id=None,
185
                   pb=bzrlib.progress.DummyProgress())
1910.2.18 by Aaron Bentley
Implement creation of knits for tree roots
186
        rev1_tree = repo.revision_tree('rev1')
1910.2.19 by Aaron Bentley
Test whether revision id for root is retained
187
        lines = rev1_tree.get_file_lines(rev1_tree.inventory.root.file_id)
188
        self.assertEqual([], lines)
189
        b_branch = b_bzrdir.create_branch()
190
        b_branch.pull(tree_a.branch)
191
        tree_b = b_bzrdir.create_workingtree()
192
        tree_b.commit('no change', rev_id='rev2')
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
193
        rev2_tree = repo.revision_tree('rev2')
194
        self.assertEqual('rev1', rev2_tree.inventory.root.revision)
1910.2.17 by Aaron Bentley
Get fetching from 1 to 2 under test
195
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
196
    def test_get_revision_delta(self):
197
        tree_a = self.make_branch_and_tree('a')
198
        self.build_tree(['a/foo'])
199
        tree_a.add('foo', 'file1')
200
        tree_a.commit('rev1', rev_id='rev1')
201
        self.build_tree(['a/vla'])
202
        tree_a.add('vla', 'file2')
203
        tree_a.commit('rev2', rev_id='rev2')
204
205
        delta = tree_a.branch.repository.get_revision_delta('rev1')
206
        self.assertIsInstance(delta, TreeDelta)
207
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
208
        delta = tree_a.branch.repository.get_revision_delta('rev2')
209
        self.assertIsInstance(delta, TreeDelta)
210
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
211
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.
212
    def test_clone_bzrdir_repository_revision(self):
213
        # make a repository with some revisions,
214
        # and clone it, this should not have unreferenced revisions.
215
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
216
        raise TestSkipped('revision limiting is not implemented yet.')
217
218
    def test_clone_repository_basis_revision(self):
219
        raise TestSkipped('the use of a basis should not add noise data to the result.')
220
221
    def test_clone_repository_incomplete_source_with_basis(self):
222
        # ensure that basis really does grab from the basis by having incomplete source
223
        tree = self.make_branch_and_tree('commit_tree')
224
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
225
        tree.add('foo')
226
        tree.commit('revision 1', rev_id='1')
227
        source = self.make_repository('source')
228
        # this gives us an incomplete repository
229
        tree.bzrdir.open_repository().copy_content_into(source)
230
        tree.commit('revision 2', rev_id='2', allow_pointless=True)
231
        self.assertFalse(source.has_revision('2'))
232
        target = source.bzrdir.clone(self.get_url('target'), basis=tree.bzrdir)
233
        self.assertTrue(target.open_repository().has_revision('2'))
234
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
235
    def test_clone_shared_no_tree(self):
236
        # cloning a shared repository keeps it shared
237
        # and preserves the make_working_tree setting.
238
        made_control = self.make_bzrdir('source')
239
        try:
240
            made_repo = made_control.create_repository(shared=True)
241
        except errors.IncompatibleFormat:
242
            # not all repository formats understand being shared, or
243
            # may only be shared in some circumstances.
244
            return
245
        made_repo.set_make_working_trees(False)
246
        result = made_control.clone(self.get_url('target'))
247
        self.failUnless(isinstance(made_repo, repository.Repository))
248
        self.assertEqual(made_control, made_repo.bzrdir)
249
        self.assertTrue(result.open_repository().is_shared())
250
        self.assertFalse(result.open_repository().make_working_trees())
251
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.
252
    def test_upgrade_preserves_signatures(self):
253
        wt = self.make_branch_and_tree('source')
254
        wt.commit('A', allow_pointless=True, rev_id='A')
255
        wt.branch.repository.sign_revision('A',
256
            bzrlib.gpg.LoopbackGPGStrategy(None))
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
257
        old_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.
258
        try:
259
            old_format = bzrdir.BzrDirFormat.get_default_format()
260
            # This gives metadir branches something they can convert to.
261
            # it would be nice to have a 'latest' vs 'default' concept.
262
            bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
263
            try:
264
                upgrade(wt.basedir)
265
            finally:
266
                bzrdir.BzrDirFormat.set_default_format(old_format)
267
        except errors.UpToDateFormat:
268
            # this is in the most current format already.
269
            return
1910.2.12 by Aaron Bentley
Implement knit repo format 2
270
        except errors.BadConversionTarget, e:
271
            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.
272
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
273
        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.
274
        self.assertEqual(old_signature, new_signature)
275
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
276
    def test_exposed_versioned_files_are_marked_dirty(self):
277
        repo = self.make_repository('.')
278
        repo.lock_write()
279
        inv = repo.get_inventory_weave()
280
        repo.unlock()
281
        self.assertRaises(errors.OutSideTransaction, inv.add_lines, 'foo', [], [])
282
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
283
    def test_format_description(self):
284
        repo = self.make_repository('.')
285
        text = repo._format.get_format_description()
286
        self.failUnless(len(text))
287
1666.1.6 by Robert Collins
Make knit the default format.
288
    def assertMessageRoundtrips(self, message):
289
        """Assert that message roundtrips to a repository and back intact."""
290
        tree = self.make_branch_and_tree('.')
291
        tree.commit(message, rev_id='a', allow_pointless=True)
292
        rev = tree.branch.repository.get_revision('a')
293
        # we have to manually escape this as we dont try to
294
        # roundtrip xml invalid characters at this point.
295
        # when escaping is moved to the serialiser, this test
296
        # can check against the literal message rather than
297
        # this escaped version.
298
        escaped_message, escape_count = re.subn(
299
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
300
            lambda match: match.group(0).encode('unicode_escape'),
301
            message)
302
        escaped_message= re.sub('\r', '\n', escaped_message)
303
        self.assertEqual(rev.message, escaped_message)
304
        # insist the class is unicode no matter what came in for 
305
        # consistency.
306
        self.assertIsInstance(rev.message, unicode)
307
308
    def test_commit_unicode_message(self):
309
        # a siple unicode message should be preserved
310
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
311
312
    def test_commit_unicode_control_characters(self):
313
        # a unicode message with control characters should roundtrip too.
314
        self.assertMessageRoundtrips(
315
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
316
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
317
    def test_check_repository(self):
318
        """Check a fairly simple repository's history"""
319
        tree = self.make_branch_and_tree('.')
320
        tree.commit('initial empty commit', rev_id='a-rev',
321
                    allow_pointless=True)
322
        result = tree.branch.repository.check(['a-rev'])
323
        # writes to log; should accept both verbose or non-verbose
324
        result.report_results(verbose=True)
325
        result.report_results(verbose=False)
326
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
327
    def test_get_revisions(self):
328
        tree = self.make_branch_and_tree('.')
329
        tree.commit('initial empty commit', rev_id='a-rev',
330
                    allow_pointless=True)
331
        tree.commit('second empty commit', rev_id='b-rev',
332
                    allow_pointless=True)
333
        tree.commit('third empty commit', rev_id='c-rev',
334
                    allow_pointless=True)
335
        repo = tree.branch.repository
336
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
337
        revisions = repo.get_revisions(revision_ids)
338
        assert len(revisions) == 3, repr(revisions)
339
        zipped = zip(revisions, revision_ids)
340
        self.assertEqual(len(zipped), 3)
341
        for revision, revision_id in zipped:
342
            self.assertEqual(revision.revision_id, revision_id)
343
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
344
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
345
    def test_root_entry_has_revision(self):
346
        tree = self.make_branch_and_tree('.')
347
        tree.commit('message', rev_id='rev_id')
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
348
        self.assertEqual('rev_id', tree.basis_tree().inventory.root.revision)
1908.7.6 by Robert Collins
Deprecate WorkingTree.last_revision.
349
        rev_tree = tree.branch.repository.revision_tree(tree.get_parent_ids()[0])
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
350
        self.assertEqual('rev_id', rev_tree.inventory.root.revision)
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
351
1910.2.31 by Aaron Bentley
Fix bugs in basis inventory handling, change filename
352
    def test_create_basis_inventory(self):
353
        # Needs testing here because differences between repo and working tree
354
        # basis inventory formats can lead to bugs.
355
        t = self.make_branch_and_tree('.')
356
        b = t.branch
357
        open('a', 'wb').write('a\n')
358
        t.add('a')
359
        t.commit('a', rev_id='r1')
360
361
        t._control_files.get_utf8('basis-inventory-cache')
362
363
        basis_inv = t.basis_tree().inventory
364
        self.assertEquals('r1', basis_inv.revision_id)
365
        
366
        store_inv = b.repository.get_inventory('r1')
367
        self.assertEquals(store_inv._byid, basis_inv._byid)
368
369
        open('b', 'wb').write('b\n')
370
        t.add('b')
371
        t.commit('b', rev_id='r2')
372
373
        t._control_files.get_utf8('basis-inventory-cache')
374
375
        basis_inv_txt = t.read_basis_inventory()
376
        basis_inv = bzrlib.xml6.serializer_v6.read_inventory_from_string(basis_inv_txt)
377
        self.assertEquals('r2', basis_inv.revision_id)
378
        store_inv = b.repository.get_inventory('r2')
379
380
        self.assertEquals(store_inv._byid, basis_inv._byid)
381
1910.2.36 by Aaron Bentley
Get upgrade from format4 under test and fixed for all formats
382
    def test_upgrade_from_format4(self):
383
        from bzrlib.tests.test_upgrade import _upgrade_dir_template
384
        if self.repository_format.__class__ == repository.RepositoryFormat4:
385
            raise TestSkipped('Cannot convert format-4 to itself')
386
        self.build_tree_contents(_upgrade_dir_template)
387
        old_repodir = bzrlib.bzrdir.BzrDir.open_unsupported('.')
388
        old_repo_format = old_repodir.open_repository()._format
389
        format = self.repository_format._matchingbzrdir
390
        try:
391
            format.repository_format = self.repository_format
392
        except AttributeError:
393
            pass
394
        upgrade('.', format)
395
1910.2.37 by Aaron Bentley
Handle empty commits, fix test
396
    def test_pointless_commit(self):
397
        tree = self.make_branch_and_tree('.')
398
        self.assertRaises(errors.PointlessCommit, tree.commit, 'pointless',
399
                          allow_pointless=False)
400
        tree.commit('pointless', allow_pointless=True)
401
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
402
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
403
class TestCaseWithComplexRepository(TestCaseWithRepository):
404
405
    def setUp(self):
406
        super(TestCaseWithComplexRepository, self).setUp()
407
        tree_a = self.make_branch_and_tree('a')
408
        self.bzrdir = tree_a.branch.bzrdir
409
        # 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.
410
        # 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.
411
        inv_file = tree_a.branch.repository.control_weaves.get_weave(
412
            'inventory', 
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
413
            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.
414
        inv_file.add_lines('orphan', [], [])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
415
        # add a real revision 'rev1'
416
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
417
        # add a real revision 'rev2' based on rev1
418
        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.
419
        # 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.
420
        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.
421
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
422
        # 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.
423
        tree_a.add_parent_tree_id('ghost1')
424
        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.
425
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
426
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
427
    def test_revision_trees(self):
428
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
429
        repository = self.bzrdir.open_repository()
430
        trees1 = list(repository.revision_trees(revision_ids))
431
        trees2 = [repository.revision_tree(t) for t in revision_ids]
432
        assert len(trees1) == len(trees2)
433
        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.
434
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
435
1756.3.22 by Aaron Bentley
Tweaks from review
436
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
437
        repository = self.bzrdir.open_repository()
438
        revisions = [repository.get_revision(r) for r in 
439
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
440
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
441
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
442
                   revisions]
443
        assert deltas1 == deltas2
444
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
445
    def test_all_revision_ids(self):
446
        # 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.
447
        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.
448
                         self.bzrdir.open_repository().all_revision_ids())
449
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
450
    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.
451
        # get_ancestry(revision that is in some data but not fully installed
452
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
453
        self.assertRaises(errors.NoSuchRevision,
454
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
455
1590.1.1 by Robert Collins
Improve common_ancestor performance.
456
    def test_get_revision_graph(self):
457
        # 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.
458
        self.assertEqual({'rev1':[],
459
                          'rev2':['rev1'],
460
                          'rev3':['rev2'],
461
                          'rev4':['rev3'],
462
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
463
                         self.bzrdir.open_repository().get_revision_graph(None))
464
        self.assertEqual({'rev1':[]},
465
                         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.
466
        self.assertEqual({'rev1':[],
467
                          'rev2':['rev1']},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
468
                         self.bzrdir.open_repository().get_revision_graph('rev2'))
469
        self.assertRaises(NoSuchRevision,
470
                          self.bzrdir.open_repository().get_revision_graph,
471
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
472
        # and ghosts are not mentioned
473
        self.assertEqual({'rev1':[],
474
                          'rev2':['rev1'],
475
                          'rev3':['rev2'],
476
                          },
477
                         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.
478
        # and we can ask for the NULLREVISION graph
479
        self.assertEqual({},
480
            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.
481
482
    def test_get_revision_graph_with_ghosts(self):
483
        # we can get a graph object with roots, ghosts, ancestors and
484
        # descendants.
485
        repo = self.bzrdir.open_repository()
486
        graph = repo.get_revision_graph_with_ghosts([])
487
        self.assertEqual(set(['rev1']), graph.roots)
488
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
489
        self.assertEqual({'rev1':[],
490
                          'rev2':['rev1'],
491
                          'rev3':['rev2', 'ghost1'],
492
                          'rev4':['rev3', 'ghost1', 'ghost2'],
493
                          },
494
                          graph.get_ancestors())
495
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
496
                          'ghost2':{'rev4':1},
497
                          'rev1':{'rev2':1},
498
                          'rev2':{'rev3':1},
499
                          'rev3':{'rev4':1},
500
                          'rev4':{},
501
                          },
502
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
503
        # and we can ask for the NULLREVISION graph
504
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
505
        self.assertEqual({}, graph.get_ancestors())
506
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
507
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
508
509
class TestCaseWithCorruptRepository(TestCaseWithRepository):
510
511
    def setUp(self):
512
        super(TestCaseWithCorruptRepository, self).setUp()
513
        # a inventory with no parents and the revision has parents..
514
        # i.e. a ghost.
515
        repo = self.make_repository('inventory_with_unnecessary_ghost')
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
516
        inv = Inventory(revision_id = 'ghost')
517
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
518
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
519
        rev = bzrlib.revision.Revision(timestamp=0,
520
                                       timezone=None,
521
                                       committer="Foo Bar <foo@example.com>",
522
                                       message="Message",
523
                                       inventory_sha1=sha1,
524
                                       revision_id='ghost')
525
        rev.parent_ids = ['the_ghost']
526
        repo.add_revision('ghost', rev)
527
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
528
        inv = Inventory(revision_id = 'the_ghost')
529
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
530
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
531
        rev = bzrlib.revision.Revision(timestamp=0,
532
                                       timezone=None,
533
                                       committer="Foo Bar <foo@example.com>",
534
                                       message="Message",
535
                                       inventory_sha1=sha1,
536
                                       revision_id='the_ghost')
537
        rev.parent_ids = []
538
        repo.add_revision('the_ghost', rev)
539
        # check its setup usefully
540
        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.
541
        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.
542
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
543
    def test_corrupt_revision_access_asserts_if_reported_wrong(self):
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
544
        repo = repository.Repository.open('inventory_with_unnecessary_ghost')
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
545
        reported_wrong = False
546
        try:
547
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
548
                reported_wrong = True
549
        except errors.CorruptRepository:
550
            # caught the bad data:
551
            return
552
        if not reported_wrong:
553
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
554
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
555
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
556
    def test_corrupt_revision_get_revision_reconcile(self):
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
557
        repo = repository.Repository.open('inventory_with_unnecessary_ghost')
558
        repo.get_revision_reconcile('ghost')