~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Martin Pool
  • Date: 2010-02-25 06:17:27 UTC
  • mfrom: (5055 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5057.
  • Revision ID: mbp@sourcefrog.net-20100225061727-4sd9lt0qmdc6087t
merge news

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
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
23
23
"""
24
24
 
25
25
from stat import S_ISDIR
 
26
from StringIO import StringIO
 
27
import sys
26
28
 
27
29
import bzrlib
28
 
from bzrlib.errors import (
29
 
    UnknownFormatError,
30
 
    UnsupportedFormatError,
31
 
    )
 
30
from bzrlib.errors import (NotBranchError,
 
31
                           NoSuchFile,
 
32
                           UnknownFormatError,
 
33
                           UnsupportedFormatError,
 
34
                           )
32
35
from bzrlib import (
33
 
    btree_index,
34
36
    graph,
35
 
    symbol_versioning,
36
37
    tests,
37
 
    transport,
38
38
    )
 
39
from bzrlib.branchbuilder import BranchBuilder
39
40
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
40
 
from bzrlib.index import GraphIndex
 
41
from bzrlib.index import GraphIndex, InMemoryGraphIndex
41
42
from bzrlib.repository import RepositoryFormat
 
43
from bzrlib.smart import server
42
44
from bzrlib.tests import (
43
45
    TestCase,
44
46
    TestCaseWithTransport,
 
47
    TestSkipped,
 
48
    test_knit,
 
49
    )
 
50
from bzrlib.transport import (
 
51
    fakenfs,
 
52
    get_transport,
45
53
    )
46
54
from bzrlib import (
 
55
    bencode,
47
56
    bzrdir,
48
57
    errors,
49
58
    inventory,
50
59
    osutils,
 
60
    progress,
51
61
    repository,
52
62
    revision as _mod_revision,
 
63
    symbol_versioning,
53
64
    upgrade,
54
65
    versionedfile,
55
 
    vf_repository,
56
66
    workingtree,
57
67
    )
58
68
from bzrlib.repofmt import (
59
69
    groupcompress_repo,
60
70
    knitrepo,
61
 
    knitpack_repo,
62
71
    pack_repo,
 
72
    weaverepo,
63
73
    )
64
74
 
65
75
 
68
78
    def test_get_set_default_format(self):
69
79
        old_default = bzrdir.format_registry.get('default')
70
80
        private_default = old_default().repository_format.__class__
71
 
        old_format = repository.format_registry.get_default()
 
81
        old_format = repository.RepositoryFormat.get_default_format()
72
82
        self.assertTrue(isinstance(old_format, private_default))
73
83
        def make_sample_bzrdir():
74
84
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
88
98
            bzrdir.format_registry.remove('default')
89
99
            bzrdir.format_registry.remove('sample')
90
100
            bzrdir.format_registry.register('default', old_default, '')
91
 
        self.assertIsInstance(repository.format_registry.get_default(),
 
101
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
92
102
                              old_format.__class__)
93
103
 
94
104
 
116
126
        return "opened repository."
117
127
 
118
128
 
119
 
class SampleExtraRepositoryFormat(repository.RepositoryFormat):
120
 
    """A sample format that can not be used in a metadir
121
 
 
122
 
    """
123
 
 
124
 
    def get_format_string(self):
125
 
        raise NotImplementedError
126
 
 
127
 
 
128
129
class TestRepositoryFormat(TestCaseWithTransport):
129
130
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
130
131
 
136
137
        def check_format(format, url):
137
138
            dir = format._matchingbzrdir.initialize(url)
138
139
            format.initialize(dir)
139
 
            t = transport.get_transport_from_path(url)
 
140
            t = get_transport(url)
140
141
            found_format = repository.RepositoryFormat.find_format(dir)
141
 
            self.assertIsInstance(found_format, format.__class__)
142
 
        check_format(repository.format_registry.get_default(), "bar")
 
142
            self.failUnless(isinstance(found_format, format.__class__))
 
143
        check_format(weaverepo.RepositoryFormat7(), "bar")
143
144
 
144
145
    def test_find_format_no_repository(self):
145
146
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
155
156
                          dir)
156
157
 
157
158
    def test_register_unregister_format(self):
158
 
        # Test deprecated format registration functions
159
159
        format = SampleRepositoryFormat()
160
160
        # make a control dir
161
161
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
162
162
        # make a repo
163
163
        format.initialize(dir)
164
164
        # register a format for it.
165
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
166
 
            repository.RepositoryFormat.register_format, format)
 
165
        repository.RepositoryFormat.register_format(format)
167
166
        # which repository.Open will refuse (not supported)
168
 
        self.assertRaises(UnsupportedFormatError, repository.Repository.open,
169
 
            self.get_url())
 
167
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
170
168
        # but open(unsupported) will work
171
169
        self.assertEqual(format.open(dir), "opened repository.")
172
170
        # unregister the format
173
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
174
 
            repository.RepositoryFormat.unregister_format, format)
175
 
 
176
 
 
177
 
class TestRepositoryFormatRegistry(TestCase):
178
 
 
179
 
    def setUp(self):
180
 
        super(TestRepositoryFormatRegistry, self).setUp()
181
 
        self.registry = repository.RepositoryFormatRegistry()
182
 
 
183
 
    def test_register_unregister_format(self):
184
 
        format = SampleRepositoryFormat()
185
 
        self.registry.register(format)
186
 
        self.assertEquals(format, self.registry.get("Sample .bzr repository format."))
187
 
        self.registry.remove(format)
188
 
        self.assertRaises(KeyError, self.registry.get, "Sample .bzr repository format.")
189
 
 
190
 
    def test_get_all(self):
191
 
        format = SampleRepositoryFormat()
192
 
        self.assertEquals([], self.registry._get_all())
193
 
        self.registry.register(format)
194
 
        self.assertEquals([format], self.registry._get_all())
195
 
 
196
 
    def test_register_extra(self):
197
 
        format = SampleExtraRepositoryFormat()
198
 
        self.assertEquals([], self.registry._get_all())
199
 
        self.registry.register_extra(format)
200
 
        self.assertEquals([format], self.registry._get_all())
201
 
 
202
 
    def test_register_extra_lazy(self):
203
 
        self.assertEquals([], self.registry._get_all())
204
 
        self.registry.register_extra_lazy("bzrlib.tests.test_repository",
205
 
            "SampleExtraRepositoryFormat")
206
 
        formats = self.registry._get_all()
207
 
        self.assertEquals(1, len(formats))
208
 
        self.assertIsInstance(formats[0], SampleExtraRepositoryFormat)
 
171
        repository.RepositoryFormat.unregister_format(format)
 
172
 
 
173
 
 
174
class TestFormat6(TestCaseWithTransport):
 
175
 
 
176
    def test_attribute__fetch_order(self):
 
177
        """Weaves need topological data insertion."""
 
178
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
179
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
180
        self.assertEqual('topological', repo._format._fetch_order)
 
181
 
 
182
    def test_attribute__fetch_uses_deltas(self):
 
183
        """Weaves do not reuse deltas."""
 
184
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
185
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
186
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
187
 
 
188
    def test_attribute__fetch_reconcile(self):
 
189
        """Weave repositories need a reconcile after fetch."""
 
190
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
191
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
192
        self.assertEqual(True, repo._format._fetch_reconcile)
 
193
 
 
194
    def test_no_ancestry_weave(self):
 
195
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
196
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
197
        # We no longer need to create the ancestry.weave file
 
198
        # since it is *never* used.
 
199
        self.assertRaises(NoSuchFile,
 
200
                          control.transport.get,
 
201
                          'ancestry.weave')
 
202
 
 
203
    def test_supports_external_lookups(self):
 
204
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
205
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
206
        self.assertFalse(repo._format.supports_external_lookups)
 
207
 
 
208
 
 
209
class TestFormat7(TestCaseWithTransport):
 
210
 
 
211
    def test_attribute__fetch_order(self):
 
212
        """Weaves need topological data insertion."""
 
213
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
214
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
215
        self.assertEqual('topological', repo._format._fetch_order)
 
216
 
 
217
    def test_attribute__fetch_uses_deltas(self):
 
218
        """Weaves do not reuse deltas."""
 
219
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
220
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
221
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
222
 
 
223
    def test_attribute__fetch_reconcile(self):
 
224
        """Weave repositories need a reconcile after fetch."""
 
225
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
226
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
227
        self.assertEqual(True, repo._format._fetch_reconcile)
 
228
 
 
229
    def test_disk_layout(self):
 
230
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
231
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
232
        # in case of side effects of locking.
 
233
        repo.lock_write()
 
234
        repo.unlock()
 
235
        # we want:
 
236
        # format 'Bazaar-NG Repository format 7'
 
237
        # lock ''
 
238
        # inventory.weave == empty_weave
 
239
        # empty revision-store directory
 
240
        # empty weaves directory
 
241
        t = control.get_repository_transport(None)
 
242
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
243
                             t.get('format').read())
 
244
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
245
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
246
        self.assertEqualDiff('# bzr weave file v5\n'
 
247
                             'w\n'
 
248
                             'W\n',
 
249
                             t.get('inventory.weave').read())
 
250
        # Creating a file with id Foo:Bar results in a non-escaped file name on
 
251
        # disk.
 
252
        control.create_branch()
 
253
        tree = control.create_workingtree()
 
254
        tree.add(['foo'], ['Foo:Bar'], ['file'])
 
255
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
 
256
        try:
 
257
            tree.commit('first post', rev_id='first')
 
258
        except errors.IllegalPath:
 
259
            if sys.platform != 'win32':
 
260
                raise
 
261
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
 
262
                              ' in repo format 7')
 
263
            return
 
264
        self.assertEqualDiff(
 
265
            '# bzr weave file v5\n'
 
266
            'i\n'
 
267
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
 
268
            'n first\n'
 
269
            '\n'
 
270
            'w\n'
 
271
            '{ 0\n'
 
272
            '. content\n'
 
273
            '}\n'
 
274
            'W\n',
 
275
            t.get('weaves/74/Foo%3ABar.weave').read())
 
276
 
 
277
    def test_shared_disk_layout(self):
 
278
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
279
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
280
        # we want:
 
281
        # format 'Bazaar-NG Repository format 7'
 
282
        # inventory.weave == empty_weave
 
283
        # empty revision-store directory
 
284
        # empty weaves directory
 
285
        # a 'shared-storage' marker file.
 
286
        # lock is not present when unlocked
 
287
        t = control.get_repository_transport(None)
 
288
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
289
                             t.get('format').read())
 
290
        self.assertEqualDiff('', t.get('shared-storage').read())
 
291
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
292
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
293
        self.assertEqualDiff('# bzr weave file v5\n'
 
294
                             'w\n'
 
295
                             'W\n',
 
296
                             t.get('inventory.weave').read())
 
297
        self.assertFalse(t.has('branch-lock'))
 
298
 
 
299
    def test_creates_lockdir(self):
 
300
        """Make sure it appears to be controlled by a LockDir existence"""
 
301
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
302
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
303
        t = control.get_repository_transport(None)
 
304
        # TODO: Should check there is a 'lock' toplevel directory,
 
305
        # regardless of contents
 
306
        self.assertFalse(t.has('lock/held/info'))
 
307
        repo.lock_write()
 
308
        try:
 
309
            self.assertTrue(t.has('lock/held/info'))
 
310
        finally:
 
311
            # unlock so we don't get a warning about failing to do so
 
312
            repo.unlock()
 
313
 
 
314
    def test_uses_lockdir(self):
 
315
        """repo format 7 actually locks on lockdir"""
 
316
        base_url = self.get_url()
 
317
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
 
318
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
319
        t = control.get_repository_transport(None)
 
320
        repo.lock_write()
 
321
        repo.unlock()
 
322
        del repo
 
323
        # make sure the same lock is created by opening it
 
324
        repo = repository.Repository.open(base_url)
 
325
        repo.lock_write()
 
326
        self.assertTrue(t.has('lock/held/info'))
 
327
        repo.unlock()
 
328
        self.assertFalse(t.has('lock/held/info'))
 
329
 
 
330
    def test_shared_no_tree_disk_layout(self):
 
331
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
332
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
333
        repo.set_make_working_trees(False)
 
334
        # we want:
 
335
        # format 'Bazaar-NG Repository format 7'
 
336
        # lock ''
 
337
        # inventory.weave == empty_weave
 
338
        # empty revision-store directory
 
339
        # empty weaves directory
 
340
        # a 'shared-storage' marker file.
 
341
        t = control.get_repository_transport(None)
 
342
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
343
                             t.get('format').read())
 
344
        ## self.assertEqualDiff('', t.get('lock').read())
 
345
        self.assertEqualDiff('', t.get('shared-storage').read())
 
346
        self.assertEqualDiff('', t.get('no-working-trees').read())
 
347
        repo.set_make_working_trees(True)
 
348
        self.assertFalse(t.has('no-working-trees'))
 
349
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
350
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
351
        self.assertEqualDiff('# bzr weave file v5\n'
 
352
                             'w\n'
 
353
                             'W\n',
 
354
                             t.get('inventory.weave').read())
 
355
 
 
356
    def test_supports_external_lookups(self):
 
357
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
358
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
359
        self.assertFalse(repo._format.supports_external_lookups)
209
360
 
210
361
 
211
362
class TestFormatKnit1(TestCaseWithTransport):
379
530
        # classes do not barf inappropriately when a surprising repository type
380
531
        # is handed to them.
381
532
        dummy_a = DummyRepository()
382
 
        dummy_a._format = RepositoryFormat()
383
 
        dummy_a._format.supports_full_versioned_files = True
384
533
        dummy_b = DummyRepository()
385
 
        dummy_b._format = RepositoryFormat()
386
 
        dummy_b._format.supports_full_versioned_files = True
387
534
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
388
535
 
389
536
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
393
540
        no actual sane default in the presence of incompatible data models.
394
541
        """
395
542
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
396
 
        self.assertEqual(vf_repository.InterSameDataRepository,
 
543
        self.assertEqual(repository.InterSameDataRepository,
397
544
                         inter_repo.__class__)
398
545
        self.assertEqual(repo_a, inter_repo.source)
399
546
        self.assertEqual(repo_b, inter_repo.target)
413
560
        dummy_a._serializer = repo._serializer
414
561
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
415
562
        dummy_a._format.rich_root_data = repo._format.rich_root_data
416
 
        dummy_a._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
417
563
        dummy_b._serializer = repo._serializer
418
564
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
419
565
        dummy_b._format.rich_root_data = repo._format.rich_root_data
420
 
        dummy_b._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
421
566
        repository.InterRepository.register_optimiser(InterDummy)
422
567
        try:
423
568
            # we should get the default for something InterDummy returns False
436
581
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
437
582
 
438
583
 
439
 
class TestRepositoryFormat1(knitrepo.RepositoryFormatKnit1):
440
 
 
441
 
    def get_format_string(self):
442
 
        return "Test Format 1"
443
 
 
444
 
 
445
 
class TestRepositoryFormat2(knitrepo.RepositoryFormatKnit1):
446
 
 
447
 
    def get_format_string(self):
448
 
        return "Test Format 2"
 
584
class TestInterWeaveRepo(TestCaseWithTransport):
 
585
 
 
586
    def test_is_compatible_and_registered(self):
 
587
        # InterWeaveRepo is compatible when either side
 
588
        # is a format 5/6/7 branch
 
589
        from bzrlib.repofmt import knitrepo, weaverepo
 
590
        formats = [weaverepo.RepositoryFormat5(),
 
591
                   weaverepo.RepositoryFormat6(),
 
592
                   weaverepo.RepositoryFormat7()]
 
593
        incompatible_formats = [weaverepo.RepositoryFormat4(),
 
594
                                knitrepo.RepositoryFormatKnit1(),
 
595
                                ]
 
596
        repo_a = self.make_repository('a')
 
597
        repo_b = self.make_repository('b')
 
598
        is_compatible = repository.InterWeaveRepo.is_compatible
 
599
        for source in incompatible_formats:
 
600
            # force incompatible left then right
 
601
            repo_a._format = source
 
602
            repo_b._format = formats[0]
 
603
            self.assertFalse(is_compatible(repo_a, repo_b))
 
604
            self.assertFalse(is_compatible(repo_b, repo_a))
 
605
        for source in formats:
 
606
            repo_a._format = source
 
607
            for target in formats:
 
608
                repo_b._format = target
 
609
                self.assertTrue(is_compatible(repo_a, repo_b))
 
610
        self.assertEqual(repository.InterWeaveRepo,
 
611
                         repository.InterRepository.get(repo_a,
 
612
                                                        repo_b).__class__)
449
613
 
450
614
 
451
615
class TestRepositoryConverter(TestCaseWithTransport):
452
616
 
453
617
    def test_convert_empty(self):
454
 
        source_format = TestRepositoryFormat1()
455
 
        target_format = TestRepositoryFormat2()
456
 
        repository.format_registry.register(source_format)
457
 
        self.addCleanup(repository.format_registry.remove,
458
 
            source_format)
459
 
        repository.format_registry.register(target_format)
460
 
        self.addCleanup(repository.format_registry.remove,
461
 
            target_format)
462
 
        t = self.get_transport()
 
618
        t = get_transport(self.get_url('.'))
463
619
        t.mkdir('repository')
464
620
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
465
 
        repo = TestRepositoryFormat1().initialize(repo_dir)
 
621
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
 
622
        target_format = knitrepo.RepositoryFormatKnit1()
466
623
        converter = repository.CopyConverter(target_format)
467
624
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
468
625
        try:
473
630
        self.assertTrue(isinstance(target_format, repo._format.__class__))
474
631
 
475
632
 
 
633
class TestMisc(TestCase):
 
634
 
 
635
    def test_unescape_xml(self):
 
636
        """We get some kind of error when malformed entities are passed"""
 
637
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;')
 
638
 
 
639
 
476
640
class TestRepositoryFormatKnit3(TestCaseWithTransport):
477
641
 
478
642
    def test_attribute__fetch_order(self):
527
691
 
528
692
class Test2a(tests.TestCaseWithMemoryTransport):
529
693
 
530
 
    def test_chk_bytes_uses_custom_btree_parser(self):
531
 
        mt = self.make_branch_and_memory_tree('test', format='2a')
532
 
        mt.lock_write()
533
 
        self.addCleanup(mt.unlock)
534
 
        mt.add([''], ['root-id'])
535
 
        mt.commit('first')
536
 
        index = mt.branch.repository.chk_bytes._index._graph_index._indices[0]
537
 
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
538
 
        # It should also work if we re-open the repo
539
 
        repo = mt.branch.repository.bzrdir.open_repository()
540
 
        repo.lock_read()
541
 
        self.addCleanup(repo.unlock)
542
 
        index = repo.chk_bytes._index._graph_index._indices[0]
543
 
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
544
 
 
545
694
    def test_fetch_combines_groups(self):
546
695
        builder = self.make_branch_builder('source', format='2a')
547
696
        builder.start_series()
673
822
        target = self.make_repository('target', format='rich-root-pack')
674
823
        stream = source._get_source(target._format)
675
824
        # We don't want the child GroupCHKStreamSource
676
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
825
        self.assertIs(type(stream), repository.StreamSource)
677
826
 
678
827
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
679
828
        source_builder = self.make_branch_builder('source',
755
904
        source = self.make_repository('source', format='pack-0.92')
756
905
        target = self.make_repository('target', format='pack-0.92')
757
906
        stream_source = source._get_source(target._format)
758
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
907
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
759
908
 
760
909
    def test_source_to_exact_pack_rich_root_pack(self):
761
910
        source = self.make_repository('source', format='rich-root-pack')
762
911
        target = self.make_repository('target', format='rich-root-pack')
763
912
        stream_source = source._get_source(target._format)
764
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
913
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
765
914
 
766
915
    def test_source_to_exact_pack_19(self):
767
916
        source = self.make_repository('source', format='1.9')
768
917
        target = self.make_repository('target', format='1.9')
769
918
        stream_source = source._get_source(target._format)
770
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
919
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
771
920
 
772
921
    def test_source_to_exact_pack_19_rich_root(self):
773
922
        source = self.make_repository('source', format='1.9-rich-root')
774
923
        target = self.make_repository('target', format='1.9-rich-root')
775
924
        stream_source = source._get_source(target._format)
776
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
925
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
777
926
 
778
927
    def test_source_to_remote_exact_pack_19(self):
779
928
        trans = self.make_smart_server('target')
782
931
        target = self.make_repository('target', format='1.9')
783
932
        target = repository.Repository.open(trans.base)
784
933
        stream_source = source._get_source(target._format)
785
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
934
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
786
935
 
787
936
    def test_stream_source_to_non_exact(self):
788
937
        source = self.make_repository('source', format='pack-0.92')
789
938
        target = self.make_repository('target', format='1.9')
790
939
        stream = source._get_source(target._format)
791
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
940
        self.assertIs(type(stream), repository.StreamSource)
792
941
 
793
942
    def test_stream_source_to_non_exact_rich_root(self):
794
943
        source = self.make_repository('source', format='1.9')
795
944
        target = self.make_repository('target', format='1.9-rich-root')
796
945
        stream = source._get_source(target._format)
797
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
946
        self.assertIs(type(stream), repository.StreamSource)
798
947
 
799
948
    def test_source_to_remote_non_exact_pack_19(self):
800
949
        trans = self.make_smart_server('target')
803
952
        target = self.make_repository('target', format='1.6')
804
953
        target = repository.Repository.open(trans.base)
805
954
        stream_source = source._get_source(target._format)
806
 
        self.assertIs(type(stream_source), vf_repository.StreamSource)
 
955
        self.assertIs(type(stream_source), repository.StreamSource)
807
956
 
808
957
    def test_stream_source_to_knit(self):
809
958
        source = self.make_repository('source', format='pack-0.92')
810
959
        target = self.make_repository('target', format='dirstate')
811
960
        stream = source._get_source(target._format)
812
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
961
        self.assertIs(type(stream), repository.StreamSource)
813
962
 
814
963
 
815
964
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
817
966
 
818
967
    def setUp(self):
819
968
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
820
 
        self.builder = self.make_branch_builder('source')
 
969
        self.builder = self.make_branch_builder('source',
 
970
            format='development6-rich-root')
821
971
        self.builder.start_series()
822
972
        self.builder.build_snapshot('initial', None,
823
973
            [('add', ('', 'tree-root', 'directory', None))])
1451
1601
        # Because of how they were built, they correspond to
1452
1602
        # ['D', 'C', 'B', 'A']
1453
1603
        packs = b.repository._pack_collection.packs
1454
 
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
 
1604
        packer = pack_repo.Packer(b.repository._pack_collection,
1455
1605
                                  packs, 'testing',
1456
1606
                                  revision_ids=['B', 'C'])
1457
1607
        # Now, when we are copying the B & C revisions, their pack files should
1471
1621
        return repo._pack_collection
1472
1622
 
1473
1623
    def test_open_pack_will_optimise(self):
1474
 
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
 
1624
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1475
1625
                                            [], '.test')
1476
1626
        new_pack = packer.open_pack()
1477
1627
        self.addCleanup(new_pack.abort) # ensure cleanup
1482
1632
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1483
1633
 
1484
1634
 
1485
 
class TestGCCHKPacker(TestCaseWithTransport):
1486
 
 
1487
 
    def make_abc_branch(self):
1488
 
        builder = self.make_branch_builder('source')
1489
 
        builder.start_series()
1490
 
        builder.build_snapshot('A', None, [
1491
 
            ('add', ('', 'root-id', 'directory', None)),
1492
 
            ('add', ('file', 'file-id', 'file', 'content\n')),
1493
 
            ])
1494
 
        builder.build_snapshot('B', ['A'], [
1495
 
            ('add', ('dir', 'dir-id', 'directory', None))])
1496
 
        builder.build_snapshot('C', ['B'], [
1497
 
            ('modify', ('file-id', 'new content\n'))])
1498
 
        builder.finish_series()
1499
 
        return builder.get_branch()
1500
 
 
1501
 
    def make_branch_with_disjoint_inventory_and_revision(self):
1502
 
        """a repo with separate packs for a revisions Revision and Inventory.
1503
 
 
1504
 
        There will be one pack file that holds the Revision content, and one
1505
 
        for the Inventory content.
1506
 
 
1507
 
        :return: (repository,
1508
 
                  pack_name_with_rev_A_Revision,
1509
 
                  pack_name_with_rev_A_Inventory,
1510
 
                  pack_name_with_rev_C_content)
1511
 
        """
1512
 
        b_source = self.make_abc_branch()
1513
 
        b_base = b_source.bzrdir.sprout('base', revision_id='A').open_branch()
1514
 
        b_stacked = b_base.bzrdir.sprout('stacked', stacked=True).open_branch()
1515
 
        b_stacked.lock_write()
1516
 
        self.addCleanup(b_stacked.unlock)
1517
 
        b_stacked.fetch(b_source, 'B')
1518
 
        # Now re-open the stacked repo directly (no fallbacks) so that we can
1519
 
        # fill in the A rev.
1520
 
        repo_not_stacked = b_stacked.bzrdir.open_repository()
1521
 
        repo_not_stacked.lock_write()
1522
 
        self.addCleanup(repo_not_stacked.unlock)
1523
 
        # Now we should have a pack file with A's inventory, but not its
1524
 
        # Revision
1525
 
        self.assertEqual([('A',), ('B',)],
1526
 
                         sorted(repo_not_stacked.inventories.keys()))
1527
 
        self.assertEqual([('B',)],
1528
 
                         sorted(repo_not_stacked.revisions.keys()))
1529
 
        stacked_pack_names = repo_not_stacked._pack_collection.names()
1530
 
        # We have a couple names here, figure out which has A's inventory
1531
 
        for name in stacked_pack_names:
1532
 
            pack = repo_not_stacked._pack_collection.get_pack_by_name(name)
1533
 
            keys = [n[1] for n in pack.inventory_index.iter_all_entries()]
1534
 
            if ('A',) in keys:
1535
 
                inv_a_pack_name = name
1536
 
                break
1537
 
        else:
1538
 
            self.fail('Could not find pack containing A\'s inventory')
1539
 
        repo_not_stacked.fetch(b_source.repository, 'A')
1540
 
        self.assertEqual([('A',), ('B',)],
1541
 
                         sorted(repo_not_stacked.revisions.keys()))
1542
 
        new_pack_names = set(repo_not_stacked._pack_collection.names())
1543
 
        rev_a_pack_names = new_pack_names.difference(stacked_pack_names)
1544
 
        self.assertEqual(1, len(rev_a_pack_names))
1545
 
        rev_a_pack_name = list(rev_a_pack_names)[0]
1546
 
        # Now fetch 'C', so we have a couple pack files to join
1547
 
        repo_not_stacked.fetch(b_source.repository, 'C')
1548
 
        rev_c_pack_names = set(repo_not_stacked._pack_collection.names())
1549
 
        rev_c_pack_names = rev_c_pack_names.difference(new_pack_names)
1550
 
        self.assertEqual(1, len(rev_c_pack_names))
1551
 
        rev_c_pack_name = list(rev_c_pack_names)[0]
1552
 
        return (repo_not_stacked, rev_a_pack_name, inv_a_pack_name,
1553
 
                rev_c_pack_name)
1554
 
 
1555
 
    def test_pack_with_distant_inventories(self):
1556
 
        # See https://bugs.launchpad.net/bzr/+bug/437003
1557
 
        # When repacking, it is possible to have an inventory in a different
1558
 
        # pack file than the associated revision. An autopack can then come
1559
 
        # along, and miss that inventory, and complain.
1560
 
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
1561
 
         ) = self.make_branch_with_disjoint_inventory_and_revision()
1562
 
        a_pack = repo._pack_collection.get_pack_by_name(rev_a_pack_name)
1563
 
        c_pack = repo._pack_collection.get_pack_by_name(rev_c_pack_name)
1564
 
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
1565
 
                    [a_pack, c_pack], '.test-pack')
