~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

(gz) Fix test failure on alpha by correcting format string for
 gc_chk_sha1_record (Martin [gz])

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
import sys
26
27
 
27
28
import bzrlib
28
29
from bzrlib.errors import (
 
30
    NoSuchFile,
29
31
    UnknownFormatError,
30
32
    UnsupportedFormatError,
31
33
    )
52
54
    revision as _mod_revision,
53
55
    upgrade,
54
56
    versionedfile,
55
 
    vf_repository,
56
57
    workingtree,
57
58
    )
58
59
from bzrlib.repofmt import (
59
60
    groupcompress_repo,
60
61
    knitrepo,
61
 
    knitpack_repo,
62
62
    pack_repo,
 
63
    weaverepo,
63
64
    )
64
65
 
65
66
 
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 = transport.get_transport(url)
140
141
            found_format = repository.RepositoryFormat.find_format(dir)
141
 
            self.assertIsInstance(found_format, format.__class__)
 
142
            self.failUnless(isinstance(found_format, format.__class__))
142
143
        check_format(repository.format_registry.get_default(), "bar")
143
144
 
144
145
    def test_find_format_no_repository(self):
208
209
        self.assertIsInstance(formats[0], SampleExtraRepositoryFormat)
209
210
 
210
211
 
 
212
class TestFormat6(TestCaseWithTransport):
 
213
 
 
214
    def test_attribute__fetch_order(self):
 
215
        """Weaves need topological data insertion."""
 
216
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
217
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
218
        self.assertEqual('topological', repo._format._fetch_order)
 
219
 
 
220
    def test_attribute__fetch_uses_deltas(self):
 
221
        """Weaves do not reuse deltas."""
 
222
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
223
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
224
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
225
 
 
226
    def test_attribute__fetch_reconcile(self):
 
227
        """Weave repositories need a reconcile after fetch."""
 
228
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
229
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
230
        self.assertEqual(True, repo._format._fetch_reconcile)
 
231
 
 
232
    def test_no_ancestry_weave(self):
 
233
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
234
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
235
        # We no longer need to create the ancestry.weave file
 
236
        # since it is *never* used.
 
237
        self.assertRaises(NoSuchFile,
 
238
                          control.transport.get,
 
239
                          'ancestry.weave')
 
240
 
 
241
    def test_supports_external_lookups(self):
 
242
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
243
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
244
        self.assertFalse(repo._format.supports_external_lookups)
 
245
 
 
246
 
 
247
class TestFormat7(TestCaseWithTransport):
 
248
 
 
249
    def test_attribute__fetch_order(self):
 
250
        """Weaves need topological data insertion."""
 
251
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
252
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
253
        self.assertEqual('topological', repo._format._fetch_order)
 
254
 
 
255
    def test_attribute__fetch_uses_deltas(self):
 
256
        """Weaves do not reuse deltas."""
 
257
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
258
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
259
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
260
 
 
261
    def test_attribute__fetch_reconcile(self):
 
262
        """Weave repositories need a reconcile after fetch."""
 
263
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
264
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
265
        self.assertEqual(True, repo._format._fetch_reconcile)
 
266
 
 
267
    def test_disk_layout(self):
 
268
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
269
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
270
        # in case of side effects of locking.
 
271
        repo.lock_write()
 
272
        repo.unlock()
 
273
        # we want:
 
274
        # format 'Bazaar-NG Repository format 7'
 
275
        # lock ''
 
276
        # inventory.weave == empty_weave
 
277
        # empty revision-store directory
 
278
        # empty weaves directory
 
279
        t = control.get_repository_transport(None)
 
280
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
281
                             t.get('format').read())
 
282
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
283
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
284
        self.assertEqualDiff('# bzr weave file v5\n'
 
285
                             'w\n'
 
286
                             'W\n',
 
287
                             t.get('inventory.weave').read())
 
288
        # Creating a file with id Foo:Bar results in a non-escaped file name on
 
289
        # disk.
 
290
        control.create_branch()
 
291
        tree = control.create_workingtree()
 
292
        tree.add(['foo'], ['Foo:Bar'], ['file'])
 
