/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
                           )
1731.1.33 by Aaron Bentley
Revert no-special-root changes
33
from bzrlib.inventory import Inventory, InventoryDirectory
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('.')
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')
174
        self.build_tree(['a/foo'])
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'))
1910.2.26 by Aaron Bentley
Fix up some test cases
179
        if (tree_a.branch.repository._format.rich_root_data and not
180
            repo._format.rich_root_data):
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):
187
        tree_a = self.make_branch_and_tree('a')
188
        self.build_tree(['a/foo'])
189
        tree_a.add('foo', 'file1')
190
        tree_a.commit('rev1', rev_id='rev1')
191
        # fetch with a default limit (grab everything)
192
        f = bzrdir.BzrDirMetaFormat1()
193
        f._repository_format = repository.RepositoryFormatKnit2()
194
        os.mkdir('b')
195
        b_bzrdir = f.initialize(self.get_url('b'))
196
        repo = b_bzrdir.create_repository()
197
        repo.fetch(tree_a.branch.repository,
198
                   revision_id=None,
199
                   pb=bzrlib.progress.DummyProgress())
1910.2.18 by Aaron Bentley
Implement creation of knits for tree roots
200
        rev1_tree = repo.revision_tree('rev1')
1910.2.19 by Aaron Bentley
Test whether revision id for root is retained
201
        lines = rev1_tree.get_file_lines(rev1_tree.inventory.root.file_id)
202
        self.assertEqual([], lines)
203
        b_branch = b_bzrdir.create_branch()
204
        b_branch.pull(tree_a.branch)
205
        tree_b = b_bzrdir.create_workingtree()
206
        tree_b.commit('no change', rev_id='rev2')
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
207
        rev2_tree = repo.revision_tree('rev2')
208
        self.assertEqual('rev1', rev2_tree.inventory.root.revision)
1910.2.17 by Aaron Bentley
Get fetching from 1 to 2 under test
209
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
210
    def test_get_revision_delta(self):
211
        tree_a = self.make_branch_and_tree('a')
212
        self.build_tree(['a/foo'])
213
        tree_a.add('foo', 'file1')
214
        tree_a.commit('rev1', rev_id='rev1')
215
        self.build_tree(['a/vla'])
216
        tree_a.add('vla', 'file2')
217
        tree_a.commit('rev2', rev_id='rev2')
218
219
        delta = tree_a.branch.repository.get_revision_delta('rev1')
220
        self.assertIsInstance(delta, TreeDelta)
221
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
222
        delta = tree_a.branch.repository.get_revision_delta('rev2')
223
        self.assertIsInstance(delta, TreeDelta)
224
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
225
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.
226
    def test_clone_bzrdir_repository_revision(self):
227
        # make a repository with some revisions,
228
        # and clone it, this should not have unreferenced revisions.
229
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
230
        raise TestSkipped('revision limiting is not implemented yet.')
231
232
    def test_clone_repository_basis_revision(self):
233
        raise TestSkipped('the use of a basis should not add noise data to the result.')
234
235
    def test_clone_repository_incomplete_source_with_basis(self):
236
        # ensure that basis really does grab from the basis by having incomplete source
237
        tree = self.make_branch_and_tree('commit_tree')
238
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
239
        tree.add('foo')
240
        tree.commit('revision 1', rev_id='1')
241
        source = self.make_repository('source')
242
        # this gives us an incomplete repository
243
        tree.bzrdir.open_repository().copy_content_into(source)
244
        tree.commit('revision 2', rev_id='2', allow_pointless=True)
245
        self.assertFalse(source.has_revision('2'))
246
        target = source.bzrdir.clone(self.get_url('target'), basis=tree.bzrdir)
247
        self.assertTrue(target.open_repository().has_revision('2'))
248
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
249
    def test_clone_shared_no_tree(self):
250
        # cloning a shared repository keeps it shared
251
        # and preserves the make_working_tree setting.
252
        made_control = self.make_bzrdir('source')
253
        try:
254
            made_repo = made_control.create_repository(shared=True)
255
        except errors.IncompatibleFormat:
256
            # not all repository formats understand being shared, or
257
            # may only be shared in some circumstances.
258
            return
259
        made_repo.set_make_working_trees(False)
260
        result = made_control.clone(self.get_url('target'))
261
        self.failUnless(isinstance(made_repo, repository.Repository))
262
        self.assertEqual(made_control, made_repo.bzrdir)
263
        self.assertTrue(result.open_repository().is_shared())