1566
 
        # This would raise ValueError in bug #437003, but should not raise an
1567
 
        # error once fixed.
1568
 
        packer.pack()
1569
 
 
1570
 
    def test_pack_with_missing_inventory(self):
1571
 
        # Similar to test_pack_with_missing_inventory, but this time, we force
1572
 
        # the A inventory to actually be gone from the repository.
1573
 
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
1574
 
         ) = self.make_branch_with_disjoint_inventory_and_revision()
1575
 
        inv_a_pack = repo._pack_collection.get_pack_by_name(inv_a_pack_name)
1576
 
        repo._pack_collection._remove_pack_from_memory(inv_a_pack)
1577
 
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
1578
 
            repo._pack_collection.all_packs(), '.test-pack')
1579
 
        e = self.assertRaises(ValueError, packer.pack)
1580
 
        packer.new_pack.abort()
1581
 
        self.assertContainsRe(str(e),
1582
 
            r"We are missing inventories for revisions: .*'A'")
1583
 
 
1584
 
 
1585
1635
class TestCrossFormatPacks(TestCaseWithTransport):
1586
1636
 
1587
1637
    def log_pack(self, hint=None):
1602
1652
        self.addCleanup(target.unlock)
1603
1653
        source = source_tree.branch.repository._get_source(target._format)
