~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: John Arbash Meinel
  • Date: 2007-07-05 19:39:28 UTC
  • mto: This revision was merged to the branch mainline in revision 2614.
  • Revision ID: john@arbash-meinel.com-20070705193928-xtm8nh4ucc8qosdn
Add direct tests of how we handle incomplete/'broken' lines

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
also see this file.
23
23
"""
24
24
 
25
 
import md5
26
25
from stat import S_ISDIR
27
26
from StringIO import StringIO
28
27
 
 
28
from bzrlib import symbol_versioning
29
29
import bzrlib
 
30
import bzrlib.bzrdir as bzrdir
 
31
import bzrlib.errors as errors
30
32
from bzrlib.errors import (NotBranchError,
31
33
                           NoSuchFile,
32
34
                           UnknownFormatError,
33
35
                           UnsupportedFormatError,
34
36
                           )
35
 
from bzrlib.index import GraphIndex, InMemoryGraphIndex
36
37
from bzrlib.repository import RepositoryFormat
37
 
from bzrlib.smart import server
38
 
from bzrlib.tests import (
39
 
    TestCase,
40
 
    TestCaseWithTransport,
41
 
    test_knit,
42
 
    )
 
38
from bzrlib.tests import TestCase, TestCaseWithTransport
43
39
from bzrlib.transport import get_transport
44
40
from bzrlib.transport.memory import MemoryServer
45
 
from bzrlib.util import bencode
46
41
from bzrlib import (
47
 
    bzrdir,
48
 
    errors,
49
 
    inventory,
50
 
    progress,
51
42
    repository,
52
 
    revision as _mod_revision,
53
 
    symbol_versioning,
54
43
    upgrade,
55
44
    workingtree,
56
45
    )
57
 
from bzrlib.repofmt import knitrepo, weaverepo, pack_repo
 
46
from bzrlib.repofmt import knitrepo, weaverepo
58
47
 
59
48
 
60
49
class TestDefaultFormat(TestCase):
166
155
                          control.transport.get,
167
156
                          'ancestry.weave')
168
157
 
169
 
    def test_exposed_versioned_files_are_marked_dirty(self):
170
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
171
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
172
 
        repo.lock_write()
173
 
        inv = repo.get_inventory_weave()
174
 
        repo.unlock()
175
 
        self.assertRaises(errors.OutSideTransaction,
176
 
            inv.add_lines, 'foo', [], [])
177
 
 
178
158
 
179
159
class TestFormat7(TestCaseWithTransport):
180
160
    
279
259
                             'W\n',
280
260
                             t.get('inventory.weave').read())
281
261
 
282
 
    def test_exposed_versioned_files_are_marked_dirty(self):
283
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
284
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
285
 
        repo.lock_write()
286
 
        inv = repo.get_inventory_weave()
287
 
        repo.unlock()
288
 
        self.assertRaises(errors.OutSideTransaction,
289
 
            inv.add_lines, 'foo', [], [])
290
 
 
291
262
 
292
263
class TestFormatKnit1(TestCaseWithTransport):
293
264
    
366
337
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
367
338
        self.check_knits(t)
368
339
 
369
 
    def test_exposed_versioned_files_are_marked_dirty(self):
370
 
        format = bzrdir.BzrDirMetaFormat1()
371
 
        format.repository_format = knitrepo.RepositoryFormatKnit1()
372
 
        repo = self.make_repository('.', format=format)
373
 
        repo.lock_write()
374
 
        inv = repo.get_inventory_weave()
375
 
        repo.unlock()
376
 
        self.assertRaises(errors.OutSideTransaction,
377
 
            inv.add_lines, 'foo', [], [])
378
 
 
379
 
    def test_deserialise_sets_root_revision(self):
380
 
        """We must have a inventory.root.revision
381
 
 
382
 
        Old versions of the XML5 serializer did not set the revision_id for
383
 
        the whole inventory. So we grab the one from the expected text. Which
384
 
        is valid when the api is not being abused.
385
 
        """
386
 
        repo = self.make_repository('.',
387
 
                format=bzrdir.format_registry.get('knit')())
388
 
        inv_xml = '<inventory format="5">\n</inventory>\n'
389
 
        inv = repo.deserialise_inventory('test-rev-id', inv_xml)
390
 
        self.assertEqual('test-rev-id', inv.root.revision)
391
 
 
392
 
    def test_deserialise_uses_global_revision_id(self):
393
 
        """If it is set, then we re-use the global revision id"""
394
 
        repo = self.make_repository('.',
395
 
                format=bzrdir.format_registry.get('knit')())
396
 
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
397
 
                   '</inventory>\n')
398
 
        # Arguably, the deserialise_inventory should detect a mismatch, and
399
 
        # raise an error, rather than silently using one revision_id over the
400
 
        # other.
401
 
        self.assertRaises(AssertionError, repo.deserialise_inventory,
402
 
            'test-rev-id', inv_xml)
403
 
        inv = repo.deserialise_inventory('other-rev-id', inv_xml)
404
 
        self.assertEqual('other-rev-id', inv.root.revision)
405
 
 
406
 
 
407
 
class KnitRepositoryStreamTests(test_knit.KnitTests):
408
 
    """Tests for knitrepo._get_stream_as_bytes."""
409
 
 
410
 
    def test_get_stream_as_bytes(self):
411
 
        # Make a simple knit
412
 
        k1 = self.make_test_knit()
413
 
        k1.add_lines('text-a', [], test_knit.split_lines(test_knit.TEXT_1))
414
 
        
415
 
        # Serialise it, check the output.
416
 
        bytes = knitrepo._get_stream_as_bytes(k1, ['text-a'])
417
 
        data = bencode.bdecode(bytes)
418
 
        format, record = data
419
 
        self.assertEqual('knit-plain', format)
420
 
        self.assertEqual(['text-a', ['fulltext'], []], record[:3])
421
 
        self.assertRecordContentEqual(k1, 'text-a', record[3])
422
 
 
423
 
    def test_get_stream_as_bytes_all(self):
424
 
        """Get a serialised data stream for all the records in a knit.
425
 
 
426
 
        Much like test_get_stream_all, except for get_stream_as_bytes.
