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