681
459
tree.commit("Another dull commit", rev_id='dull2')
682
460
revision_tree = tree.branch.repository.revision_tree('dull2')
683
461
self.assertEqual('dull', revision_tree.inventory.root.revision)
685
def test_exposed_versioned_files_are_marked_dirty(self):
686
format = bzrdir.BzrDirMetaFormat1()
687
format.repository_format = knitrepo.RepositoryFormatKnit3()
688
repo = self.make_repository('.', format=format)
690
inv = repo.get_inventory_weave()
692
self.assertRaises(errors.OutSideTransaction,
693
inv.add_lines, 'foo', [], [])
695
def test_supports_external_lookups(self):
696
format = bzrdir.BzrDirMetaFormat1()
697
format.repository_format = knitrepo.RepositoryFormatKnit3()
698
repo = self.make_repository('.', format=format)
699
self.assertFalse(repo._format.supports_external_lookups)
702
class TestWithBrokenRepo(TestCaseWithTransport):
703
"""These tests seem to be more appropriate as interface tests?"""
705
def make_broken_repository(self):
706
# XXX: This function is borrowed from Aaron's "Reconcile can fix bad
707
# parent references" branch which is due to land in bzr.dev soon. Once
708
# it does, this duplication should be removed.
709
repo = self.make_repository('broken-repo')
713
cleanups.append(repo.unlock)
714
repo.start_write_group()
715
cleanups.append(repo.commit_write_group)
716
# make rev1a: A well-formed revision, containing 'file1'
717
inv = inventory.Inventory(revision_id='rev1a')
718
inv.root.revision = 'rev1a'
719
self.add_file(repo, inv, 'file1', 'rev1a', [])
720
repo.add_inventory('rev1a', inv, [])
721
revision = _mod_revision.Revision('rev1a',
722
committer='jrandom@example.com', timestamp=0,
723
inventory_sha1='', timezone=0, message='foo', parent_ids=[])
724
repo.add_revision('rev1a',revision, inv)
726
# make rev1b, which has no Revision, but has an Inventory, and
728
inv = inventory.Inventory(revision_id='rev1b')
729
inv.root.revision = 'rev1b'
730
self.add_file(repo, inv, 'file1', 'rev1b', [])
731
repo.add_inventory('rev1b', inv, [])
733
# make rev2, with file1 and file2
735
# file1 has 'rev1b' as an ancestor, even though this is not
736
# mentioned by 'rev1a', making it an unreferenced ancestor
737
inv = inventory.Inventory()
738
self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b'])
739
self.add_file(repo, inv, 'file2', 'rev2', [])
740
self.add_revision(repo, 'rev2', inv, ['rev1a'])
742
# make ghost revision rev1c
743
inv = inventory.Inventory()
744
self.add_file(repo, inv, 'file2', 'rev1c', [])
746
# make rev3 with file2
747
# file2 refers to 'rev1c', which is a ghost in this repository, so
748
# file2 cannot have rev1c as its ancestor.
749
inv = inventory.Inventory()
750
self.add_file(repo, inv, 'file2', 'rev3', ['rev1c'])
751
self.add_revision(repo, 'rev3', inv, ['rev1c'])
754
for cleanup in reversed(cleanups):
757
def add_revision(self, repo, revision_id, inv, parent_ids):
758
inv.revision_id = revision_id
759
inv.root.revision = revision_id
760
repo.add_inventory(revision_id, inv, parent_ids)
761
revision = _mod_revision.Revision(revision_id,
762
committer='jrandom@example.com', timestamp=0, inventory_sha1='',
763
timezone=0, message='foo', parent_ids=parent_ids)
764
repo.add_revision(revision_id,revision, inv)
766
def add_file(self, repo, inv, filename, revision, parents):
767
file_id = filename + '-id'
768
entry = inventory.InventoryFile(file_id, filename, 'TREE_ROOT')
769
entry.revision = revision
772
vf = repo.weave_store.get_weave_or_empty(file_id,
773
repo.get_transaction())
774
vf.add_lines(revision, parents, ['line\n'])
776
def test_insert_from_broken_repo(self):
777
"""Inserting a data stream from a broken repository won't silently
778
corrupt the target repository.
780
broken_repo = self.make_broken_repository()
781
empty_repo = self.make_repository('empty-repo')
782
search = graph.SearchResult(set(['rev1a', 'rev2', 'rev3']),
783
set(), 3, ['rev1a', 'rev2', 'rev3'])
784
stream = broken_repo.get_data_stream_for_search(search)
785
empty_repo.lock_write()
786
self.addCleanup(empty_repo.unlock)
787
empty_repo.start_write_group()
790
errors.KnitCorrupt, empty_repo.insert_data_stream, stream)
792
empty_repo.abort_write_group()
795
class TestKnitPackNoSubtrees(TestCaseWithTransport):
797
def get_format(self):
798
return bzrdir.format_registry.make_bzrdir('pack-0.92')
800
def test_disk_layout(self):
801
format = self.get_format()
802
repo = self.make_repository('.', format=format)
803
# in case of side effects of locking.
806
t = repo.bzrdir.get_repository_transport(None)
808
# XXX: no locks left when unlocked at the moment
809
# self.assertEqualDiff('', t.get('lock').read())
810
self.check_databases(t)
812
def check_format(self, t):
813
self.assertEqualDiff(
814
"Bazaar pack repository format 1 (needs bzr 0.92)\n",
815
t.get('format').read())
817
def assertHasKndx(self, t, knit_name):
818
"""Assert that knit_name exists on t."""
819
self.assertEqualDiff('# bzr knit index 8\n',
820
t.get(knit_name + '.kndx').read())
822
def assertHasNoKndx(self, t, knit_name):
823
"""Assert that knit_name has no index on t."""
824
self.assertFalse(t.has(knit_name + '.kndx'))
826
def assertHasNoKnit(self, t, knit_name):
827
"""Assert that knit_name exists on t."""
829
self.assertFalse(t.has(knit_name + '.knit'))
831
def check_databases(self, t):
832
"""check knit content for a repository."""
833
# check conversion worked
834
self.assertHasNoKndx(t, 'inventory')
835
self.assertHasNoKnit(t, 'inventory')
836
self.assertHasNoKndx(t, 'revisions')
837
self.assertHasNoKnit(t, 'revisions')
838
self.assertHasNoKndx(t, 'signatures')
839
self.assertHasNoKnit(t, 'signatures')
840
self.assertFalse(t.has('knits'))
841
# revision-indexes file-container directory
843
list(GraphIndex(t, 'pack-names', None).iter_all_entries()))
844
self.assertTrue(S_ISDIR(t.stat('packs').st_mode))
845
self.assertTrue(S_ISDIR(t.stat('upload').st_mode))
846
self.assertTrue(S_ISDIR(t.stat('indices').st_mode))
847
self.assertTrue(S_ISDIR(t.stat('obsolete_packs').st_mode))
849
def test_shared_disk_layout(self):
850
format = self.get_format()
851
repo = self.make_repository('.', shared=True, format=format)
853
t = repo.bzrdir.get_repository_transport(None)
855
# XXX: no locks left when unlocked at the moment
856
# self.assertEqualDiff('', t.get('lock').read())
857
# We should have a 'shared-storage' marker file.
858
self.assertEqualDiff('', t.get('shared-storage').read())
859
self.check_databases(t)
861
def test_shared_no_tree_disk_layout(self):
862
format = self.get_format()
863
repo = self.make_repository('.', shared=True, format=format)
864
repo.set_make_working_trees(False)
866
t = repo.bzrdir.get_repository_transport(None)
868
# XXX: no locks left when unlocked at the moment
869
# self.assertEqualDiff('', t.get('lock').read())
870
# We should have a 'shared-storage' marker file.
871
self.assertEqualDiff('', t.get('shared-storage').read())
872
# We should have a marker for the no-working-trees flag.
873
self.assertEqualDiff('', t.get('no-working-trees').read())
874
# The marker should go when we toggle the setting.
875
repo.set_make_working_trees(True)
876
self.assertFalse(t.has('no-working-trees'))
877
self.check_databases(t)
879
def test_adding_revision_creates_pack_indices(self):
880
format = self.get_format()
881
tree = self.make_branch_and_tree('.', format=format)
882
trans = tree.branch.repository.bzrdir.get_repository_transport(None)
884
list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
885
tree.commit('foobarbaz')
886
index = GraphIndex(trans, 'pack-names', None)
887
index_nodes = list(index.iter_all_entries())
888
self.assertEqual(1, len(index_nodes))
889
node = index_nodes[0]
891
# the pack sizes should be listed in the index
893
sizes = [int(digits) for digits in pack_value.split(' ')]
894
for size, suffix in zip(sizes, ['.rix', '.iix', '.tix', '.six']):
895
stat = trans.stat('indices/%s%s' % (name, suffix))
896
self.assertEqual(size, stat.st_size)
898
def test_pulling_nothing_leads_to_no_new_names(self):
899
format = self.get_format()
900
tree1 = self.make_branch_and_tree('1', format=format)
901
tree2 = self.make_branch_and_tree('2', format=format)
902
tree1.branch.repository.fetch(tree2.branch.repository)
903
trans = tree1.branch.repository.bzrdir.get_repository_transport(None)
905
list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
907
def test_commit_across_pack_shape_boundary_autopacks(self):
908
format = self.get_format()
909
tree = self.make_branch_and_tree('.', format=format)
910
trans = tree.branch.repository.bzrdir.get_repository_transport(None)
911
# This test could be a little cheaper by replacing the packs
912
# attribute on the repository to allow a different pack distribution
913
# and max packs policy - so we are checking the policy is honoured
914
# in the test. But for now 11 commits is not a big deal in a single
917
tree.commit('commit %s' % x)
918
# there should be 9 packs:
919
index = GraphIndex(trans, 'pack-names', None)
920
self.assertEqual(9, len(list(index.iter_all_entries())))
921
# insert some files in obsolete_packs which should be removed by pack.
922
trans.put_bytes('obsolete_packs/foo', '123')
923
trans.put_bytes('obsolete_packs/bar', '321')
924
# committing one more should coalesce to 1 of 10.
925
tree.commit('commit triggering pack')
926
index = GraphIndex(trans, 'pack-names', None)
927
self.assertEqual(1, len(list(index.iter_all_entries())))
928
# packing should not damage data
929
tree = tree.bzrdir.open_workingtree()
930
check_result = tree.branch.repository.check(
931
[tree.branch.last_revision()])
932
# We should have 50 (10x5) files in the obsolete_packs directory.
933
obsolete_files = list(trans.list_dir('obsolete_packs'))
934
self.assertFalse('foo' in obsolete_files)
935
self.assertFalse('bar' in obsolete_files)
936
self.assertEqual(50, len(obsolete_files))
937
# XXX: Todo check packs obsoleted correctly - old packs and indices
938
# in the obsolete_packs directory.
939
large_pack_name = list(index.iter_all_entries())[0][1][0]
940
# finally, committing again should not touch the large pack.
941
tree.commit('commit not triggering pack')
942
index = GraphIndex(trans, 'pack-names', None)
943
self.assertEqual(2, len(list(index.iter_all_entries())))
944
pack_names = [node[1][0] for node in index.iter_all_entries()]
945
self.assertTrue(large_pack_name in pack_names)
947
def test_pack_after_two_commits_packs_everything(self):
948
format = self.get_format()
949
tree = self.make_branch_and_tree('.', format=format)
950
trans = tree.branch.repository.bzrdir.get_repository_transport(None)
952
tree.commit('more work')
953
tree.branch.repository.pack()
954
# there should be 1 pack:
955
index = GraphIndex(trans, 'pack-names', None)
956
self.assertEqual(1, len(list(index.iter_all_entries())))
957
self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
959
def test_pack_layout(self):
960
format = self.get_format()
961
tree = self.make_branch_and_tree('.', format=format)
962
trans = tree.branch.repository.bzrdir.get_repository_transport(None)
963
tree.commit('start', rev_id='1')
964
tree.commit('more work', rev_id='2')
965
tree.branch.repository.pack()
967
self.addCleanup(tree.unlock)
968
pack = tree.branch.repository._pack_collection.get_pack_by_name(
969
tree.branch.repository._pack_collection.names()[0])
970
# revision access tends to be tip->ancestor, so ordering that way on
971
# disk is a good idea.
972
for _1, key, val, refs in pack.revision_index.iter_all_entries():
974
pos_1 = int(val[1:].split()[0])
976
pos_2 = int(val[1:].split()[0])
977
self.assertTrue(pos_2 < pos_1)
979
def test_pack_repositories_support_multiple_write_locks(self):
980
format = self.get_format()
981
self.make_repository('.', shared=True, format=format)
982
r1 = repository.Repository.open('.')
983
r2 = repository.Repository.open('.')
985
self.addCleanup(r1.unlock)
989
def _add_text(self, repo, fileid):
990
"""Add a text to the repository within a write group."""
991
vf =repo.weave_store.get_weave(fileid, repo.get_transaction())
992
vf.add_lines('samplerev+' + fileid, [], [])
994
def test_concurrent_writers_merge_new_packs(self):
995
format = self.get_format()
996
self.make_repository('.', shared=True, format=format)
997
r1 = repository.Repository.open('.')
998
r2 = repository.Repository.open('.')
1001
# access enough data to load the names list
1002
list(r1.all_revision_ids())
1005
# access enough data to load the names list
1006
list(r2.all_revision_ids())
1007
r1.start_write_group()
1009
r2.start_write_group()
1011
self._add_text(r1, 'fileidr1')
1012
self._add_text(r2, 'fileidr2')
1014
r2.abort_write_group()
1017
r1.abort_write_group()
1019
# both r1 and r2 have open write groups with data in them
1020
# created while the other's write group was open.
1021
# Commit both which requires a merge to the pack-names.
1023
r1.commit_write_group()
1025
r1.abort_write_group()
1026
r2.abort_write_group()
1028
r2.commit_write_group()
1029
# tell r1 to reload from disk
1030
r1._pack_collection.reset()
1031
# Now both repositories should know about both names
1032
r1._pack_collection.ensure_loaded()
1033
r2._pack_collection.ensure_loaded()
1034
self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1035
self.assertEqual(2, len(r1._pack_collection.names()))
1041
def test_concurrent_writer_second_preserves_dropping_a_pack(self):
1042
format = self.get_format()
1043
self.make_repository('.', shared=True, format=format)
1044
r1 = repository.Repository.open('.')
1045
r2 = repository.Repository.open('.')
1046
# add a pack to drop
1049
r1.start_write_group()
1051
self._add_text(r1, 'fileidr1')
1053
r1.abort_write_group()
1056
r1.commit_write_group()
1057
r1._pack_collection.ensure_loaded()
1058
name_to_drop = r1._pack_collection.all_packs()[0].name
1063
# access enough data to load the names list
1064
list(r1.all_revision_ids())
1067
# access enough data to load the names list
1068
list(r2.all_revision_ids())
1069
r1._pack_collection.ensure_loaded()
1071
r2.start_write_group()
1073
# in r1, drop the pack
1074
r1._pack_collection._remove_pack_from_memory(
1075
r1._pack_collection.get_pack_by_name(name_to_drop))
1077
self._add_text(r2, 'fileidr2')
1079
r2.abort_write_group()
1082
r1._pack_collection.reset()
1084
# r1 has a changed names list, and r2 an open write groups with
1086
# save r1, and then commit the r2 write group, which requires a
1087
# merge to the pack-names, which should not reinstate
1090
r1._pack_collection._save_pack_names()
1091
r1._pack_collection.reset()
1093
r2.abort_write_group()
1096
r2.commit_write_group()
1098
r2.abort_write_group()
1100
# Now both repositories should now about just one name.
1101
r1._pack_collection.ensure_loaded()
1102
r2._pack_collection.ensure_loaded()
1103
self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1104
self.assertEqual(1, len(r1._pack_collection.names()))
1105
self.assertFalse(name_to_drop in r1._pack_collection.names())
1111
def test_lock_write_does_not_physically_lock(self):
1112
repo = self.make_repository('.', format=self.get_format())
1114
self.addCleanup(repo.unlock)
1115
self.assertFalse(repo.get_physical_lock_status())
1117
def prepare_for_break_lock(self):
1118
# Setup the global ui factory state so that a break-lock method call
1119
# will find usable input in the input stream.
1120
old_factory = bzrlib.ui.ui_factory
1121
def restoreFactory():
1122
bzrlib.ui.ui_factory = old_factory
1123
self.addCleanup(restoreFactory)
1124
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1125
bzrlib.ui.ui_factory.stdin = StringIO("y\n")
1127
def test_break_lock_breaks_physical_lock(self):
1128
repo = self.make_repository('.', format=self.get_format())
1129
repo._pack_collection.lock_names()
1130
repo2 = repository.Repository.open('.')
1131
self.assertTrue(repo.get_physical_lock_status())
1132
self.prepare_for_break_lock()
1134
self.assertFalse(repo.get_physical_lock_status())
1136
def test_broken_physical_locks_error_on__unlock_names_lock(self):
1137
repo = self.make_repository('.', format=self.get_format())
1138
repo._pack_collection.lock_names()
1139
self.assertTrue(repo.get_physical_lock_status())
1140
repo2 = repository.Repository.open('.')
1141
self.prepare_for_break_lock()
1143
self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
1145
def test_fetch_without_find_ghosts_ignores_ghosts(self):
1146
# we want two repositories at this point:
1147
# one with a revision that is a ghost in the other
1149
# 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
1150
# 'references' is present in both repositories, and 'tip' is present
1151
# just in has_ghost.
1152
# has_ghost missing_ghost
1153
#------------------------------
1155
# 'references' 'references'
1157
# In this test we fetch 'tip' which should not fetch 'ghost'
1158
has_ghost = self.make_repository('has_ghost', format=self.get_format())
1159
missing_ghost = self.make_repository('missing_ghost',
1160
format=self.get_format())
1162
def add_commit(repo, revision_id, parent_ids):
1164
repo.start_write_group()
1165
inv = inventory.Inventory(revision_id=revision_id)
1166
inv.root.revision = revision_id
1167
root_id = inv.root.file_id
1168
sha1 = repo.add_inventory(revision_id, inv, [])
1169
vf = repo.weave_store.get_weave_or_empty(root_id,
1170
repo.get_transaction())
1171
vf.add_lines(revision_id, [], [])
1172
rev = bzrlib.revision.Revision(timestamp=0,
1174
committer="Foo Bar <foo@example.com>",
1176
inventory_sha1=sha1,
1177
revision_id=revision_id)
1178
rev.parent_ids = parent_ids
1179
repo.add_revision(revision_id, rev)
1180
repo.commit_write_group()
1182
add_commit(has_ghost, 'ghost', [])
1183
add_commit(has_ghost, 'references', ['ghost'])
1184
add_commit(missing_ghost, 'references', ['ghost'])
1185
add_commit(has_ghost, 'tip', ['references'])
1186
missing_ghost.fetch(has_ghost, 'tip')
1187
# missing ghost now has tip and not ghost.
1188
rev = missing_ghost.get_revision('tip')
1189
inv = missing_ghost.get_inventory('tip')
1190
self.assertRaises(errors.NoSuchRevision,
1191
missing_ghost.get_revision, 'ghost')
1192
self.assertRaises(errors.RevisionNotPresent,
1193
missing_ghost.get_inventory, 'ghost')
1195
def test_supports_external_lookups(self):
1196
repo = self.make_repository('.', format=self.get_format())
1197
self.assertFalse(repo._format.supports_external_lookups)
1200
class TestKnitPackSubtrees(TestKnitPackNoSubtrees):
1202
def get_format(self):
1203
return bzrdir.format_registry.make_bzrdir(
1204
'pack-0.92-subtree')
1206
def check_format(self, t):
1207
self.assertEqualDiff(
1208
"Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n",
1209
t.get('format').read())
1212
class TestDevelopment0(TestKnitPackNoSubtrees):
1214
def get_format(self):
1215
return bzrdir.format_registry.make_bzrdir(
1218
def check_format(self, t):
1219
self.assertEqualDiff(
1220
"Bazaar development format 0 (needs bzr.dev from before 1.3)\n",
1221
t.get('format').read())
1224
class TestDevelopment0Subtree(TestKnitPackNoSubtrees):
1226
def get_format(self):
1227
return bzrdir.format_registry.make_bzrdir(
1228
'development-subtree')
1230
def check_format(self, t):
1231
self.assertEqualDiff(
1232
"Bazaar development format 0 with subtree support "
1233
"(needs bzr.dev from before 1.3)\n",
1234
t.get('format').read())
1237
class TestRepositoryPackCollection(TestCaseWithTransport):
1239
def get_format(self):
1240
return bzrdir.format_registry.make_bzrdir('pack-0.92')
1242
def test__max_pack_count(self):
1243
"""The maximum pack count is a function of the number of revisions."""
1244
format = self.get_format()
1245
repo = self.make_repository('.', format=format)
1246
packs = repo._pack_collection
1247
# no revisions - one pack, so that we can have a revision free repo
1248
# without it blowing up
1249
self.assertEqual(1, packs._max_pack_count(0))
1250
# after that the sum of the digits, - check the first 1-9
1251
self.assertEqual(1, packs._max_pack_count(1))
1252
self.assertEqual(2, packs._max_pack_count(2))
1253
self.assertEqual(3, packs._max_pack_count(3))
1254
self.assertEqual(4, packs._max_pack_count(4))
1255
self.assertEqual(5, packs._max_pack_count(5))
1256
self.assertEqual(6, packs._max_pack_count(6))
1257
self.assertEqual(7, packs._max_pack_count(7))
1258
self.assertEqual(8, packs._max_pack_count(8))
1259
self.assertEqual(9, packs._max_pack_count(9))
1260
# check the boundary cases with two digits for the next decade
1261
self.assertEqual(1, packs._max_pack_count(10))
1262
self.assertEqual(2, packs._max_pack_count(11))
1263
self.assertEqual(10, packs._max_pack_count(19))
1264
self.assertEqual(2, packs._max_pack_count(20))
1265
self.assertEqual(3, packs._max_pack_count(21))
1266
# check some arbitrary big numbers
1267
self.assertEqual(25, packs._max_pack_count(112894))
1269
def test_pack_distribution_zero(self):
1270
format = self.get_format()
1271
repo = self.make_repository('.', format=format)
1272
packs = repo._pack_collection
1273
self.assertEqual([0], packs.pack_distribution(0))
1275
def test_ensure_loaded_unlocked(self):
1276
format = self.get_format()
1277
repo = self.make_repository('.', format=format)
1278
self.assertRaises(errors.ObjectNotLocked,
1279
repo._pack_collection.ensure_loaded)
1281
def test_pack_distribution_one_to_nine(self):
1282
format = self.get_format()
1283
repo = self.make_repository('.', format=format)
1284
packs = repo._pack_collection
1285
self.assertEqual([1],
1286
packs.pack_distribution(1))
1287
self.assertEqual([1, 1],
1288
packs.pack_distribution(2))
1289
self.assertEqual([1, 1, 1],
1290
packs.pack_distribution(3))
1291
self.assertEqual([1, 1, 1, 1],
1292
packs.pack_distribution(4))
1293
self.assertEqual([1, 1, 1, 1, 1],
1294
packs.pack_distribution(5))
1295
self.assertEqual([1, 1, 1, 1, 1, 1],
1296
packs.pack_distribution(6))
1297
self.assertEqual([1, 1, 1, 1, 1, 1, 1],
1298
packs.pack_distribution(7))
1299
self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1],
1300
packs.pack_distribution(8))
1301
self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1, 1],
1302
packs.pack_distribution(9))
1304
def test_pack_distribution_stable_at_boundaries(self):
1305
"""When there are multi-rev packs the counts are stable."""
1306
format = self.get_format()
1307
repo = self.make_repository('.', format=format)
1308
packs = repo._pack_collection
1310
self.assertEqual([10], packs.pack_distribution(10))
1311
self.assertEqual([10, 1], packs.pack_distribution(11))
1312
self.assertEqual([10, 10], packs.pack_distribution(20))
1313
self.assertEqual([10, 10, 1], packs.pack_distribution(21))
1315
self.assertEqual([100], packs.pack_distribution(100))
1316
self.assertEqual([100, 1], packs.pack_distribution(101))
1317
self.assertEqual([100, 10, 1], packs.pack_distribution(111))
1318
self.assertEqual([100, 100], packs.pack_distribution(200))
1319
self.assertEqual([100, 100, 1], packs.pack_distribution(201))
1320
self.assertEqual([100, 100, 10, 1], packs.pack_distribution(211))
1322
def test_plan_pack_operations_2009_revisions_skip_all_packs(self):
1323
format = self.get_format()
1324
repo = self.make_repository('.', format=format)
1325
packs = repo._pack_collection
1326
existing_packs = [(2000, "big"), (9, "medium")]
1327
# rev count - 2009 -> 2x1000 + 9x1
1328
pack_operations = packs.plan_autopack_combinations(
1329
existing_packs, [1000, 1000, 1, 1, 1, 1, 1, 1, 1, 1, 1])
1330
self.assertEqual([], pack_operations)
1332
def test_plan_pack_operations_2010_revisions_skip_all_packs(self):
1333
format = self.get_format()
1334
repo = self.make_repository('.', format=format)
1335
packs = repo._pack_collection
1336
existing_packs = [(2000, "big"), (9, "medium"), (1, "single")]
1337
# rev count - 2010 -> 2x1000 + 1x10
1338
pack_operations = packs.plan_autopack_combinations(
1339
existing_packs, [1000, 1000, 10])
1340
self.assertEqual([], pack_operations)
1342
def test_plan_pack_operations_2010_combines_smallest_two(self):
1343
format = self.get_format()
1344
repo = self.make_repository('.', format=format)
1345
packs = repo._pack_collection
1346
existing_packs = [(1999, "big"), (9, "medium"), (1, "single2"),
1348
# rev count - 2010 -> 2x1000 + 1x10 (3)
1349
pack_operations = packs.plan_autopack_combinations(
1350
existing_packs, [1000, 1000, 10])
1351
self.assertEqual([[2, ["single2", "single1"]], [0, []]], pack_operations)
1353
def test_all_packs_none(self):
1354
format = self.get_format()
1355
tree = self.make_branch_and_tree('.', format=format)
1357
self.addCleanup(tree.unlock)
1358
packs = tree.branch.repository._pack_collection
1359
packs.ensure_loaded()
1360
self.assertEqual([], packs.all_packs())
1362
def test_all_packs_one(self):
1363
format = self.get_format()
1364
tree = self.make_branch_and_tree('.', format=format)
1365
tree.commit('start')
1367
self.addCleanup(tree.unlock)
1368
packs = tree.branch.repository._pack_collection
1369
packs.ensure_loaded()
1371
packs.get_pack_by_name(packs.names()[0])],
1374
def test_all_packs_two(self):
1375
format = self.get_format()
1376
tree = self.make_branch_and_tree('.', format=format)
1377
tree.commit('start')
1378
tree.commit('continue')
1380
self.addCleanup(tree.unlock)
1381
packs = tree.branch.repository._pack_collection
1382
packs.ensure_loaded()
1384
packs.get_pack_by_name(packs.names()[0]),
1385
packs.get_pack_by_name(packs.names()[1]),
1386
], packs.all_packs())
1388
def test_get_pack_by_name(self):
1389
format = self.get_format()
1390
tree = self.make_branch_and_tree('.', format=format)
1391
tree.commit('start')
1393
self.addCleanup(tree.unlock)
1394
packs = tree.branch.repository._pack_collection
1395
packs.ensure_loaded()
1396
name = packs.names()[0]
1397
pack_1 = packs.get_pack_by_name(name)
1398
# the pack should be correctly initialised
1399
rev_index = GraphIndex(packs._index_transport, name + '.rix',
1400
packs._names[name][0])
1401
inv_index = GraphIndex(packs._index_transport, name + '.iix',
1402
packs._names[name][1])
1403
txt_index = GraphIndex(packs._index_transport, name + '.tix',
1404
packs._names[name][2])
1405
sig_index = GraphIndex(packs._index_transport, name + '.six',
1406
packs._names[name][3])
1407
self.assertEqual(pack_repo.ExistingPack(packs._pack_transport,
1408
name, rev_index, inv_index, txt_index, sig_index), pack_1)
1409
# and the same instance should be returned on successive calls.
1410
self.assertTrue(pack_1 is packs.get_pack_by_name(name))
1413
class TestPack(TestCaseWithTransport):
1414
"""Tests for the Pack object."""
1416
def assertCurrentlyEqual(self, left, right):
1417
self.assertTrue(left == right)
1418
self.assertTrue(right == left)
1419
self.assertFalse(left != right)
1420
self.assertFalse(right != left)
1422
def assertCurrentlyNotEqual(self, left, right):
1423
self.assertFalse(left == right)
1424
self.assertFalse(right == left)
1425
self.assertTrue(left != right)
1426
self.assertTrue(right != left)
1428
def test___eq____ne__(self):
1429
left = pack_repo.ExistingPack('', '', '', '', '', '')
1430
right = pack_repo.ExistingPack('', '', '', '', '', '')
1431
self.assertCurrentlyEqual(left, right)
1432
# change all attributes and ensure equality changes as we do.
1433
left.revision_index = 'a'
1434
self.assertCurrentlyNotEqual(left, right)
1435
right.revision_index = 'a'
1436
self.assertCurrentlyEqual(left, right)
1437
left.inventory_index = 'a'
1438
self.assertCurrentlyNotEqual(left, right)
1439
right.inventory_index = 'a'
1440
self.assertCurrentlyEqual(left, right)
1441
left.text_index = 'a'
1442
self.assertCurrentlyNotEqual(left, right)
1443
right.text_index = 'a'
1444
self.assertCurrentlyEqual(left, right)
1445
left.signature_index = 'a'
1446
self.assertCurrentlyNotEqual(left, right)
1447
right.signature_index = 'a'
1448
self.assertCurrentlyEqual(left, right)
1450
self.assertCurrentlyNotEqual(left, right)
1452
self.assertCurrentlyEqual(left, right)
1453
left.transport = 'a'
1454
self.assertCurrentlyNotEqual(left, right)
1455
right.transport = 'a'
1456
self.assertCurrentlyEqual(left, right)
1458
def test_file_name(self):
1459
pack = pack_repo.ExistingPack('', 'a_name', '', '', '', '')
1460
self.assertEqual('a_name.pack', pack.file_name())
1463
class TestNewPack(TestCaseWithTransport):
1464
"""Tests for pack_repo.NewPack."""
1466
def test_new_instance_attributes(self):
1467
upload_transport = self.get_transport('upload')
1468
pack_transport = self.get_transport('pack')
1469
index_transport = self.get_transport('index')
1470
upload_transport.mkdir('.')
1471
pack = pack_repo.NewPack(upload_transport, index_transport,
1473
self.assertIsInstance(pack.revision_index, InMemoryGraphIndex)
1474
self.assertIsInstance(pack.inventory_index, InMemoryGraphIndex)
1475
self.assertIsInstance(pack._hash, type(md5.new()))
1476
self.assertTrue(pack.upload_transport is upload_transport)
1477
self.assertTrue(pack.index_transport is index_transport)
1478
self.assertTrue(pack.pack_transport is pack_transport)
1479
self.assertEqual(None, pack.index_sizes)
1480
self.assertEqual(20, len(pack.random_name))
1481
self.assertIsInstance(pack.random_name, str)
1482
self.assertIsInstance(pack.start_time, float)
1485
class TestPacker(TestCaseWithTransport):
1486
"""Tests for the packs repository Packer class."""
1488
# To date, this class has been factored out and nothing new added to it;
1489
# thus there are not yet any tests.
1492
class TestInterDifferingSerializer(TestCaseWithTransport):
1494
def test_progress_bar(self):
1495
tree = self.make_branch_and_tree('tree')
1496
tree.commit('rev1', rev_id='rev-1')
1497
tree.commit('rev2', rev_id='rev-2')
1498
tree.commit('rev3', rev_id='rev-3')
1499
repo = self.make_repository('repo')
1500
inter_repo = repository.InterDifferingSerializer(
1501
tree.branch.repository, repo)
1502
pb = progress.InstrumentedProgress(to_file=StringIO())
1503
pb.never_throttle = True
1504
inter_repo.fetch('rev-1', pb)
1505
self.assertEqual('Transferring revisions', pb.last_msg)
1506
self.assertEqual(1, pb.last_cnt)
1507
self.assertEqual(1, pb.last_total)
1508
inter_repo.fetch('rev-3', pb)
1509
self.assertEqual(2, pb.last_cnt)
1510
self.assertEqual(2, pb.last_total)