427
 
        """
428
 
        k1 = self.make_test_knit()
429
 
        # Insert the same data as BasicKnitTests.test_knit_join, as they seem
430
 
        # to cover a range of cases (no parents, one parent, multiple parents).
431
 
        test_data = [
432
 
            ('text-a', [], test_knit.TEXT_1),
433
 
            ('text-b', ['text-a'], test_knit.TEXT_1),
434
 
            ('text-c', [], test_knit.TEXT_1),
435
 
            ('text-d', ['text-c'], test_knit.TEXT_1),
436
 
            ('text-m', ['text-b', 'text-d'], test_knit.TEXT_1),
437
 
           ]
438
 
        # This test is actually a bit strict as the order in which they're
439
 
        # returned is not defined.  This matches the current (deterministic)
440
 
        # behaviour.
441
 
        expected_data_list = [
442
 
            # version, options, parents
443
 
            ('text-a', ['fulltext'], []),
444
 
            ('text-b', ['line-delta'], ['text-a']),
445
 
            ('text-m', ['line-delta'], ['text-b', 'text-d']),
446
 
            ('text-c', ['fulltext'], []),
447
 
            ('text-d', ['line-delta'], ['text-c']),
448
 
            ]
449
 
        for version_id, parents, lines in test_data:
450
 
            k1.add_lines(version_id, parents, test_knit.split_lines(lines))
451
 
 
452
 
        bytes = knitrepo._get_stream_as_bytes(
453
 
            k1, ['text-a', 'text-b', 'text-m', 'text-c', 'text-d', ])
454
 
 
455
 
        data = bencode.bdecode(bytes)
456
 
        format = data.pop(0)
457
 
        self.assertEqual('knit-plain', format)
458
 
 
459
 
        for expected, actual in zip(expected_data_list, data):
460
 
            expected_version = expected[0]
461
 
            expected_options = expected[1]
462
 
            expected_parents = expected[2]
463
 
            version, options, parents, bytes = actual
464
 
            self.assertEqual(expected_version, version)
465
 
            self.assertEqual(expected_options, options)
466
 
            self.assertEqual(expected_parents, parents)
467
 
            self.assertRecordContentEqual(k1, version, bytes)
468
 
 
469
340
 
470
341
class DummyRepository(object):
471
342
    """A dummy repository for testing."""
481
352
 
482
353
    This is for use during testing where we use DummyRepository as repositories
483
354
    so that none of the default regsitered inter-repository classes will
484
 
    MATCH.
 
355
    match.
485
356
    """
486
357
 
487
358
    @staticmethod
577
448
                                                        repo_b).__class__)
578
449
 
579
450
 
580
 
class TestInterRemoteToOther(TestCaseWithTransport):
581
 
 
582
 
    def make_remote_repository(self, path, backing_format=None):
583
 
        """Make a RemoteRepository object backed by a real repository that will
584
 
        be created at the given path."""
585
 
        self.make_repository(path, format=backing_format)
586
 
        smart_server = server.SmartTCPServer_for_testing()
587
 
        smart_server.setUp()
588
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
589
 
        self.addCleanup(smart_server.tearDown)
590
 
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
591
 
        remote_repo = remote_bzrdir.open_repository()
592
 
        return remote_repo
593
 
 
594
 
    def test_is_compatible_same_format(self):
595
 
        """InterRemoteToOther is compatible with a remote repository and a
596
 
        second repository that have the same format."""
597
 
        local_repo = self.make_repository('local')
598
 
        remote_repo = self.make_remote_repository('remote')
599
 
        is_compatible = repository.InterRemoteToOther.is_compatible
600
 
        self.assertTrue(
601
 
            is_compatible(remote_repo, local_repo),
602
 
            "InterRemoteToOther(%r, %r) is false" % (remote_repo, local_repo))
603
 
          
604
 
    def test_is_incompatible_different_format(self):
605
 
        local_repo = self.make_repository('local', 'dirstate')
606
 
        remote_repo = self.make_remote_repository('a', 'dirstate-with-subtree')
607
 
        is_compatible = repository.InterRemoteToOther.is_compatible
608
 
        self.assertFalse(
609
 
            is_compatible(remote_repo, local_repo),
610
 
            "InterRemoteToOther(%r, %r) is true" % (local_repo, remote_repo))
611
 
 
612
 
    def test_is_incompatible_different_format_both_remote(self):
613
 
        remote_repo_a = self.make_remote_repository(
614
 
            'a', 'dirstate-with-subtree')
615
 
        remote_repo_b = self.make_remote_repository('b', 'dirstate')
616
 
        is_compatible = repository.InterRemoteToOther.is_compatible
617
 
        self.assertFalse(
618
 
            is_compatible(remote_repo_a, remote_repo_b),
619
 
            "InterRemoteToOther(%r, %r) is true"
620
 
            % (remote_repo_a, remote_repo_b))
621
 
 
622
 
 
623
451
class TestRepositoryConverter(TestCaseWithTransport):
624
452
 
625
453
    def test_convert_empty(self):
666
494
        revision_tree = tree.branch.repository.revision_tree('dull2')
667
495
        self.assertEqual('dull', revision_tree.inventory.root.revision)
668
496
 
669
 
    def test_exposed_versioned_files_are_marked_dirty(self):
670
 
        format = bzrdir.BzrDirMetaFormat1()
671
 
        format.repository_format = knitrepo.RepositoryFormatKnit3()
672
 
        repo = self.make_repository('.', format=format)
673
 
        repo.lock_write()
674
 
        inv = repo.get_inventory_weave()
675
 
        repo.unlock()
676
 
        self.assertRaises(errors.OutSideTransaction,
677
 
            inv.add_lines, 'foo', [], [])
678
 
 
679
 
 
680
 
class TestWithBrokenRepo(TestCaseWithTransport):
681
 
    """These tests seem to be more appropriate as interface tests?"""
682
 
 
683
 
    def make_broken_repository(self):
684
 
        # XXX: This function is borrowed from Aaron's "Reconcile can fix bad
685
 
        # parent references" branch which is due to land in bzr.dev soon.  Once
686
 
        # it does, this duplication should be removed.
687
 
        repo = self.make_repository('broken-repo')
688
 
        cleanups = []
689
 
        try:
690
 
            repo.lock_write()
691
 
            cleanups.append(repo.unlock)
692
 
            repo.start_write_group()
693
 
            cleanups.append(repo.commit_write_group)
694
 
            # make rev1a: A well-formed revision, containing 'file1'
695
 
            inv = inventory.Inventory(revision_id='rev1a')
696
 
            inv.root.revision = 'rev1a'
697
 
            self.add_file(repo, inv, 'file1', 'rev1a', [])
698
 
            repo.add_inventory('rev1a', inv, [])