293
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
 
294
        try:
 
295
            tree.commit('first post', rev_id='first')
 
296
        except errors.IllegalPath:
 
297
            if sys.platform != 'win32':
 
298
                raise
 
299
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
 
300
                              ' in repo format 7')
 
301
            return
 
302
        self.assertEqualDiff(
 
303
            '# bzr weave file v5\n'
 
304
            'i\n'
 
305
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
 
306
            'n first\n'
 
307
            '\n'
 
308
            'w\n'
 
309
            '{ 0\n'
 
310
            '. content\n'
 
311
            '}\n'
 
312
            'W\n',
 
313
            t.get('weaves/74/Foo%3ABar.weave').read())
 
314
 
 
315
    def test_shared_disk_layout(self):
 
316
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
317
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
318
        # we want:
 
319
        # format 'Bazaar-NG Repository format 7'
 
320
        # inventory.weave == empty_weave
 
321
        # empty revision-store directory
 
322
        # empty weaves directory
 
323
        # a 'shared-storage' marker file.
 
324
        # lock is not present when unlocked
 
325
        t = control.get_repository_transport(None)
 
326
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
327
                             t.get('format').read())
 
328
        self.assertEqualDiff('', t.get('shared-storage').read())
 
329
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
330
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
331
        self.assertEqualDiff('# bzr weave file v5\n'
 
332
                             'w\n'
 
333
                             'W\n',
 
334
                             t.get('inventory.weave').read())
 
335
        self.assertFalse(t.has('branch-lock'))
 
336
 
 
337
    def test_creates_lockdir(self):
 
338
        """Make sure it appears to be controlled by a LockDir existence"""
 
339
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
340
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
341
        t = control.get_repository_transport(None)
 
342
        # TODO: Should check there is a 'lock' toplevel directory,
 
343
        # regardless of contents
 
344
        self.assertFalse(t.has('lock/held/info'))
 
345
        repo.lock_write()
 
346
        try:
 
347
            self.assertTrue(t.has('lock/held/info'))
 
348
        finally:
 
349
            # unlock so we don't get a warning about failing to do so
 
350
            repo.unlock()
 
351
 
 
352
    def test_uses_lockdir(self):
 
353
        """repo format 7 actually locks on lockdir"""
 
354
        base_url = self.get_url()
 
355
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
 
356
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
357
        t = control.get_repository_transport(None)
 
358
        repo.lock_write()
 
359
        repo.unlock()
 
360
        del repo
 
361
        # make sure the same lock is created by opening it
 
362
        repo = repository.Repository.open(base_url)
 
363
        repo.lock_write()
 
364
        self.assertTrue(t.has('lock/held/info'))
 
365
        repo.unlock()
 
366
        self.assertFalse(t.has('lock/held/info'))
 
367
 
 
368
    def test_shared_no_tree_disk_layout(self):
 
369
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
370
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
371
        repo.set_make_working_trees(False)
 
372
        # we want:
 
373
        # format 'Bazaar-NG Repository format 7'
 
374
        # lock ''
 
375
        # inventory.weave == empty_weave
 
376
        # empty revision-store directory
 
377
        # empty weaves directory
 
378
        # a 'shared-storage' marker file.
 
379
        t = control.get_repository_transport(None)
 
380
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
381
                             t.get('format').read())
 
382
        ## self.assertEqualDiff('', t.get('lock').read())
 
383
        self.assertEqualDiff('', t.get('shared-storage').read())
 
384
        self.assertEqualDiff('', t.get('no-working-trees').read())
 
385
        repo.set_make_working_trees(True)
 
386
        self.assertFalse(t.has('no-working-trees'))
 
387
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
388
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
389
        self.assertEqualDiff('# bzr weave file v5\n'
 
390
                             'w\n'
 
391
                             'W\n',
 
392
                             t.get('inventory.weave').read())
 
393
 
 
394
    def test_supports_external_lookups(self):
 
395
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
396
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
397
        self.assertFalse(repo._format.supports_external_lookups)
 
398
 
 
399
 
211
400
class TestFormatKnit1(TestCaseWithTransport):
212
401
 