264
        self.assertFalse(result.open_repository().make_working_trees())
265
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.
266
    def test_upgrade_preserves_signatures(self):
267
        wt = self.make_branch_and_tree('source')
268
        wt.commit('A', allow_pointless=True, rev_id='A')
269
        wt.branch.repository.sign_revision('A',
270
            bzrlib.gpg.LoopbackGPGStrategy(None))
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
271
        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.
272
        try:
273
            old_format = bzrdir.BzrDirFormat.get_default_format()
274
            # This gives metadir branches something they can convert to.
275
            # it would be nice to have a 'latest' vs 'default' concept.
2204.4.13 by Aaron Bentley
Update all test cases to avoid set_default_format
276
            format = bzrdir.format_registry.make_bzrdir('experimental-knit2')
277
            upgrade(wt.basedir, 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.
278
        except errors.UpToDateFormat:
279
            # this is in the most current format already.
280
            return
1910.2.12 by Aaron Bentley
Implement knit repo format 2
281
        except errors.BadConversionTarget, e:
282
            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.
283
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
284
        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.
285
        self.assertEqual(old_signature, new_signature)
286
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
287
    def test_exposed_versioned_files_are_marked_dirty(self):
288
        repo = self.make_repository('.')
289
        repo.lock_write()
290
        inv = repo.get_inventory_weave()
291
        repo.unlock()
292
        self.assertRaises(errors.OutSideTransaction, inv.add_lines, 'foo', [], [])
293
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
294
    def test_format_description(self):
295
        repo = self.make_repository('.')
296
        text = repo._format.get_format_description()
297
        self.failUnless(len(text))
298
1666.1.6 by Robert Collins
Make knit the default format.
299
    def assertMessageRoundtrips(self, message):
300
        """Assert that message roundtrips to a repository and back intact."""
301
        tree = self.make_branch_and_tree('.')
302
        tree.commit(message, rev_id='a', allow_pointless=True)
303
        rev = tree.branch.repository.get_revision('a')
304
        # we have to manually escape this as we dont try to
305
        # roundtrip xml invalid characters at this point.
306
        # when escaping is moved to the serialiser, this test
307
        # can check against the literal message rather than
308
        # this escaped version.
309
        escaped_message, escape_count = re.subn(
310
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
311
            lambda match: match.group(0).encode('unicode_escape'),
312
            message)
313
        escaped_message= re.sub('\r', '\n', escaped_message)
314
        self.assertEqual(rev.message, escaped_message)
315
        # insist the class is unicode no matter what came in for 
316
        # consistency.
317
        self.assertIsInstance(rev.message, unicode)
318
319
    def test_commit_unicode_message(self):
320
        # a siple unicode message should be preserved
321
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
322
323
    def test_commit_unicode_control_characters(self):
324
        # a unicode message with control characters should roundtrip too.
325
        self.assertMessageRoundtrips(
326
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
327
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
328
    def test_check_repository(self):
329
        """Check a fairly simple repository's history"""
330
        tree = self.make_branch_and_tree('.')
331
        tree.commit('initial empty commit', rev_id='a-rev',
332
                    allow_pointless=True)
333
        result = tree.branch.repository.check(['a-rev'])
334
        # writes to log; should accept both verbose or non-verbose
335
        result.report_results(verbose=True)
336
        result.report_results(verbose=False)
337
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
338
    def test_get_revisions(self):
339
        tree = self.make_branch_and_tree('.')
340
        tree.commit('initial empty commit', rev_id='a-rev',
341
                    allow_pointless=True)
342
        tree.commit('second empty commit', rev_id='b-rev',
343
                    allow_pointless=True)
344
        tree.commit('third empty commit', rev_id='c-rev',
345
                    allow_pointless=True)
346
        repo = tree.branch.repository
347
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
348
        revisions = repo.get_revisions(revision_ids)
349
        assert len(revisions) == 3, repr(revisions)
350
        zipped = zip(revisions, revision_ids)
351
        self.assertEqual(len(zipped), 3)
352
        for revision, revision_id in zipped:
353
            self.assertEqual(revision.revision_id, revision_id)
354
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
355
1910.2.1 by Aaron Bentley
Ensure root entry always has a revision
356
    def test_root_entry_has_revision(self):
357
        tree = self.make_branch_and_tree('.')
358
        tree.commit('message', rev_id='rev_id')
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
359
        self.assertEqual('rev_id', tree.basis_tree().inventory.root.revision)
1908.7.6 by Robert Collins
Deprecate WorkingTree.last_revision.
360
        rev_tree = tree.branch.repository.revision_tree(tree.get_parent_ids()[0])
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
1910.2.31 by Aaron Bentley
Fix bugs in basis inventory handling, change filename
363
    def test_create_basis_inventory(self):
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()
387
        basis_inv = bzrlib.xml6.serializer_v6.read_inventory_from_string(basis_inv_txt)
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
395
        if self.repository_format.__class__ == repository.RepositoryFormat4:
396
            raise TestSkipped('Cannot convert format-4 to itself')
397
        self.build_tree_contents(_upgrade_dir_template)
398
        old_repodir = bzrlib.bzrdir.BzrDir.open_unsupported('.')
399
        old_repo_format = old_repodir.open_repository()._format
400
        format = self.repository_format._matchingbzrdir
401
        try:
402
            format.repository_format = self.repository_format
403
        except AttributeError:
404
            pass
405
        upgrade('.', format)
406
1910.2.37 by Aaron Bentley
Handle empty commits, fix test
407
    def test_pointless_commit(self):
408
        tree = self.make_branch_and_tree('.')
409
        self.assertRaises(errors.PointlessCommit, tree.commit, 'pointless',
410
                          allow_pointless=False)
411
        tree.commit('pointless', allow_pointless=True)
412
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
413
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
414
class TestCaseWithComplexRepository(TestCaseWithRepository):
415
416
    def setUp(self):
417
        super(TestCaseWithComplexRepository, self).setUp()
418
        tree_a = self.make_branch_and_tree('a')
419
        self.bzrdir = tree_a.branch.bzrdir
420
        # 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.
421
        # 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.
422
        inv_file = tree_a.branch.repository.control_weaves.get_weave(
423
            'inventory', 
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
424
            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.
425
        inv_file.add_lines('orphan', [], [])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
426
        # add a real revision 'rev1'
427
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
428
        # add a real revision 'rev2' based on rev1
429
        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.
430
        # 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.
431
        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.
432
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
433
        # 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.
434
        tree_a.add_parent_tree_id('ghost1')
435
        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.
436
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
437
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
438
    def test_revision_trees(self):
439
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
440
        repository = self.bzrdir.open_repository()
441
        trees1 = list(repository.revision_trees(revision_ids))
442
        trees2 = [repository.revision_tree(t) for t in revision_ids]
443
        assert len(trees1) == len(trees2)
444
        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.
445
            assert not tree2.changes_from(tree1).has_changed()
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
446
1756.3.22 by Aaron Bentley
Tweaks from review
447
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
448
        repository = self.bzrdir.open_repository()
449
        revisions = [repository.get_revision(r) for r in 
450
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
451
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
452
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
453
                   revisions]
454
        assert deltas1 == deltas2
455
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
456
    def test_all_revision_ids(self):
457
        # 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.
458
        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.
459
                         self.bzrdir.open_repository().all_revision_ids())
460
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
461
    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.
462
        # get_ancestry(revision that is in some data but not fully installed
463
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
464
        self.assertRaises(errors.NoSuchRevision,
465
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
466
1590.1.1 by Robert Collins
Improve common_ancestor performance.
467
    def test_get_revision_graph(self):
468
        # 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.
469
        self.assertEqual({'rev1':[],
470
                          'rev2':['rev1'],
471
                          'rev3':['rev2'],
472
                          'rev4':['rev3'],
473
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
474
                         self.bzrdir.open_repository().get_revision_graph(None))
475
        self.assertEqual({'rev1':[]},
476
                         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.
477
        self.assertEqual({'rev1':[],
478
                          'rev2':['rev1']},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
479
                         self.bzrdir.open_repository().get_revision_graph('rev2'))
480
        self.assertRaises(NoSuchRevision,
481
                          self.bzrdir.open_repository().get_revision_graph,
482
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
483
        # and ghosts are not mentioned
484
        self.assertEqual({'rev1':[],
485
                          'rev2':['rev1'],
486
                          'rev3':['rev2'],
487
                          },
488
                         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.
489
        # and we can ask for the NULLREVISION graph
490
        self.assertEqual({},
491
            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.
492
493
    def test_get_revision_graph_with_ghosts(self):
494
        # we can get a graph object with roots, ghosts, ancestors and
495
        # descendants.
496
        repo = self.bzrdir.open_repository()
497
        graph = repo.get_revision_graph_with_ghosts([])
498
        self.assertEqual(set(['rev1']), graph.roots)
499
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
500
        self.assertEqual({'rev1':[],
501
                          'rev2':['rev1'],
502
                          'rev3':['rev2', 'ghost1'],
503
                          'rev4':['rev3', 'ghost1', 'ghost2'],
504
                          },
505
                          graph.get_ancestors())
506
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
507
                          'ghost2':{'rev4':1},
508
                          'rev1':{'rev2':1},
509
                          'rev2':{'rev3':1},
510
                          'rev3':{'rev4':1},
511
                          'rev4':{},
512
                          },
513
                          graph.get_descendants())
1836.3.1 by Robert Collins
(robertc) Teach repository.get_revision_graph, and revision.common_ancestor, about NULL_REVISION.
514
        # and we can ask for the NULLREVISION graph
515
        graph = repo.get_revision_graph_with_ghosts([NULL_REVISION])
516
        self.assertEqual({}, graph.get_ancestors())
517
        self.assertEqual({}, graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
518
2229.2.1 by Aaron Bentley
Reject reserved ids in versiondfile, tree, branch and repository
519
    def test_reserved_id(self):
520
        repo = self.make_repository('repository')
521
        self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
522
                          None, None)
523
        self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
524
                          None)
2229.2.3 by Aaron Bentley
change reserved_id to is_reserved_id, add check_not_reserved for DRY
525
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
526
527
class TestCaseWithCorruptRepository(TestCaseWithRepository):
528
529
    def setUp(self):
530
        super(TestCaseWithCorruptRepository, self).setUp()
531
        # a inventory with no parents and the revision has parents..
532
        # i.e. a ghost.
533
        repo = self.make_repository('inventory_with_unnecessary_ghost')
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
534
        inv = Inventory(revision_id = 'ghost')
535
        inv.root.revision = 'ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
536
        sha1 = repo.add_inventory('ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
537
        rev = bzrlib.revision.Revision(timestamp=0,
538
                                       timezone=None,
539
                                       committer="Foo Bar <foo@example.com>",
540
                                       message="Message",
541
                                       inventory_sha1=sha1,
542
                                       revision_id='ghost')
543
        rev.parent_ids = ['the_ghost']
544
        repo.add_revision('ghost', rev)
545
         
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
546
        inv = Inventory(revision_id = 'the_ghost')
547
        inv.root.revision = 'the_ghost'
1907.1.1 by Aaron Bentley
Unshelved all changes except those related to removing RootEntry
548
        sha1 = repo.add_inventory('the_ghost', inv, [])
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
549
        rev = bzrlib.revision.Revision(timestamp=0,
550
                                       timezone=None,
551
                                       committer="Foo Bar <foo@example.com>",
552
                                       message="Message",
553
                                       inventory_sha1=sha1,
554
                                       revision_id='the_ghost')
555
        rev.parent_ids = []
556
        repo.add_revision('the_ghost', rev)
557
        # check its setup usefully
558
        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.
559
        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.
560
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
561
    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.
562
        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.
563
        reported_wrong = False
564
        try:
565
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
566
                reported_wrong = True
567
        except errors.CorruptRepository:
568
            # caught the bad data:
569
            return
570
        if not reported_wrong:
571
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
572
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
573
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
574
    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.
575
        repo = repository.Repository.open('inventory_with_unnecessary_ghost')
576
        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.
577
578
579
class TestEscaping(TestCaseWithTransport):
580
    """Test that repositories can be stored correctly on VFAT transports.
581
    
582
    Makes sure we have proper escaping of invalid characters, etc.
583
584
    It'd be better to test all operations on the FakeVFATTransportDecorator,
585
    but working trees go straight to the os not through the Transport layer.
586
    Therefore we build some history first in the regular way and then 
587
    check it's safe to access for vfat.
588
    """
589
590
    def test_on_vfat(self):
591
        FOO_ID = 'foo<:>ID'
592
        REV_ID = 'revid-1'
593
        wt = self.make_branch_and_tree('repo')
2052.2.1 by Alexander Belchenko
test_on_vfat win32 fix: use binary line-endings
594
        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.
595
        # add file with id containing wierd characters
596
        wt.add(['foo'], [FOO_ID])
597
        wt.commit('this is my new commit', rev_id=REV_ID)
598
        # now access over vfat; should be safe
599
        branch = bzrdir.BzrDir.open('vfat+' + self.get_url('repo')).open_branch()
600
        revtree = branch.repository.revision_tree(REV_ID)
601
        contents = revtree.get_file_text(FOO_ID)
602
        self.assertEqual(contents, 'contents of repo/foo\n')