699
 
            revision = _mod_revision.Revision('rev1a',
700
 
                committer='jrandom@example.com', timestamp=0,
701
 
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
702
 
            repo.add_revision('rev1a',revision, inv)
703
 
 
704
 
            # make rev1b, which has no Revision, but has an Inventory, and
705
 
            # file1
706
 
            inv = inventory.Inventory(revision_id='rev1b')
707
 
            inv.root.revision = 'rev1b'
708
 
            self.add_file(repo, inv, 'file1', 'rev1b', [])
709
 
            repo.add_inventory('rev1b', inv, [])
710
 
 
711
 
            # make rev2, with file1 and file2
712
 
            # file2 is sane
713
 
            # file1 has 'rev1b' as an ancestor, even though this is not
714
 
            # mentioned by 'rev1a', making it an unreferenced ancestor
715
 
            inv = inventory.Inventory()
716
 
            self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b'])
717
 
            self.add_file(repo, inv, 'file2', 'rev2', [])
718
 
            self.add_revision(repo, 'rev2', inv, ['rev1a'])
719
 
 
720
 
            # make ghost revision rev1c
721
 
            inv = inventory.Inventory()
722
 
            self.add_file(repo, inv, 'file2', 'rev1c', [])
723
 
 
724
 
            # make rev3 with file2
725
 
            # file2 refers to 'rev1c', which is a ghost in this repository, so
726
 
            # file2 cannot have rev1c as its ancestor.
727
 
            inv = inventory.Inventory()
728
 
            self.add_file(repo, inv, 'file2', 'rev3', ['rev1c'])
729
 
            self.add_revision(repo, 'rev3', inv, ['rev1c'])
730
 
            return repo
731
 
        finally:
732
 
            for cleanup in reversed(cleanups):
733
 
                cleanup()
734
 
 
735
 
    def add_revision(self, repo, revision_id, inv, parent_ids):
736
 
        inv.revision_id = revision_id
737
 
        inv.root.revision = revision_id
738
 
        repo.add_inventory(revision_id, inv, parent_ids)
739
 
        revision = _mod_revision.Revision(revision_id,
740
 
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
741
 
            timezone=0, message='foo', parent_ids=parent_ids)
742
 
        repo.add_revision(revision_id,revision, inv)
743
 
 
744
 
    def add_file(self, repo, inv, filename, revision, parents):
745
 
        file_id = filename + '-id'
746
 
        entry = inventory.InventoryFile(file_id, filename, 'TREE_ROOT')
747
 
        entry.revision = revision
748
 
        entry.text_size = 0
749
 
        inv.add(entry)
750
 
        vf = repo.weave_store.get_weave_or_empty(file_id,
751
 
                                                 repo.get_transaction())
752
 
        vf.add_lines(revision, parents, ['line\n'])
753
 
 
754
 
    def test_insert_from_broken_repo(self):
755
 
        """Inserting a data stream from a broken repository won't silently
756
 
        corrupt the target repository.
757
 
        """
758
 
        broken_repo = self.make_broken_repository()
759
 
        empty_repo = self.make_repository('empty-repo')
760
 
        stream = broken_repo.get_data_stream(['rev1a', 'rev2', 'rev3'])
761
 
        empty_repo.lock_write()
762
 
        self.addCleanup(empty_repo.unlock)
763
 
        empty_repo.start_write_group()
764
 
        try:
765
 
            self.assertRaises(
766
 
                errors.KnitCorrupt, empty_repo.insert_data_stream, stream)
767
 
        finally:
768
 
            empty_repo.abort_write_group()
769
 
 
770
 
 
771
 
class TestKnitPackNoSubtrees(TestCaseWithTransport):
772
 
 
773
 
    def get_format(self):
774
 
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
775
 
 
776
 
    def test_disk_layout(self):
777
 
        format = self.get_format()
778
 
        repo = self.make_repository('.', format=format)
779
 
        # in case of side effects of locking.
780
 
        repo.lock_write()
781
 
        repo.unlock()
782
 
        t = repo.bzrdir.get_repository_transport(None)
783
 
        self.check_format(t)
784
 
        # XXX: no locks left when unlocked at the moment
785
 
        # self.assertEqualDiff('', t.get('lock').read())
786
 
        self.check_databases(t)
787
 
 
788
 
    def check_format(self, t):
789
 
        self.assertEqualDiff(
790
 
            "Bazaar pack repository format 1 (needs bzr 0.92)\n",
791
 
                             t.get('format').read())
792
 
 
793
 
    def assertHasKndx(self, t, knit_name):
794
 
        """Assert that knit_name exists on t."""
795
 
        self.assertEqualDiff('# bzr knit index 8\n',
796
 
                             t.get(knit_name + '.kndx').read())
797
 
 
798
 
    def assertHasNoKndx(self, t, knit_name):
799
 
        """Assert that knit_name has no index on t."""
800
 
        self.assertFalse(t.has(knit_name + '.kndx'))
801
 
 
802
 
    def assertHasNoKnit(self, t, knit_name):
803
 
        """Assert that knit_name exists on t."""
804
 
        # no default content
805
 
        self.assertFalse(t.has(knit_name + '.knit'))
806
 
 
807
 
    def check_databases(self, t):
808
 
        """check knit content for a repository."""
809
 
        # check conversion worked
810
 
        self.assertHasNoKndx(t, 'inventory')
811
 
        self.assertHasNoKnit(t, 'inventory')
812
 
        self.assertHasNoKndx(t, 'revisions')
813
 
        self.assertHasNoKnit(t, 'revisions')
814
 
        self.assertHasNoKndx(t, 'signatures')
815
 
        self.assertHasNoKnit(t, 'signatures')
816
 
        self.assertFalse(t.has('knits'))
817
 
        # revision-indexes file-container directory
818
 
        self.assertEqual([],
819
 
            list(GraphIndex(t, 'pack-names', None).iter_all_entries()))
820
 
        self.assertTrue(S_ISDIR(t.stat('packs').st_mode))
821
 
        self.assertTrue(S_ISDIR(t.stat('upload').st_mode))
822
 
        self.assertTrue(S_ISDIR(t.stat('indices').st_mode))
823
 
        self.assertTrue(S_ISDIR(t.stat('obsolete_packs').st_mode))
824
 
 
825
 
    def test_shared_disk_layout(self):
826
 
        format = self.get_format()
827
 
        repo = self.make_repository('.', shared=True, format=format)
828
 
        # we want:
829
 
        t = repo.bzrdir.get_repository_transport(None)
830
 
        self.check_format(t)
831
 
        # XXX: no locks left when unlocked at the moment
832
 
        # self.assertEqualDiff('', t.get('lock').read())
833
 
        # We should have a 'shared-storage' marker file.
834
 
        self.assertEqualDiff('', t.get('shared-storage').read())
835
 
        self.check_databases(t)
836
 
 
837
 
    def test_shared_no_tree_disk_layout(self):
838
 
        format = self.get_format()
839
 
        repo = self.make_repository('.', shared=True, format=format)
840
 
        repo.set_make_working_trees(False)
841
 
        # we want:
842
 
        t = repo.bzrdir.get_repository_transport(None)
843
 
        self.check_format(t)
844
 
        # XXX: no locks left when unlocked at the moment
845
 
        # self.assertEqualDiff('', t.get('lock').read())
846
 
        # We should have a 'shared-storage' marker file.
847
 
        self.assertEqualDiff('', t.get('shared-storage').read())
848
 
        # We should have a marker for the no-working-trees flag.
849
 
        self.assertEqualDiff('', t.get('no-working-trees').read())
850
 
        # The marker should go when we toggle the setting.
851
 
        repo.set_make_working_trees(True)
852
 
        self.assertFalse(t.has('no-working-trees'))
853
 
        self.check_databases(t)
854
 
 
855
 
    def test_adding_revision_creates_pack_indices(self):
856
 
        format = self.get_format()
857
 
        tree = self.make_branch_and_tree('.', format=format)
858
 
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
859
 
        self.assertEqual([],
860
 
            list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
861
 
        tree.commit('foobarbaz')
862
 
        index = GraphIndex(trans, 'pack-names', None)
863
 
        index_nodes = list(index.iter_all_entries())
864
 
        self.assertEqual(1, len(index_nodes))
865
 
        node = index_nodes[0]
866
 
        name = node[1][0]
867
 
        # the pack sizes should be listed in the index
868
 
        pack_value = node[2]
869
 
        sizes = [int(digits) for digits in pack_value.split(' ')]
870
 
        for size, suffix in zip(sizes, ['.rix', '.iix', '.tix', '.six']):
871
 
            stat = trans.stat('indices/%s%s' % (name, suffix))
872
 
            self.assertEqual(size, stat.st_size)
873
 
 
874
 
    def test_pulling_nothing_leads_to_no_new_names(self):
875
 
        format = self.get_format()
876
 
        tree1 = self.make_branch_and_tree('1', format=format)
877
 
        tree2 = self.make_branch_and_tree('2', format=format)
878
 
        tree1.branch.repository.fetch(tree2.branch.repository)
879
 
        trans = tree1.branch.repository.bzrdir.get_repository_transport(None)
880
 
        self.assertEqual([],
881
 
            list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
882
 
 
883
 
    def test_commit_across_pack_shape_boundary_autopacks(self):
884
 
        format = self.get_format()
885
 
        tree = self.make_branch_and_tree('.', format=format)
886
 
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
887
 
        # This test could be a little cheaper by replacing the packs
888
 
        # attribute on the repository to allow a different pack distribution
889
 
        # and max packs policy - so we are checking the policy is honoured
890
 
        # in the test. But for now 11 commits is not a big deal in a single
891
 
        # test.
892
 
        for x in range(9):
893
 
            tree.commit('commit %s' % x)
894
 
        # there should be 9 packs:
895
 
        index = GraphIndex(trans, 'pack-names', None)
896
 
        self.assertEqual(9, len(list(index.iter_all_entries())))
897
 
        # insert some files in obsolete_packs which should be removed by pack.
898
 
        trans.put_bytes('obsolete_packs/foo', '123')
899
 
        trans.put_bytes('obsolete_packs/bar', '321')
900
 
        # committing one more should coalesce to 1 of 10.
901
 
        tree.commit('commit triggering pack')
902
 
        index = GraphIndex(trans, 'pack-names', None)
903
 
        self.assertEqual(1, len(list(index.iter_all_entries())))
904
 
        # packing should not damage data
905
 
        tree = tree.bzrdir.open_workingtree()
906
 
        check_result = tree.branch.repository.check(
907
 
            [tree.branch.last_revision()])
908
 
        # We should have 50 (10x5) files in the obsolete_packs directory.
909
 
        obsolete_files = list(trans.list_dir('obsolete_packs'))
910
 
        self.assertFalse('foo' in obsolete_files)
911
 
        self.assertFalse('bar' in obsolete_files)
912
 
        self.assertEqual(50, len(obsolete_files))
913
 
        # XXX: Todo check packs obsoleted correctly - old packs and indices
914
 
        # in the obsolete_packs directory.
915
 
        large_pack_name = list(index.iter_all_entries())[0][1][0]
916
 
        # finally, committing again should not touch the large pack.
917
 
        tree.commit('commit not triggering pack')
918
 
        index = GraphIndex(trans, 'pack-names', None)
919
 
        self.assertEqual(2, len(list(index.iter_all_entries())))
920
 
        pack_names = [node[1][0] for node in index.iter_all_entries()]
921
 
        self.assertTrue(large_pack_name in pack_names)
922
 
 
923
 
    def test_pack_after_two_commits_packs_everything(self):
924
 
        format = self.get_format()
925
 
        tree = self.make_branch_and_tree('.', format=format)
926
 
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
927
 
        tree.commit('start')
928
 
        tree.commit('more work')
929
 
        tree.branch.repository.pack()
930
 
        # there should be 1 pack:
931
 
        index = GraphIndex(trans, 'pack-names', None)
932
 
        self.assertEqual(1, len(list(index.iter_all_entries())))
933
 
        self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
934
 
 
935
 
    def test_pack_layout(self):
936
 
        format = self.get_format()
937
 
        tree = self.make_branch_and_tree('.', format=format)
938
 
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
939
 
        tree.commit('start', rev_id='1')
940
 
        tree.commit('more work', rev_id='2')
941
 
        tree.branch.repository.pack()
942
 
        tree.lock_read()
943
 
        self.addCleanup(tree.unlock)
944
 
        pack = tree.branch.repository._pack_collection.get_pack_by_name(
945
 
            tree.branch.repository._pack_collection.names()[0])
946
 
        # revision access tends to be tip->ancestor, so ordering that way on 
947
 
        # disk is a good idea.
948
 
        for _1, key, val, refs in pack.revision_index.iter_all_entries():
949
 
            if key == ('1',):
950
 
                pos_1 = int(val[1:].split()[0])
951
 
            else:
952
 
                pos_2 = int(val[1:].split()[0])
953
 
        self.assertTrue(pos_2 < pos_1)
954
 
 
955
 
    def test_pack_repositories_support_multiple_write_locks(self):
956
 
        format = self.get_format()
957
 
        self.make_repository('.', shared=True, format=format)
958
 
        r1 = repository.Repository.open('.')
959
 
        r2 = repository.Repository.open('.')
960
 
        r1.lock_write()
961
 
        self.addCleanup(r1.unlock)
962
 
        r2.lock_write()
963
 
        r2.unlock()
964
 
 
965
 
    def _add_text(self, repo, fileid):
966
 
        """Add a text to the repository within a write group."""
967
 
        vf =repo.weave_store.get_weave(fileid, repo.get_transaction())
968
 
        vf.add_lines('samplerev+' + fileid, [], [])
969
 
 
970
 
    def test_concurrent_writers_merge_new_packs(self):
971
 
        format = self.get_format()
972
 
        self.make_repository('.', shared=True, format=format)
973
 
        r1 = repository.Repository.open('.')
974
 
        r2 = repository.Repository.open('.')
975
 
        r1.lock_write()
976
 
        try:
977
 
            # access enough data to load the names list
978
 
            list(r1.all_revision_ids())
979
 
            r2.lock_write()
980
 
            try:
981
 
                # access enough data to load the names list
982
 
                list(r2.all_revision_ids())
983
 
                r1.start_write_group()
984
 
                try:
985
 
                    r2.start_write_group()
986
 
                    try:
987
 
                        self._add_text(r1, 'fileidr1')
988
 
                        self._add_text(r2, 'fileidr2')
989
 
                    except:
990
 
                        r2.abort_write_group()
991
 
                        raise
992
 
                except:
993
 
                    r1.abort_write_group()
994
 
                    raise
995
 
                # both r1 and r2 have open write groups with data in them
996
 
                # created while the other's write group was open.
997
 
                # Commit both which requires a merge to the pack-names.
998
 
                try:
999
 
                    r1.commit_write_group()
1000
 
                except:
1001
 
                    r1.abort_write_group()
1002
 
                    r2.abort_write_group()
1003
 
                    raise
1004
 
                r2.commit_write_group()
1005
 
                # tell r1 to reload from disk
1006
 
                r1._pack_collection.reset()
1007
 
                # Now both repositories should know about both names
1008
 
                r1._pack_collection.ensure_loaded()
1009
 
                r2._pack_collection.ensure_loaded()
1010
 
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1011
 
                self.assertEqual(2, len(r1._pack_collection.names()))
1012
 
            finally:
1013
 
                r2.unlock()
1014
 
        finally:
1015
 
            r1.unlock()
1016
 
 
1017
 
    def test_concurrent_writer_second_preserves_dropping_a_pack(self):
1018
 
        format = self.get_format()
1019
 
        self.make_repository('.', shared=True, format=format)
1020
 
        r1 = repository.Repository.open('.')
1021
 
        r2 = repository.Repository.open('.')
1022
 
        # add a pack to drop
1023
 
        r1.lock_write()
1024
 
        try:
1025
 
            r1.start_write_group()
1026
 
            try:
1027
 
                self._add_text(r1, 'fileidr1')
1028
 
            except:
1029
 
                r1.abort_write_group()
1030
 
                raise
1031
 
            else:
1032
 
                r1.commit_write_group()
1033
 
            r1._pack_collection.ensure_loaded()
1034
 
            name_to_drop = r1._pack_collection.all_packs()[0].name
1035
 
        finally:
1036
 
            r1.unlock()
1037
 
        r1.lock_write()
1038
 
        try:
1039
 
            # access enough data to load the names list
1040
 
            list(r1.all_revision_ids())
1041
 
            r2.lock_write()
1042
 
            try:
1043
 
                # access enough data to load the names list
1044
 
                list(r2.all_revision_ids())
1045
 
                r1._pack_collection.ensure_loaded()
1046
 
                try:
1047
 
                    r2.start_write_group()
1048
 
                    try:
1049
 
                        # in r1, drop the pack
1050
 
                        r1._pack_collection._remove_pack_from_memory(
1051
 
                            r1._pack_collection.get_pack_by_name(name_to_drop))
1052
 
                        # in r2, add a pack
1053
 
                        self._add_text(r2, 'fileidr2')
1054
 
                    except:
1055
 
                        r2.abort_write_group()
1056
 
                        raise
1057
 
                except:
1058
 
                    r1._pack_collection.reset()
1059
 
                    raise
1060
 
                # r1 has a changed names list, and r2 an open write groups with
1061
 
                # changes.
1062
 
                # save r1, and then commit the r2 write group, which requires a
1063
 
                # merge to the pack-names, which should not reinstate
1064
 
                # name_to_drop
1065
 
                try:
1066
 
                    r1._pack_collection._save_pack_names()
1067
 
                    r1._pack_collection.reset()
1068
 
                except:
1069
 
                    r2.abort_write_group()
1070
 
                    raise
1071
 
                try:
1072
 
                    r2.commit_write_group()
1073
 
                except:
1074
 
                    r2.abort_write_group()
1075
 
                    raise
1076
 
                # Now both repositories should now about just one name.
1077
 
                r1._pack_collection.ensure_loaded()
1078
 
                r2._pack_collection.ensure_loaded()
1079
 
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1080
 
                self.assertEqual(1, len(r1._pack_collection.names()))
1081
 
                self.assertFalse(name_to_drop in r1._pack_collection.names())
1082
 
            finally:
1083
 
                r2.unlock()
1084
 
        finally:
1085
 
            r1.unlock()
1086
 
 
1087
 
    def test_lock_write_does_not_physically_lock(self):
1088
 
        repo = self.make_repository('.', format=self.get_format())
1089
 
        repo.lock_write()
1090
 
        self.addCleanup(repo.unlock)
1091
 
        self.assertFalse(repo.get_physical_lock_status())
1092
 
 
1093
 
    def prepare_for_break_lock(self):
1094
 
        # Setup the global ui factory state so that a break-lock method call
1095
 
        # will find usable input in the input stream.
1096
 
        old_factory = bzrlib.ui.ui_factory
1097
 
        def restoreFactory():
1098
 
            bzrlib.ui.ui_factory = old_factory
1099
 
        self.addCleanup(restoreFactory)
1100
 
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1101
 
        bzrlib.ui.ui_factory.stdin = StringIO("y\n")
1102
 
 
1103
 
    def test_break_lock_breaks_physical_lock(self):
1104
 
        repo = self.make_repository('.', format=self.get_format())
1105
 
        repo._pack_collection.lock_names()
1106
 
        repo2 = repository.Repository.open('.')
1107
 
        self.assertTrue(repo.get_physical_lock_status())
1108
 
        self.prepare_for_break_lock()
1109
 
        repo2.break_lock()
1110
 
        self.assertFalse(repo.get_physical_lock_status())
1111
 
 
1112
 
    def test_broken_physical_locks_error_on__unlock_names_lock(self):
1113
 
        repo = self.make_repository('.', format=self.get_format())
1114
 
        repo._pack_collection.lock_names()
1115
 
        self.assertTrue(repo.get_physical_lock_status())
1116
 
        repo2 = repository.Repository.open('.')
1117
 
        self.prepare_for_break_lock()
1118
 
        repo2.break_lock()
1119
 
        self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
1120
 
 
1121
 
    def test_fetch_without_find_ghosts_ignores_ghosts(self):
1122
 
        # we want two repositories at this point:
1123
 
        # one with a revision that is a ghost in the other
1124
 
        # repository.
1125
 
        # 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
1126
 
        # 'references' is present in both repositories, and 'tip' is present
1127
 
        # just in has_ghost.
1128
 
        # has_ghost       missing_ghost
1129
 
        #------------------------------
1130
 
        # 'ghost'             -
1131
 
        # 'references'    'references'
1132
 
        # 'tip'               -
1133
 
        # In this test we fetch 'tip' which should not fetch 'ghost'
1134
 
        has_ghost = self.make_repository('has_ghost', format=self.get_format())
1135
 
        missing_ghost = self.make_repository('missing_ghost',
1136
 
            format=self.get_format())
1137
 
 
1138
 
        def add_commit(repo, revision_id, parent_ids):
1139
 
            repo.lock_write()
1140
 
            repo.start_write_group()
1141
 
            inv = inventory.Inventory(revision_id=revision_id)
1142
 
            inv.root.revision = revision_id
1143
 
            root_id = inv.root.file_id
1144
 
            sha1 = repo.add_inventory(revision_id, inv, [])
1145
 
            vf = repo.weave_store.get_weave_or_empty(root_id,
1146
 
                repo.get_transaction())
1147
 
            vf.add_lines(revision_id, [], [])
1148
 
            rev = bzrlib.revision.Revision(timestamp=0,
1149
 
                                           timezone=None,
1150
 
                                           committer="Foo Bar <foo@example.com>",
1151
 
                                           message="Message",
1152
 
                                           inventory_sha1=sha1,
1153
 
                                           revision_id=revision_id)
1154
 
            rev.parent_ids = parent_ids
1155
 
            repo.add_revision(revision_id, rev)
1156
 
            repo.commit_write_group()
1157
 
            repo.unlock()
1158
 
        add_commit(has_ghost, 'ghost', [])
1159
 
        add_commit(has_ghost, 'references', ['ghost'])
1160
 
        add_commit(missing_ghost, 'references', ['ghost'])
1161
 
        add_commit(has_ghost, 'tip', ['references'])
1162
 
        missing_ghost.fetch(has_ghost, 'tip')
1163
 
        # missing ghost now has tip and not ghost.
1164
 
        rev = missing_ghost.get_revision('tip')
1165
 
        inv = missing_ghost.get_inventory('tip')
1166
 
        self.assertRaises(errors.NoSuchRevision,
1167
 
            missing_ghost.get_revision, 'ghost')
1168
 
        self.assertRaises(errors.RevisionNotPresent,
1169
 
            missing_ghost.get_inventory, 'ghost')
1170
 
 
1171
 
 
1172
 
class TestKnitPackSubtrees(TestKnitPackNoSubtrees):
1173
 
 
1174
 
    def get_format(self):
1175
 
        return bzrdir.format_registry.make_bzrdir(
1176
 
            'pack-0.92-subtree')
1177
 
 
1178
 
    def check_format(self, t):
1179
 
        self.assertEqualDiff(
1180
 
            "Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n",
1181
 
            t.get('format').read())
1182
 
 
1183
 
 
1184
 
class TestRepositoryPackCollection(TestCaseWithTransport):
1185
 
 
1186
 
    def get_format(self):
1187
 
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
1188
 
 
1189
 
    def test__max_pack_count(self):
1190
 
        """The maximum pack count is a function of the number of revisions."""
1191
 
        format = self.get_format()
1192
 
        repo = self.make_repository('.', format=format)
1193
 
        packs = repo._pack_collection
1194
 
        # no revisions - one pack, so that we can have a revision free repo
1195
 
        # without it blowing up
1196
 
        self.assertEqual(1, packs._max_pack_count(0))
1197
 
        # after that the sum of the digits, - check the first 1-9
1198
 
        self.assertEqual(1, packs._max_pack_count(1))
1199
 
        self.assertEqual(2, packs._max_pack_count(2))
1200
 
        self.assertEqual(3, packs._max_pack_count(3))
1201
 
        self.assertEqual(4, packs._max_pack_count(4))
1202
 
        self.assertEqual(5, packs._max_pack_count(5))
1203
 
        self.assertEqual(6, packs._max_pack_count(6))
1204
 
        self.assertEqual(7, packs._max_pack_count(7))
1205
 
        self.assertEqual(8, packs._max_pack_count(8))
1206
 
        self.assertEqual(9, packs._max_pack_count(9))
1207
 
        # check the boundary cases with two digits for the next decade
1208
 
        self.assertEqual(1, packs._max_pack_count(10))
1209
 
        self.assertEqual(2, packs._max_pack_count(11))
1210
 
        self.assertEqual(10, packs._max_pack_count(19))
1211
 
        self.assertEqual(2, packs._max_pack_count(20))
1212
 
        self.assertEqual(3, packs._max_pack_count(21))
1213
 
        # check some arbitrary big numbers
1214
 
        self.assertEqual(25, packs._max_pack_count(112894))
1215
 
 
1216
 
    def test_pack_distribution_zero(self):
1217
 
        format = self.get_format()
1218
 
        repo = self.make_repository('.', format=format)
1219
 
        packs = repo._pack_collection
1220
 
        self.assertEqual([0], packs.pack_distribution(0))
1221
 
 
1222
 
    def test_ensure_loaded_unlocked(self):
1223
 
        format = self.get_format()
1224
 
        repo = self.make_repository('.', format=format)
1225
 
        self.assertRaises(errors.ObjectNotLocked,
1226
 
                          repo._pack_collection.ensure_loaded)
1227
 
 
1228
 
    def test_pack_distribution_one_to_nine(self):
1229
 
        format = self.get_format()
1230
 
        repo = self.make_repository('.', format=format)
1231
 
        packs = repo._pack_collection
1232
 
        self.assertEqual([1],
1233
 
            packs.pack_distribution(1))
1234
 
        self.assertEqual([1, 1],
1235
 
            packs.pack_distribution(2))
1236
 
        self.assertEqual([1, 1, 1],
1237
 
            packs.pack_distribution(3))
1238
 
        self.assertEqual([1, 1, 1, 1],
1239
 
            packs.pack_distribution(4))
1240
 
        self.assertEqual([1, 1, 1, 1, 1],
1241
 
            packs.pack_distribution(5))
1242
 
        self.assertEqual([1, 1, 1, 1, 1, 1],
1243
 
            packs.pack_distribution(6))
1244
 
        self.assertEqual([1, 1, 1, 1, 1, 1, 1],
1245
 
            packs.pack_distribution(7))
1246
 
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1],
1247
 
            packs.pack_distribution(8))
1248
 
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1, 1],
1249
 
            packs.pack_distribution(9))