213
402
    def test_attribute__fetch_order(self):
379
568
        # classes do not barf inappropriately when a surprising repository type
380
569
        # is handed to them.
381
570
        dummy_a = DummyRepository()
382
 
        dummy_a._format = RepositoryFormat()
383
 
        dummy_a._format.supports_full_versioned_files = True
384
571
        dummy_b = DummyRepository()
385
 
        dummy_b._format = RepositoryFormat()
386
 
        dummy_b._format.supports_full_versioned_files = True
387
572
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
388
573
 
389
574
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
393
578
        no actual sane default in the presence of incompatible data models.
394
579
        """
395
580
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
396
 
        self.assertEqual(vf_repository.InterSameDataRepository,
 
581
        self.assertEqual(repository.InterSameDataRepository,
397
582
                         inter_repo.__class__)
398
583
        self.assertEqual(repo_a, inter_repo.source)
399
584
        self.assertEqual(repo_b, inter_repo.target)
413
598
        dummy_a._serializer = repo._serializer
414
599
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
415
600
        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
601
        dummy_b._serializer = repo._serializer
418
602
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
419
603
        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
604
        repository.InterRepository.register_optimiser(InterDummy)
422
605
        try:
423
606
            # we should get the default for something InterDummy returns False
436
619
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
437
620
 
438
621
 
 
622
class TestInterWeaveRepo(TestCaseWithTransport):
 
623
 
 
624
    def test_is_compatible_and_registered(self):
 
625
        # InterWeaveRepo is compatible when either side
 
626
        # is a format 5/6/7 branch
 
627
        from bzrlib.repofmt import knitrepo, weaverepo
 
628
        formats = [weaverepo.RepositoryFormat5(),
 
629
                   weaverepo.RepositoryFormat6(),
 
630
                   weaverepo.RepositoryFormat7()]
 
631
        incompatible_formats = [weaverepo.RepositoryFormat4(),
 
632
                                knitrepo.RepositoryFormatKnit1(),
 
633
                                ]
 
634
        repo_a = self.make_repository('a')
 
635
        repo_b = self.make_repository('b')
 
636
        is_compatible = weaverepo.InterWeaveRepo.is_compatible
 
637
        for source in incompatible_formats:
 
638
            # force incompatible left then right
 
639
            repo_a._format = source
 
640
            repo_b._format = formats[0]
 
641
            self.assertFalse(is_compatible(repo_a, repo_b))
 
642
            self.assertFalse(is_compatible(repo_b, repo_a))
 
643
        for source in formats:
 
644
            repo_a._format = source
 
645
            for target in formats:
 
646
                repo_b._format = target
 
647
                self.assertTrue(is_compatible(repo_a, repo_b))
 
648
        self.assertEqual(weaverepo.InterWeaveRepo,
 
649
                         repository.InterRepository.get(repo_a,
 
650
                                                        repo_b).__class__)
 
651
 
 
652
 
439
653
class TestRepositoryFormat1(knitrepo.RepositoryFormatKnit1):
440
654
 
441
655
    def get_format_string(self):
673
887
        target = self.make_repository('target', format='rich-root-pack')
674
888
        stream = source._get_source(target._format)
675
889
        # We don't want the child GroupCHKStreamSource
676
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
890
        self.assertIs(type(stream), repository.StreamSource)
677
891
 
678
892
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
679
893
        source_builder = self.make_branch_builder('source',
755
969
        source = self.make_repository('source', format='pack-0.92')
756
970
        target = self.make_repository('target', format='pack-0.92')
757
971
        stream_source = source._get_source(target._format)
758
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
972
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
759
973
 
760
974
    def test_source_to_exact_pack_rich_root_pack(self):
761
975
        source = self.make_repository('source', format='rich-root-pack')
762
976
        target = self.make_repository('target', format='rich-root-pack')
763
977
        stream_source = source._get_source(target._format)
764
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
978
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
765
979
 
766
980
    def test_source_to_exact_pack_19(self):
767
981
        source = self.make_repository('source', format='1.9')
768
982
        target = self.make_repository('target', format='1.9')
769
983
        stream_source = source._get_source(target._format)
770
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
984
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
771
985
 
772
986
    def test_source_to_exact_pack_19_rich_root(self):
773
987
        source = self.make_repository('source', format='1.9-rich-root')
774
988
        target = self.make_repository('target', format='1.9-rich-root')
775
989
        stream_source = source._get_source(target._format)
776
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
990
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
777
991
 
778
992
    def test_source_to_remote_exact_pack_19(self):
779
993
        trans = self.make_smart_server('target')
782
996
        target = self.make_repository('target', format='1.9')
783
997
        target = repository.Repository.open(trans.base)
784
998
        stream_source = source._get_source(target._format)
785
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
999
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
786
1000
 
787
1001
    def test_stream_source_to_non_exact(self):
788
1002
        source = self.make_repository('source', format='pack-0.92')
789
1003
        target = self.make_repository('target', format='1.9')
790
1004
        stream = source._get_source(target._format)
791
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
1005
        self.assertIs(type(stream), repository.StreamSource)
792
1006
 
793
1007
    def test_stream_source_to_non_exact_rich_root(self):
794
1008
        source = self.make_repository('source', format='1.9')
795
1009
        target = self.make_repository('target', format='1.9-rich-root')
796
1010
        stream = source._get_source(target._format)
797
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
1011
        self.assertIs(type(stream), repository.StreamSource)
798
1012
 
799
1013
    def test_source_to_remote_non_exact_pack_19(self):
800
1014
        trans = self.make_smart_server('target')
803
1017
        target = self.make_repository('target', format='1.6')
804
1018
        target = repository.Repository.open(trans.base)
805
1019
        stream_source = source._get_source(target._format)
806
 
        self.assertIs(type(stream_source), vf_repository.StreamSource)
 
1020
        self.assertIs(type(stream_source), repository.StreamSource)
807
1021
 
808
1022
    def test_stream_source_to_knit(self):
809
1023
        source = self.make_repository('source', format='pack-0.92')
810
1024
        target = self.make_repository('target', format='dirstate')
811
1025
        stream = source._get_source(target._format)
812
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
1026
        self.assertIs(type(stream), repository.StreamSource)
813
1027
 
814
1028
 
815
1029
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
1451
1665
        # Because of how they were built, they correspond to
1452
1666
        # ['D', 'C', 'B', 'A']
1453
1667
        packs = b.repository._pack_collection.packs
1454
 
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
 
1668
        packer = pack_repo.Packer(b.repository._pack_collection,
1455
1669
                                  packs, 'testing',
1456
1670
                                  revision_ids=['B', 'C'])
1457
1671
        # Now, when we are copying the B & C revisions, their pack files should
1471
1685
        return repo._pack_collection
1472
1686
 
1473
1687
    def test_open_pack_will_optimise(self):
1474
 
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
 
1688
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1475
1689
                                            [], '.test')
1476
1690
        new_pack = packer.open_pack()
1477
1691
        self.addCleanup(new_pack.abort) # ensure cleanup
1482
1696
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1483
1697
 
1484
1698
 
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
1699
class TestCrossFormatPacks(TestCaseWithTransport):
1586
1700
 
1587
1701
    def log_pack(self, hint=None):
1602
1716
        self.addCleanup(target.unlock)
1603
1717
        source = source_tree.branch.repository._get_source(target._format)
1604
1718
        self.orig_pack = target.pack
1605
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1719
        target.pack = self.log_pack
1606
1720
        search = target.search_missing_revision_ids(
1607
1721
            source_tree.branch.repository, revision_ids=[tip])
1608
1722
        stream = source.get_stream(search)
1626
1740
        self.addCleanup(target.unlock)
1627
1741
        source = source_tree.branch.repository
1628
1742
        self.orig_pack = target.pack
1629
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1743
        target.pack = self.log_pack
1630
1744
        target.fetch(source)
1631
1745
        if expect_pack_called:
1632
1746
            self.assertLength(1, self.calls)
1660
1774
    def test_IDS_format_same_no(self):
1661
1775
        # When the formats are the same, pack is not called.
1662
1776
        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))