1604
1654
        self.orig_pack = target.pack
1605
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1655
        target.pack = self.log_pack
1606
1656
        search = target.search_missing_revision_ids(
1607
 
            source_tree.branch.repository, revision_ids=[tip])
 
1657
            source_tree.branch.repository, tip)
1608
1658
        stream = source.get_stream(search)
1609
1659
        from_format = source_tree.branch.repository._format
1610
1660
        sink = target._get_sink()
1626
1676
        self.addCleanup(target.unlock)
1627
1677
        source = source_tree.branch.repository
1628
1678
        self.orig_pack = target.pack
1629
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1679
        target.pack = self.log_pack
1630
1680
        target.fetch(source)
1631
1681
        if expect_pack_called:
1632
1682
            self.assertLength(1, self.calls)
1660
1710
    def test_IDS_format_same_no(self):
1661
1711
        # When the formats are the same, pack is not called.
1662
1712
        self.run_fetch('2a', '2a', False)
1663
 
 
1664
 
 
1665
 
class Test_LazyListJoin(tests.TestCase):
1666
 
 
1667
 
    def test__repr__(self):
1668
 
        lazy = repository._LazyListJoin(['a'], ['b'])
1669
 
        self.assertEqual("bzrlib.repository._LazyListJoin((['a'], ['b']))",
1670
 
                         repr(lazy))