1250
 
 
1251
 
    def test_pack_distribution_stable_at_boundaries(self):
1252
 
        """When there are multi-rev packs the counts are stable."""
1253
 
        format = self.get_format()
1254
 
        repo = self.make_repository('.', format=format)
1255
 
        packs = repo._pack_collection
1256
 
        # in 10s:
1257
 
        self.assertEqual([10], packs.pack_distribution(10))
1258
 
        self.assertEqual([10, 1], packs.pack_distribution(11))
1259
 
        self.assertEqual([10, 10], packs.pack_distribution(20))
1260
 
        self.assertEqual([10, 10, 1], packs.pack_distribution(21))
1261
 
        # 100s
1262
 
        self.assertEqual([100], packs.pack_distribution(100))
1263
 
        self.assertEqual([100, 1], packs.pack_distribution(101))
1264
 
        self.assertEqual([100, 10, 1], packs.pack_distribution(111))
1265
 
        self.assertEqual([100, 100], packs.pack_distribution(200))
1266
 
        self.assertEqual([100, 100, 1], packs.pack_distribution(201))
1267
 
        self.assertEqual([100, 100, 10, 1], packs.pack_distribution(211))
1268
 
 
1269
 
    def test_plan_pack_operations_2009_revisions_skip_all_packs(self):
