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