def test_add_thin_pack(self): o = MemoryObjectStore() blob = make_object(Blob, data=b'yummy data') o.add_object(blob) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (blob.id, b'more yummy data')), ], store=o) o.add_thin_pack(f.read, None) packed_blob_sha = sha_to_hex(entries[0][3]) self.assertEqual((Blob.type_num, b'more yummy data'), o.get_raw(packed_blob_sha))
def test_add_thin_pack(self): o = MemoryObjectStore() blob = make_object(Blob, data=b'yummy data') o.add_object(blob) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (blob.id, b'more yummy data')), ], store=o) o.add_thin_pack(f.read, None) packed_blob_sha = sha_to_hex(entries[0][3]) self.assertEqual((Blob.type_num, b'more yummy data'), o.get_raw(packed_blob_sha))
class DeltaChainIteratorTests(TestCase): def setUp(self): super(DeltaChainIteratorTests, self).setUp() self.store = MemoryObjectStore() self.fetched = set() def store_blobs(self, blobs_data): blobs = [] for data in blobs_data: blob = make_object(Blob, data=data) blobs.append(blob) self.store.add_object(blob) return blobs def get_raw_no_repeat(self, bin_sha): """Wrapper around store.get_raw that doesn't allow repeat lookups.""" hex_sha = sha_to_hex(bin_sha) self.assertFalse(hex_sha in self.fetched, 'Attempted to re-fetch object %s' % hex_sha) self.fetched.add(hex_sha) return self.store.get_raw(hex_sha) def make_pack_iter(self, f, thin=None): if thin is None: thin = bool(list(self.store)) resolve_ext_ref = thin and self.get_raw_no_repeat or None data = PackData('test.pack', file=f) return TestPackIterator.for_pack_data( data, resolve_ext_ref=resolve_ext_ref) def assertEntriesMatch(self, expected_indexes, entries, pack_iter): expected = [entries[i] for i in expected_indexes] self.assertEqual(expected, list(pack_iter._walk_all_chains())) def test_no_deltas(self): f = BytesIO() entries = build_pack(f, [ (Commit.type_num, 'commit'), (Blob.type_num, 'blob'), (Tree.type_num, 'tree'), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ofs_deltas(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (0, 'blob2')), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ofs_deltas_chain(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ref_deltas(self): f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob1')), (Blob.type_num, ('blob')), (REF_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 0, 2], entries, self.make_pack_iter(f)) def test_ref_deltas_chain(self): f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (2, 'blob1')), (Blob.type_num, ('blob')), (REF_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f)) def test_ofs_and_ref_deltas(self): # Deltas pending on this offset are popped before deltas depending on # this ref. f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob1')), (Blob.type_num, ('blob')), (OFS_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f)) def test_mixed_chain(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (REF_DELTA, (2, 'blob2')), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (1, 'blob3')), (OFS_DELTA, (0, 'bob')), ]) self.assertEntriesMatch([0, 2, 1, 3, 4], entries, self.make_pack_iter(f)) def test_long_chain(self): n = 100 objects_spec = [(Blob.type_num, 'blob')] for i in range(n): objects_spec.append((OFS_DELTA, (i, 'blob%i' % i))) f = BytesIO() entries = build_pack(f, objects_spec) self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f)) def test_branchy_chain(self): n = 100 objects_spec = [(Blob.type_num, 'blob')] for i in range(n): objects_spec.append((OFS_DELTA, (0, 'blob%i' % i))) f = BytesIO() entries = build_pack(f, objects_spec) self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f)) def test_ext_ref(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_ext_ref_chain(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob2')), (REF_DELTA, (blob.id, 'blob1')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([1, 0], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_ext_ref_multiple_times(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (blob.id, 'blob1')), (REF_DELTA, (blob.id, 'blob2')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0, 1], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_multiple_ext_refs(self): b1, b2 = self.store_blobs(['foo', 'bar']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (b1.id, 'foo1')), (REF_DELTA, (b2.id, 'bar2')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0, 1], entries, pack_iter) self.assertEqual([hex_to_sha(b1.id), hex_to_sha(b2.id)], pack_iter.ext_refs()) def test_bad_ext_ref_non_thin_pack(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))], store=self.store) pack_iter = self.make_pack_iter(f, thin=False) try: list(pack_iter._walk_all_chains()) self.fail() except KeyError as e: self.assertEqual(([blob.id],), e.args) def test_bad_ext_ref_thin_pack(self): b1, b2, b3 = self.store_blobs(['foo', 'bar', 'baz']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'foo99')), (REF_DELTA, (b1.id, 'foo1')), (REF_DELTA, (b2.id, 'bar2')), (REF_DELTA, (b3.id, 'baz3')), ], store=self.store) del self.store[b2.id] del self.store[b3.id] pack_iter = self.make_pack_iter(f) try: list(pack_iter._walk_all_chains()) self.fail() except KeyError as e: self.assertEqual((sorted([b2.id, b3.id]),), e.args)
class DeltaChainIteratorTests(TestCase): def setUp(self): super(DeltaChainIteratorTests, self).setUp() self.store = MemoryObjectStore() self.fetched = set() def store_blobs(self, blobs_data): blobs = [] for data in blobs_data: blob = make_object(Blob, data=data) blobs.append(blob) self.store.add_object(blob) return blobs def get_raw_no_repeat(self, bin_sha): """Wrapper around store.get_raw that doesn't allow repeat lookups.""" hex_sha = sha_to_hex(bin_sha) self.assertFalse(hex_sha in self.fetched, 'Attempted to re-fetch object %s' % hex_sha) self.fetched.add(hex_sha) return self.store.get_raw(hex_sha) def make_pack_iter(self, f, thin=None): if thin is None: thin = bool(list(self.store)) resolve_ext_ref = thin and self.get_raw_no_repeat or None data = PackData('test.pack', file=f) return TestPackIterator.for_pack_data( data, resolve_ext_ref=resolve_ext_ref) def assertEntriesMatch(self, expected_indexes, entries, pack_iter): expected = [entries[i] for i in expected_indexes] self.assertEqual(expected, list(pack_iter._walk_all_chains())) def test_no_deltas(self): f = BytesIO() entries = build_pack(f, [ (Commit.type_num, 'commit'), (Blob.type_num, 'blob'), (Tree.type_num, 'tree'), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ofs_deltas(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (0, 'blob2')), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ofs_deltas_chain(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f)) def test_ref_deltas(self): f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob1')), (Blob.type_num, ('blob')), (REF_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 0, 2], entries, self.make_pack_iter(f)) def test_ref_deltas_chain(self): f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (2, 'blob1')), (Blob.type_num, ('blob')), (REF_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f)) def test_ofs_and_ref_deltas(self): # Deltas pending on this offset are popped before deltas depending on # this ref. f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob1')), (Blob.type_num, ('blob')), (OFS_DELTA, (1, 'blob2')), ]) self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f)) def test_mixed_chain(self): f = BytesIO() entries = build_pack(f, [ (Blob.type_num, 'blob'), (REF_DELTA, (2, 'blob2')), (OFS_DELTA, (0, 'blob1')), (OFS_DELTA, (1, 'blob3')), (OFS_DELTA, (0, 'bob')), ]) self.assertEntriesMatch([0, 2, 1, 3, 4], entries, self.make_pack_iter(f)) def test_long_chain(self): n = 100 objects_spec = [(Blob.type_num, 'blob')] for i in range(n): objects_spec.append((OFS_DELTA, (i, 'blob%i' % i))) f = BytesIO() entries = build_pack(f, objects_spec) self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f)) def test_branchy_chain(self): n = 100 objects_spec = [(Blob.type_num, 'blob')] for i in range(n): objects_spec.append((OFS_DELTA, (0, 'blob%i' % i))) f = BytesIO() entries = build_pack(f, objects_spec) self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f)) def test_ext_ref(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_ext_ref_chain(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (1, 'blob2')), (REF_DELTA, (blob.id, 'blob1')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([1, 0], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_ext_ref_chain_degenerate(self): # Test a degenerate case where the sender is sending a REF_DELTA # object that expands to an object already in the repository. blob, = self.store_blobs(['blob']) blob2, = self.store_blobs(['blob2']) assert blob.id < blob2.id f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (blob.id, 'blob2')), (REF_DELTA, (0, 'blob3')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0, 1], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_ext_ref_multiple_times(self): blob, = self.store_blobs(['blob']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (blob.id, 'blob1')), (REF_DELTA, (blob.id, 'blob2')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0, 1], entries, pack_iter) self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs()) def test_multiple_ext_refs(self): b1, b2 = self.store_blobs(['foo', 'bar']) f = BytesIO() entries = build_pack(f, [ (REF_DELTA, (b1.id, 'foo1')), (REF_DELTA, (b2.id, 'bar2')), ], store=self.store) pack_iter = self.make_pack_iter(f) self.assertEntriesMatch([0, 1], entries, pack_iter) self.assertEqual([hex_to_sha(b1.id), hex_to_sha(b2.id)], pack_iter.ext_refs()) def test_bad_ext_ref_non_thin_pack(self): blob, = self.store_blobs(['blob']) f = BytesIO() build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))], store=self.store) pack_iter = self.make_pack_iter(f, thin=False) try: list(pack_iter._walk_all_chains()) self.fail() except KeyError as e: self.assertEqual(([blob.id],), e.args) def test_bad_ext_ref_thin_pack(self): b1, b2, b3 = self.store_blobs(['foo', 'bar', 'baz']) f = BytesIO() build_pack(f, [ (REF_DELTA, (1, 'foo99')), (REF_DELTA, (b1.id, 'foo1')), (REF_DELTA, (b2.id, 'bar2')), (REF_DELTA, (b3.id, 'baz3')), ], store=self.store) del self.store[b2.id] del self.store[b3.id] pack_iter = self.make_pack_iter(f) try: list(pack_iter._walk_all_chains()) self.fail() except KeyError as e: self.assertEqual((sorted([b2.id, b3.id]),), (sorted(e.args[0]),))