1270
 
        format = self.get_format()
1271
 
        repo = self.make_repository('.', format=format)
1272
 
        packs = repo._pack_collection
1273
 
        existing_packs = [(2000, "big"), (9, "medium")]
1274
 
        # rev count - 2009 -> 2x1000 + 9x1
1275
 
        pack_operations = packs.plan_autopack_combinations(
1276
 
            existing_packs, [1000, 1000, 1, 1, 1, 1, 1, 1, 1, 1, 1])
1277
 
        self.assertEqual([], pack_operations)
1278
 
 
1279
 
    def test_plan_pack_operations_2010_revisions_skip_all_packs(self):
1280
 
        format = self.get_format()
1281
 
        repo = self.make_repository('.', format=format)
1282
 
        packs = repo._pack_collection
1283
 
        existing_packs = [(2000, "big"), (9, "medium"), (1, "single")]
1284
 
        # rev count - 2010 -> 2x1000 + 1x10
1285
 
        pack_operations = packs.plan_autopack_combinations(
1286
 
            existing_packs, [1000, 1000, 10])
1287
 
        self.assertEqual([], pack_operations)
1288
 
 
1289
 
    def test_plan_pack_operations_2010_combines_smallest_two(self):
1290
 
        format = self.get_format()
1291
 
        repo = self.make_repository('.', format=format)
