~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-09-20 02:40:52 UTC
  • mfrom: (2835.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070920024052-y2l7r5o00zrpnr73
No longer propagate index differences automatically (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# (C) 2006 Canonical Ltd
2
 
 
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
22
also see this file.
23
23
"""
24
24
 
25
 
from stat import *
 
25
from stat import S_ISDIR
26
26
from StringIO import StringIO
27
27
 
 
28
from bzrlib import symbol_versioning
28
29
import bzrlib
29
30
import bzrlib.bzrdir as bzrdir
30
31
import bzrlib.errors as errors
33
34
                           UnknownFormatError,
34
35
                           UnsupportedFormatError,
35
36
                           )
36
 
import bzrlib.repository as repository
37
 
from bzrlib.tests import TestCase, TestCaseWithTransport
 
37
from bzrlib.repository import RepositoryFormat
 
38
from bzrlib.tests import (
 
39
    TestCase,
 
40
    TestCaseWithTransport,
 
41
    test_knit,
 
42
    )
38
43
from bzrlib.transport import get_transport
39
 
from bzrlib.transport.http import HttpServer
40
44
from bzrlib.transport.memory import MemoryServer
 
45
from bzrlib.util import bencode
 
46
from bzrlib import (
 
47
    repository,
 
48
    upgrade,
 
49
    workingtree,
 
50
    )
 
51
from bzrlib.repofmt import knitrepo, weaverepo
41
52
 
42
53
 
43
54
class TestDefaultFormat(TestCase):
44
55
 
45
56
    def test_get_set_default_format(self):
 
57
        old_default = bzrdir.format_registry.get('default')
 
58
        private_default = old_default().repository_format.__class__
46
59
        old_format = repository.RepositoryFormat.get_default_format()
47
 
        self.assertTrue(isinstance(old_format, repository.RepositoryFormatKnit1))
48
 
        repository.RepositoryFormat.set_default_format(SampleRepositoryFormat())
 
60
        self.assertTrue(isinstance(old_format, private_default))
 
61
        def make_sample_bzrdir():
 
62
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
 
63
            my_bzrdir.repository_format = SampleRepositoryFormat()
 
64
            return my_bzrdir
 
65
        bzrdir.format_registry.remove('default')
 
66
        bzrdir.format_registry.register('sample', make_sample_bzrdir, '')
 
67
        bzrdir.format_registry.set_default('sample')
49
68
        # creating a repository should now create an instrumented dir.
50
69
        try:
51
70
            # the default branch format is used by the meta dir format
52
71
            # which is not the default bzrdir format at this point
53
 
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:/')
 
72
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
54
73
            result = dir.create_repository()
55
74
            self.assertEqual(result, 'A bzr repository dir')
56
75
        finally:
57
 
            repository.RepositoryFormat.set_default_format(old_format)
58
 
        self.assertEqual(old_format, repository.RepositoryFormat.get_default_format())
 
76
            bzrdir.format_registry.remove('default')
 
77
            bzrdir.format_registry.remove('sample')
 
78
            bzrdir.format_registry.register('default', old_default, '')
 
79
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
 
80
                              old_format.__class__)
59
81
 
60
82
 
61
83
class SampleRepositoryFormat(repository.RepositoryFormat):
72
94
    def initialize(self, a_bzrdir, shared=False):
73
95
        """Initialize a repository in a BzrDir"""
74
96
        t = a_bzrdir.get_repository_transport(self)
75
 
        t.put('format', StringIO(self.get_format_string()))
 
97
        t.put_bytes('format', self.get_format_string())
76
98
        return 'A bzr repository dir'
77
99
 
78
100
    def is_supported(self):
96
118
            t = get_transport(url)
97
119
            found_format = repository.RepositoryFormat.find_format(dir)
98
120
            self.failUnless(isinstance(found_format, format.__class__))
99
 
        check_format(repository.RepositoryFormat7(), "bar")
 
121
        check_format(weaverepo.RepositoryFormat7(), "bar")
100
122
        
101
123
    def test_find_format_no_repository(self):
102
124
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
131
153
 
132
154
    def test_no_ancestry_weave(self):
133
155
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
134
 
        repo = repository.RepositoryFormat6().initialize(control)
 
156
        repo = weaverepo.RepositoryFormat6().initialize(control)
135
157
        # We no longer need to create the ancestry.weave file
136
158
        # since it is *never* used.
137
159
        self.assertRaises(NoSuchFile,
143
165
    
144
166
    def test_disk_layout(self):
145
167
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
146
 
        repo = repository.RepositoryFormat7().initialize(control)
 
168
        repo = weaverepo.RepositoryFormat7().initialize(control)
147
169
        # in case of side effects of locking.
148
170
        repo.lock_write()
149
171
        repo.unlock()
165
187
 
166
188
    def test_shared_disk_layout(self):
167
189
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
168
 
        repo = repository.RepositoryFormat7().initialize(control, shared=True)
 
190
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
169
191
        # we want:
170
192
        # format 'Bazaar-NG Repository format 7'
171
193
        # inventory.weave == empty_weave
188
210
    def test_creates_lockdir(self):
189
211
        """Make sure it appears to be controlled by a LockDir existence"""
190
212
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
191
 
        repo = repository.RepositoryFormat7().initialize(control, shared=True)
 
213
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
192
214
        t = control.get_repository_transport(None)
193
215
        # TODO: Should check there is a 'lock' toplevel directory, 
194
216
        # regardless of contents
204
226
        """repo format 7 actually locks on lockdir"""
205
227
        base_url = self.get_url()
206
228
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
207
 
        repo = repository.RepositoryFormat7().initialize(control, shared=True)
 
229
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
208
230
        t = control.get_repository_transport(None)
209
231
        repo.lock_write()
210
232
        repo.unlock()
218
240
 
219
241
    def test_shared_no_tree_disk_layout(self):
220
242
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
221
 
        repo = repository.RepositoryFormat7().initialize(control, shared=True)
 
243
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
222
244
        repo.set_make_working_trees(False)
223
245
        # we want:
224
246
        # format 'Bazaar-NG Repository format 7'
247
269
    
248
270
    def test_disk_layout(self):
249
271
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
250
 
        repo = repository.RepositoryFormatKnit1().initialize(control)
 
272
        repo = knitrepo.RepositoryFormatKnit1().initialize(control)
251
273
        # in case of side effects of locking.
252
274
        repo.lock_write()
253
275
        repo.unlock()
280
302
 
281
303
    def test_shared_disk_layout(self):
282
304
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
283
 
        repo = repository.RepositoryFormatKnit1().initialize(control, shared=True)
 
305
        repo = knitrepo.RepositoryFormatKnit1().initialize(control, shared=True)
284
306
        # we want:
285
307
        # format 'Bazaar-NG Knit Repository Format 1'
286
308
        # lock: is a directory
299
321
 
300
322
    def test_shared_no_tree_disk_layout(self):
301
323
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
302
 
        repo = repository.RepositoryFormatKnit1().initialize(control, shared=True)
 
324
        repo = knitrepo.RepositoryFormatKnit1().initialize(control, shared=True)
303
325
        repo.set_make_working_trees(False)
304
326
        # we want:
305
327
        # format 'Bazaar-NG Knit Repository Format 1'
321
343
        self.check_knits(t)
322
344
 
323
345
 
324
 
class InterString(repository.InterRepository):
325
 
    """An inter-repository optimised code path for strings.
326
 
 
327
 
    This is for use during testing where we use strings as repositories
 
346
class KnitRepositoryStreamTests(test_knit.KnitTests):
 
347
    """Tests for knitrepo._get_stream_as_bytes."""
 
348
 
 
349
    def test_get_stream_as_bytes(self):
 
350
        # Make a simple knit
 
351
        k1 = self.make_test_knit()
 
352
        k1.add_lines('text-a', [], test_knit.split_lines(test_knit.TEXT_1))
 
353
        
 
354
        # Serialise it, check the output.
 
355
        bytes = knitrepo._get_stream_as_bytes(k1, ['text-a'])
 
356
        data = bencode.bdecode(bytes)
 
357
        format, record = data
 
358
        self.assertEqual('knit-plain', format)
 
359
        self.assertEqual(['text-a', ['fulltext'], []], record[:3])
 
360
        self.assertRecordContentEqual(k1, 'text-a', record[3])
 
361
 
 
362
    def test_get_stream_as_bytes_all(self):
 
363
        """Get a serialised data stream for all the records in a knit.
 
364
 
 
365
        Much like test_get_stream_all, except for get_stream_as_bytes.
 
366
        """
 
367
        k1 = self.make_test_knit()
 
368
        # Insert the same data as BasicKnitTests.test_knit_join, as they seem
 
369
        # to cover a range of cases (no parents, one parent, multiple parents).
 
370
        test_data = [
 
371
            ('text-a', [], test_knit.TEXT_1),
 
372
            ('text-b', ['text-a'], test_knit.TEXT_1),
 
373
            ('text-c', [], test_knit.TEXT_1),
 
374
            ('text-d', ['text-c'], test_knit.TEXT_1),
 
375
            ('text-m', ['text-b', 'text-d'], test_knit.TEXT_1),
 
376
           ]
 
377
        expected_data_list = [
 
378
            # version, options, parents
 
379
            ('text-a', ['fulltext'], []),
 
380
            ('text-b', ['line-delta'], ['text-a']),
 
381
            ('text-c', ['fulltext'], []),
 
382
            ('text-d', ['line-delta'], ['text-c']),
 
383
            ('text-m', ['line-delta'], ['text-b', 'text-d']),
 
384
            ]
 
385
        for version_id, parents, lines in test_data:
 
386
            k1.add_lines(version_id, parents, test_knit.split_lines(lines))
 
387
 
 
388
        bytes = knitrepo._get_stream_as_bytes(
 
389
            k1, ['text-a', 'text-b', 'text-c', 'text-d', 'text-m'])
 
390
 
 
391
        data = bencode.bdecode(bytes)
 
392
        format = data.pop(0)
 
393
        self.assertEqual('knit-plain', format)
 
394
 
 
395
        for expected, actual in zip(expected_data_list, data):
 
396
            expected_version = expected[0]
 
397
            expected_options = expected[1]
 
398
            expected_parents = expected[2]
 
399
            version, options, parents, bytes = actual
 
400
            self.assertEqual(expected_version, version)
 
401
            self.assertEqual(expected_options, options)
 
402
            self.assertEqual(expected_parents, parents)
 
403
            self.assertRecordContentEqual(k1, version, bytes)
 
404
 
 
405
 
 
406
class DummyRepository(object):
 
407
    """A dummy repository for testing."""
 
408
 
 
409
    _serializer = None
 
410
 
 
411
    def supports_rich_root(self):
 
412
        return False
 
413
 
 
414
 
 
415
class InterDummy(repository.InterRepository):
 
416
    """An inter-repository optimised code path for DummyRepository.
 
417
 
 
418
    This is for use during testing where we use DummyRepository as repositories
328
419
    so that none of the default regsitered inter-repository classes will
329
420
    match.
330
421
    """
331
422
 
332
423
    @staticmethod
333
424
    def is_compatible(repo_source, repo_target):
334
 
        """InterString is compatible with strings-as-repos."""
335
 
        return isinstance(repo_source, str) and isinstance(repo_target, str)
 
425
        """InterDummy is compatible with DummyRepository."""
 
426
        return (isinstance(repo_source, DummyRepository) and 
 
427
            isinstance(repo_target, DummyRepository))
336
428
 
337
429
 
338
430
class TestInterRepository(TestCaseWithTransport):
344
436
        # This also tests that the default registered optimised interrepository
345
437
        # classes do not barf inappropriately when a surprising repository type
346
438
        # is handed to them.
347
 
        dummy_a = "Repository 1."
348
 
        dummy_b = "Repository 2."
 
439
        dummy_a = DummyRepository()
 
440
        dummy_b = DummyRepository()
349
441
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
350
442
 
351
443
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
352
 
        """Asserts that InterRepository.get(repo_a, repo_b) -> the default."""
 
444
        """Asserts that InterRepository.get(repo_a, repo_b) -> the default.
 
445
        
 
446
        The effective default is now InterSameDataRepository because there is
 
447
        no actual sane default in the presence of incompatible data models.
 
448
        """
353
449
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
354
 
        self.assertEqual(repository.InterRepository,
 
450
        self.assertEqual(repository.InterSameDataRepository,
355
451
                         inter_repo.__class__)
356
452
        self.assertEqual(repo_a, inter_repo.source)
357
453
        self.assertEqual(repo_b, inter_repo.target)
362
458
        # and that it is correctly selected when given a repository
363
459
        # pair that it returns true on for the is_compatible static method
364
460
        # check
365
 
        dummy_a = "Repository 1."
366
 
        dummy_b = "Repository 2."
367
 
        repository.InterRepository.register_optimiser(InterString)
 
461
        dummy_a = DummyRepository()
 
462
        dummy_b = DummyRepository()
 
463
        repo = self.make_repository('.')
 
464
        # hack dummies to look like repo somewhat.
 
465
        dummy_a._serializer = repo._serializer
 
466
        dummy_b._serializer = repo._serializer
 
467
        repository.InterRepository.register_optimiser(InterDummy)
368
468
        try:
369
 
            # we should get the default for something InterString returns False
 
469
            # we should get the default for something InterDummy returns False
370
470
            # to
371
 
            self.assertFalse(InterString.is_compatible(dummy_a, None))
372
 
            self.assertGetsDefaultInterRepository(dummy_a, None)
373
 
            # and we should get an InterString for a pair it 'likes'
374
 
            self.assertTrue(InterString.is_compatible(dummy_a, dummy_b))
 
471
            self.assertFalse(InterDummy.is_compatible(dummy_a, repo))
 
472
            self.assertGetsDefaultInterRepository(dummy_a, repo)
 
473
            # and we should get an InterDummy for a pair it 'likes'
 
474
            self.assertTrue(InterDummy.is_compatible(dummy_a, dummy_b))
375
475
            inter_repo = repository.InterRepository.get(dummy_a, dummy_b)
376
 
            self.assertEqual(InterString, inter_repo.__class__)
 
476
            self.assertEqual(InterDummy, inter_repo.__class__)
377
477
            self.assertEqual(dummy_a, inter_repo.source)
378
478
            self.assertEqual(dummy_b, inter_repo.target)
379
479
        finally:
380
 
            repository.InterRepository.unregister_optimiser(InterString)
 
480
            repository.InterRepository.unregister_optimiser(InterDummy)
381
481
        # now we should get the default InterRepository object again.
382
482
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
383
483
 
387
487
    def test_is_compatible_and_registered(self):
388
488
        # InterWeaveRepo is compatible when either side
389
489
        # is a format 5/6/7 branch
390
 
        formats = [repository.RepositoryFormat5(),
391
 
                   repository.RepositoryFormat6(),
392
 
                   repository.RepositoryFormat7()]
393
 
        incompatible_formats = [repository.RepositoryFormat4(),
394
 
                                repository.RepositoryFormatKnit1(),
 
490
        from bzrlib.repofmt import knitrepo, weaverepo
 
491
        formats = [weaverepo.RepositoryFormat5(),
 
492
                   weaverepo.RepositoryFormat6(),
 
493
                   weaverepo.RepositoryFormat7()]
 
494
        incompatible_formats = [weaverepo.RepositoryFormat4(),
 
495
                                knitrepo.RepositoryFormatKnit1(),
395
496
                                ]
396
497
        repo_a = self.make_repository('a')
397
498
        repo_b = self.make_repository('b')
418
519
        t = get_transport(self.get_url('.'))
419
520
        t.mkdir('repository')
420
521
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
421
 
        repo = repository.RepositoryFormat7().initialize(repo_dir)
422
 
        target_format = repository.RepositoryFormatKnit1()
 
522
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
 
523
        target_format = knitrepo.RepositoryFormatKnit1()
423
524
        converter = repository.CopyConverter(target_format)
424
525
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
425
526
        try:
428
529
            pb.finished()
429
530
        repo = repo_dir.open_repository()
430
531
        self.assertTrue(isinstance(target_format, repo._format.__class__))
 
532
 
 
533
 
 
534
class TestMisc(TestCase):
 
535
    
 
536
    def test_unescape_xml(self):
 
537
        """We get some kind of error when malformed entities are passed"""
 
538
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;') 
 
539
 
 
540
 
 
541
class TestRepositoryFormatKnit3(TestCaseWithTransport):
 
542
 
 
543
    def test_convert(self):
 
544
        """Ensure the upgrade adds weaves for roots"""
 
545
        format = bzrdir.BzrDirMetaFormat1()
 
546
        format.repository_format = knitrepo.RepositoryFormatKnit1()
 
547
        tree = self.make_branch_and_tree('.', format)
 
548
        tree.commit("Dull commit", rev_id="dull")
 
549
        revision_tree = tree.branch.repository.revision_tree('dull')
 
550
        self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
 
551
            revision_tree.inventory.root.file_id)
 
552
        format = bzrdir.BzrDirMetaFormat1()
 
553
        format.repository_format = knitrepo.RepositoryFormatKnit3()
 
554
        upgrade.Convert('.', format)
 
555
        tree = workingtree.WorkingTree.open('.')
 
556
        revision_tree = tree.branch.repository.revision_tree('dull')
 
557
        revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
 
558
        tree.commit("Another dull commit", rev_id='dull2')
 
559
        revision_tree = tree.branch.repository.revision_tree('dull2')
 
560
        self.assertEqual('dull', revision_tree.inventory.root.revision)
 
561