/brz/remove-bazaar

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