1292
 
        packs = repo._pack_collection
1293
 
        existing_packs = [(1999, "big"), (9, "medium"), (1, "single2"),
1294
 
            (1, "single1")]
1295
 
        # rev count - 2010 -> 2x1000 + 1x10 (3)
1296
 
        pack_operations = packs.plan_autopack_combinations(
1297
 
            existing_packs, [1000, 1000, 10])
1298
 
        self.assertEqual([[2, ["single2", "single1"]], [0, []]], pack_operations)
1299
 
 
1300
 
    def test_all_packs_none(self):
1301
 
        format = self.get_format()
1302
 
        tree = self.make_branch_and_tree('.', format=format)
1303
 
        tree.lock_read()
1304
 
        self.addCleanup(tree.unlock)
1305
 
        packs = tree.branch.repository._pack_collection
1306
 
        packs.ensure_loaded()
1307
 
        self.assertEqual([], packs.all_packs())
1308
 
 
1309
 
    def test_all_packs_one(self):
1310
 
        format = self.get_format()
1311
 
        tree = self.make_branch_and_tree('.', format=format)
1312
 
        tree.commit('start')
1313
 
        tree.lock_read()
1314
 
        self.addCleanup(tree.unlock)
1315
 
        packs = tree.branch.repository._pack_collection
1316
 
        packs.ensure_loaded()
1317
 
        self.assertEqual([
1318
 
            packs.get_pack_by_name(packs.names()[0])],
1319
 
            packs.all_packs())
1320
 
 
1321
 
    def test_all_packs_two(self):
1322
 
        format = self.get_format()
1323
 
        tree = self.make_branch_and_tree('.', format=format)
1324
 
        tree.commit('start')
1325
 
        tree.commit('continue')
1326
 
        tree.lock_read()
1327
 
        self.addCleanup(tree.unlock)
1328
 
        packs = tree.branch.repository._pack_collection
1329
 
        packs.ensure_loaded()
1330
 
        self.assertEqual([
1331
 
            packs.get_pack_by_name(packs.names()[0]),
1332
 
            packs.get_pack_by_name(packs.names()[1]),
1333
 
            ], packs.all_packs())
1334
 
 
1335
 
    def test_get_pack_by_name(self):
1336
 
        format = self.get_format()
1337
 
        tree = self.make_branch_and_tree('.', format=format)
1338
 
        tree.commit('start')
1339
 
        tree.lock_read()
1340
 
        self.addCleanup(tree.unlock)
1341
 
        packs = tree.branch.repository._pack_collection
1342
 
        packs.ensure_loaded()
1343
 
        name = packs.names()[0]
1344
 
        pack_1 = packs.get_pack_by_name(name)
1345
 
        # the pack should be correctly initialised
1346
 
        rev_index = GraphIndex(packs._index_transport, name + '.rix',
1347
 
            packs._names[name][0])
1348
 
        inv_index = GraphIndex(packs._index_transport, name + '.iix',
1349
 
            packs._names[name][1])
1350
 
        txt_index = GraphIndex(packs._index_transport, name + '.tix',
1351
 
            packs._names[name][2])
1352
 
        sig_index = GraphIndex(packs._index_transport, name + '.six',
1353
 
            packs._names[name][3])
1354
 
        self.assertEqual(pack_repo.ExistingPack(packs._pack_transport,
1355
 
            name, rev_index, inv_index, txt_index, sig_index), pack_1)
1356
 
        # and the same instance should be returned on successive calls.
1357
 
        self.assertTrue(pack_1 is packs.get_pack_by_name(name))
1358
 
 
1359
 
 
1360
 
class TestPack(TestCaseWithTransport):
1361
 
    """Tests for the Pack object."""
1362
 
 
1363
 
    def assertCurrentlyEqual(self, left, right):
1364
 
        self.assertTrue(left == right)
1365
 
        self.assertTrue(right == left)
1366
 
        self.assertFalse(left != right)
1367
 
        self.assertFalse(right != left)
1368
 
 
1369
 
    def assertCurrentlyNotEqual(self, left, right):
1370
 
        self.assertFalse(left == right)
1371
 
        self.assertFalse(right == left)
1372
 
        self.assertTrue(left != right)
1373
 
        self.assertTrue(right != left)
1374
 
 
1375
 
    def test___eq____ne__(self):
1376
 
        left = pack_repo.ExistingPack('', '', '', '', '', '')
1377
 
        right = pack_repo.ExistingPack('', '', '', '', '', '')
1378
 
        self.assertCurrentlyEqual(left, right)
1379
 
        # change all attributes and ensure equality changes as we do.
1380
 
        left.revision_index = 'a'
1381
 
        self.assertCurrentlyNotEqual(left, right)
1382
 
        right.revision_index = 'a'
1383
 
        self.assertCurrentlyEqual(left, right)
1384
 
        left.inventory_index = 'a'
1385
 
        self.assertCurrentlyNotEqual(left, right)
1386
 
        right.inventory_index = 'a'
1387
 
        self.assertCurrentlyEqual(left, right)
1388
 
        left.text_index = 'a'
1389
 
        self.assertCurrentlyNotEqual(left, right)
1390
 
        right.text_index = 'a'
1391
 
        self.assertCurrentlyEqual(left, right)
1392
 
        left.signature_index = 'a'
1393
 
        self.assertCurrentlyNotEqual(left, right)
1394
 
        right.signature_index = 'a'
1395
 
        self.assertCurrentlyEqual(left, right)
1396
 
        left.name = 'a'
1397
 
        self.assertCurrentlyNotEqual(left, right)
1398
 
        right.name = 'a'
1399
 
        self.assertCurrentlyEqual(left, right)
1400
 
        left.transport = 'a'
1401
 
        self.assertCurrentlyNotEqual(left, right)
1402
 
        right.transport = 'a'
1403
 
        self.assertCurrentlyEqual(left, right)
1404
 
 
1405
 
    def test_file_name(self):
1406
 
        pack = pack_repo.ExistingPack('', 'a_name', '', '', '', '')
1407
 
        self.assertEqual('a_name.pack', pack.file_name())
1408
 
 
1409
 
 
1410
 
class TestNewPack(TestCaseWithTransport):
1411
 
    """Tests for pack_repo.NewPack."""
1412
 
 
1413
 
    def test_new_instance_attributes(self):
1414
 
        upload_transport = self.get_transport('upload')
1415
 
        pack_transport = self.get_transport('pack')
1416
 
        index_transport = self.get_transport('index')
1417
 
        upload_transport.mkdir('.')
1418
 
        pack = pack_repo.NewPack(upload_transport, index_transport,
1419
 
            pack_transport)
1420
 
        self.assertIsInstance(pack.revision_index, InMemoryGraphIndex)
1421
 
        self.assertIsInstance(pack.inventory_index, InMemoryGraphIndex)
1422
 
        self.assertIsInstance(pack._hash, type(md5.new()))
1423
 
        self.assertTrue(pack.upload_transport is upload_transport)
1424
 
        self.assertTrue(pack.index_transport is index_transport)
1425
 
        self.assertTrue(pack.pack_transport is pack_transport)
1426
 
        self.assertEqual(None, pack.index_sizes)
1427
 
        self.assertEqual(20, len(pack.random_name))
1428
 
        self.assertIsInstance(pack.random_name, str)
1429
 
        self.assertIsInstance(pack.start_time, float)
1430
 
 
1431
 
 
1432
 
class TestPacker(TestCaseWithTransport):
1433
 
    """Tests for the packs repository Packer class."""
1434
 
 
1435
 
    # To date, this class has been factored out and nothing new added to it;
1436
 
    # thus there are not yet any tests.
1437
 
 
1438
 
 
1439
 
class TestInterDifferingSerializer(TestCaseWithTransport):
1440
 
 
1441
 
    def test_progress_bar(self):
1442
 
        tree = self.make_branch_and_tree('tree')
1443
 
        tree.commit('rev1', rev_id='rev-1')
1444
 
        tree.commit('rev2', rev_id='rev-2')
1445
 
        tree.commit('rev3', rev_id='rev-3')
1446
 
        repo = self.make_repository('repo')
1447
 
        inter_repo = repository.InterDifferingSerializer(
1448
 
            tree.branch.repository, repo)
1449
 
        pb = progress.InstrumentedProgress(to_file=StringIO())
1450
 
        pb.never_throttle = True
1451
 
        inter_repo.fetch('rev-1', pb)
1452
 
        self.assertEqual('Transferring revisions', pb.last_msg)
1453
 
        self.assertEqual(1, pb.last_cnt)
1454
 
        self.assertEqual(1, pb.last_total)
1455
 
        inter_repo.fetch('rev-3', pb)
1456
 
        self.assertEqual(2, pb.last_cnt)
1457
 
        self.assertEqual(2, pb.last_total)