Beispiel #1
0
    def setUp(self):
        super(TestThinPack, self).setUp()
        self.store = MemoryObjectStore()
        self.blobs = {}
        for blob in (b'foo', b'bar', b'foo1234', b'bar2468'):
            self.blobs[blob] = make_object(Blob, data=blob)
        self.store.add_object(self.blobs[b'foo'])
        self.store.add_object(self.blobs[b'bar'])

        # Build a thin pack. 'foo' is as an external reference, 'bar' an
        # internal reference.
        self.pack_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.pack_dir)
        self.pack_prefix = os.path.join(self.pack_dir, 'pack')

        with open(self.pack_prefix + '.pack', 'wb') as f:
            build_pack(f, [(REF_DELTA, (self.blobs[b'foo'].id, b'foo1234')),
                           (Blob.type_num, b'bar'),
                           (REF_DELTA, (self.blobs[b'bar'].id, b'bar2468'))],
                       store=self.store)

        # Index the new pack.
        with self.make_pack(True) as pack:
            with PackData(pack._data_path) as data:
                data.pack = pack
                data.create_index(self.pack_prefix + '.idx')

        del self.store[self.blobs[b'bar'].id]
Beispiel #2
0
 def test_object_diff_bin_blob_force(self):
     f = BytesIO()
     # Prepare two slightly different PNG headers
     b1 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x04\x00\x00\x00\x05\x04\x8b")
     b2 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x03\x00\x00\x00\x98\xd3\xb3")
     store = MemoryObjectStore()
     store.add_objects([(b1, None), (b2, None)])
     write_object_diff(f,
                       store, (b'foo.png', 0o644, b1.id),
                       (b'bar.png', 0o644, b2.id),
                       diff_binary=True)
     self.assertEqual([
         b'diff --git a/foo.png b/bar.png', b'index f73e47d..06364b7 644',
         b'--- a/foo.png', b'+++ b/bar.png', b'@@ -1,4 +1,4 @@',
         b' \x89PNG', b' \x1a', b' \x00\x00\x00',
         b'-IHDR\x00\x00\x01\xd5\x00\x00\x00'
         b'\x9f\x08\x04\x00\x00\x00\x05\x04\x8b',
         b'\\ No newline at end of file',
         b'+IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f'
         b'\x08\x03\x00\x00\x00\x98\xd3\xb3',
         b'\\ No newline at end of file'
     ],
                      f.getvalue().splitlines())
class CommitTreeTests(TestCase):
    def setUp(self):
        super(CommitTreeTests, self).setUp()
        self.store = MemoryObjectStore()

    def test_single_blob(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"1a1e80437220f9312e855c37ac4398b68e5c1d50")
        self.assertEqual((stat.S_IFREG, blob.id), self.store[rootid][b"bla"])
        self.assertEqual(set([rootid, blob.id]), set(self.store._data.keys()))

    def test_nested(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla/bar", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"d92b959b216ad0d044671981196781b3258fa537")
        dirid = self.store[rootid][b"bla"][1]
        self.assertEqual(dirid, b"c1a1deb9788150829579a8b4efa6311e7b638650")
        self.assertEqual((stat.S_IFDIR, dirid), self.store[rootid][b"bla"])
        self.assertEqual((stat.S_IFREG, blob.id), self.store[dirid][b"bar"])
        self.assertEqual(set([rootid, dirid, blob.id]),
                         set(self.store._data.keys()))
 def setUp(self):
     super(GitFastExporterTests, self).setUp()
     self.store = MemoryObjectStore()
     self.stream = BytesIO()
     try:
         from my_dulwich.fastexport import GitFastExporter
     except ImportError:
         raise SkipTest("python-fastimport not available")
     self.fastexporter = GitFastExporter(self.stream, self.store)
Beispiel #5
0
 def test_object_diff_add_blob(self):
     f = BytesIO()
     store = MemoryObjectStore()
     b2 = Blob.from_string(b"new\nsame\n")
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       (b"bar.txt", 0o644, b2.id))
     self.assertEqual([
         b'diff --git /dev/null b/bar.txt', b'new mode 644',
         b'index 0000000..a116b51 644', b'--- /dev/null', b'+++ b/bar.txt',
         b'@@ -0,0 +1,2 @@', b'+new', b'+same'
     ],
                      f.getvalue().splitlines())
Beispiel #6
0
 def test_object_diff_remove_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"bar.txt", 0o644, b1.id),
                       (None, None, None))
     self.assertEqual([
         b'diff --git a/bar.txt /dev/null', b'deleted mode 644',
         b'index a116b51..0000000', b'--- a/bar.txt', b'+++ /dev/null',
         b'@@ -1,2 +0,0 @@', b'-new', b'-same'
     ],
                      f.getvalue().splitlines())
Beispiel #7
0
 def test_object_diff_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"old\nsame\n")
     b2 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_objects([(b1, None), (b2, None)])
     write_object_diff(f, store, (b"foo.txt", 0o644, b1.id),
                       (b"bar.txt", 0o644, b2.id))
     self.assertEqual([
         b"diff --git a/foo.txt b/bar.txt", b"index 3b0f961..a116b51 644",
         b"--- a/foo.txt", b"+++ b/bar.txt", b"@@ -1,2 +1,2 @@", b"-old",
         b"+new", b" same"
     ],
                      f.getvalue().splitlines())
Beispiel #8
0
 def test_object_diff_add_bin_blob(self):
     f = BytesIO()
     b2 = Blob.from_string(b'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a'
                           b'\x00\x00\x00\x0d\x49\x48\x44\x52'
                           b'\x00\x00\x01\xd5\x00\x00\x00\x9f'
                           b'\x08\x03\x00\x00\x00\x98\xd3\xb3')
     store = MemoryObjectStore()
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       (b'bar.png', 0o644, b2.id))
     self.assertEqual([
         b'diff --git /dev/null b/bar.png', b'new mode 644',
         b'index 0000000..06364b7 644',
         b'Binary files /dev/null and b/bar.png differ'
     ],
                      f.getvalue().splitlines())
Beispiel #9
0
 def test_object_diff_remove_bin_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a'
                           b'\x00\x00\x00\x0d\x49\x48\x44\x52'
                           b'\x00\x00\x01\xd5\x00\x00\x00\x9f'
                           b'\x08\x04\x00\x00\x00\x05\x04\x8b')
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b'foo.png', 0o644, b1.id),
                       (None, None, None))
     self.assertEqual([
         b'diff --git a/foo.png /dev/null', b'deleted mode 644',
         b'index f73e47d..0000000',
         b'Binary files a/foo.png and /dev/null differ'
     ],
                      f.getvalue().splitlines())
 def test_against_empty_tree(self):
     i = self.get_simple_index("index")
     changes = list(i.changes_from_tree(MemoryObjectStore(), None))
     self.assertEqual(1, len(changes))
     (oldname, newname), (oldmode, newmode), (oldsha, newsha) = changes[0]
     self.assertEqual(b'bla', newname)
     self.assertEqual(b'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391', newsha)
Beispiel #11
0
 def test_tree_diff(self):
     f = BytesIO()
     store = MemoryObjectStore()
     added = Blob.from_string(b"add\n")
     removed = Blob.from_string(b"removed\n")
     changed1 = Blob.from_string(b"unchanged\nremoved\n")
     changed2 = Blob.from_string(b"unchanged\nadded\n")
     unchanged = Blob.from_string(b"unchanged\n")
     tree1 = Tree()
     tree1.add(b"removed.txt", 0o644, removed.id)
     tree1.add(b"changed.txt", 0o644, changed1.id)
     tree1.add(b"unchanged.txt", 0o644, changed1.id)
     tree2 = Tree()
     tree2.add(b"added.txt", 0o644, added.id)
     tree2.add(b"changed.txt", 0o644, changed2.id)
     tree2.add(b"unchanged.txt", 0o644, changed1.id)
     store.add_objects([
         (o, None) for o in
         [tree1, tree2, added, removed, changed1, changed2, unchanged]
     ])
     write_tree_diff(f, store, tree1.id, tree2.id)
     self.assertEqual([
         b'diff --git /dev/null b/added.txt',
         b'new mode 644',
         b'index 0000000..76d4bb8 644',
         b'--- /dev/null',
         b'+++ b/added.txt',
         b'@@ -0,0 +1 @@',
         b'+add',
         b'diff --git a/changed.txt b/changed.txt',
         b'index bf84e48..1be2436 644',
         b'--- a/changed.txt',
         b'+++ b/changed.txt',
         b'@@ -1,2 +1,2 @@',
         b' unchanged',
         b'-removed',
         b'+added',
         b'diff --git a/removed.txt /dev/null',
         b'deleted mode 644',
         b'index 2c3f0b3..0000000',
         b'--- a/removed.txt',
         b'+++ /dev/null',
         b'@@ -1 +0,0 @@',
         b'-removed',
     ],
                      f.getvalue().splitlines())
class GitFastExporterTests(TestCase):
    """Tests for the GitFastExporter tests."""
    def setUp(self):
        super(GitFastExporterTests, self).setUp()
        self.store = MemoryObjectStore()
        self.stream = BytesIO()
        try:
            from my_dulwich.fastexport import GitFastExporter
        except ImportError:
            raise SkipTest("python-fastimport not available")
        self.fastexporter = GitFastExporter(self.stream, self.store)

    def test_emit_blob(self):
        b = Blob()
        b.data = b"fooBAR"
        self.fastexporter.emit_blob(b)
        self.assertEqual(b'blob\nmark :1\ndata 6\nfooBAR\n',
                         self.stream.getvalue())

    def test_emit_commit(self):
        b = Blob()
        b.data = b"FOO"
        t = Tree()
        t.add(b"foo", stat.S_IFREG | 0o644, b.id)
        c = Commit()
        c.committer = c.author = b"Jelmer <jelmer@host>"
        c.author_time = c.commit_time = 1271345553
        c.author_timezone = c.commit_timezone = 0
        c.message = b"msg"
        c.tree = t.id
        self.store.add_objects([(b, None), (t, None), (c, None)])
        self.fastexporter.emit_commit(c, b"refs/heads/master")
        self.assertEqual(
            b"""blob
mark :1
data 3
FOO
commit refs/heads/master
mark :2
author Jelmer <jelmer@host> 1271345553 +0000
committer Jelmer <jelmer@host> 1271345553 +0000
data 3
msg
M 644 :1 foo
""", self.stream.getvalue())
 def test_empty(self):
     store = MemoryObjectStore()
     c1, c2, c3 = build_commit_graph(store, [[1], [2, 1], [3, 1, 2]])
     tree = store[c3.tree]
     stream = b''.join(tar_stream(store, tree, 10))
     out = BytesIO(stream)
     tf = tarfile.TarFile(fileobj=out)
     self.addCleanup(tf.close)
     self.assertEqual([], tf.getnames())
Beispiel #14
0
 def test_object_diff_bin_blob(self):
     f = BytesIO()
     # Prepare two slightly different PNG headers
     b1 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x04\x00\x00\x00\x05\x04\x8b")
     b2 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x03\x00\x00\x00\x98\xd3\xb3")
     store = MemoryObjectStore()
     store.add_objects([(b1, None), (b2, None)])
     write_object_diff(f, store, (b'foo.png', 0o644, b1.id),
                       (b'bar.png', 0o644, b2.id))
     self.assertEqual([
         b'diff --git a/foo.png b/bar.png', b'index f73e47d..06364b7 644',
         b'Binary files a/foo.png and b/bar.png differ'
     ],
                      f.getvalue().splitlines())
Beispiel #15
0
 def test_object_diff_kind_change(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"bar.txt", 0o644, b1.id),
                       (b"bar.txt", 0o160000,
                        b"06d0bdd9e2e20377b3180e4986b14c8549b393e4"))
     self.assertEqual([
         b'diff --git a/bar.txt b/bar.txt',
         b'old mode 644',
         b'new mode 160000',
         b'index a116b51..06d0bdd 160000',
         b'--- a/bar.txt',
         b'+++ b/bar.txt',
         b'@@ -1,2 +1 @@',
         b'-new',
         b'-same',
         b'+Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',
     ],
                      f.getvalue().splitlines())
Beispiel #16
0
 def test_tree_diff_submodule(self):
     f = BytesIO()
     store = MemoryObjectStore()
     tree1 = Tree()
     tree1.add(b"asubmodule", S_IFGITLINK,
               b"06d0bdd9e2e20377b3180e4986b14c8549b393e4")
     tree2 = Tree()
     tree2.add(b"asubmodule", S_IFGITLINK,
               b"cc975646af69f279396d4d5e1379ac6af80ee637")
     store.add_objects([(o, None) for o in [tree1, tree2]])
     write_tree_diff(f, store, tree1.id, tree2.id)
     self.assertEqual([
         b'diff --git a/asubmodule b/asubmodule',
         b'index 06d0bdd..cc97564 160000',
         b'--- a/asubmodule',
         b'+++ b/asubmodule',
         b'@@ -1 +1 @@',
         b'-Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',
         b'+Submodule commit cc975646af69f279396d4d5e1379ac6af80ee637',
     ],
                      f.getvalue().splitlines())
class DiffTestCase(TestCase):

    def setUp(self):
        super(DiffTestCase, self).setUp()
        self.store = MemoryObjectStore()
        self.empty_tree = self.commit_tree([])

    def commit_tree(self, entries):
        commit_blobs = []
        for entry in entries:
            if len(entry) == 2:
                path, obj = entry
                mode = F
            else:
                path, obj, mode = entry
            if isinstance(obj, Blob):
                self.store.add_object(obj)
                sha = obj.id
            else:
                sha = obj
            commit_blobs.append((path, sha, mode))
        return self.store[commit_tree(self.store, commit_blobs)]
 def _get_example_tar_stream(self, *tar_stream_args, **tar_stream_kwargs):
     store = MemoryObjectStore()
     b1 = Blob.from_string(b"somedata")
     store.add_object(b1)
     t1 = Tree()
     t1.add(b"somename", 0o100644, b1.id)
     store.add_object(t1)
     stream = b''.join(
         tar_stream(store, t1, *tar_stream_args, **tar_stream_kwargs))
     return BytesIO(stream)
class MissingObjectFinderTest(TestCase):
    def setUp(self):
        super(MissingObjectFinderTest, self).setUp()
        self.store = MemoryObjectStore()
        self.commits = []

    def cmt(self, n):
        return self.commits[n - 1]

    def assertMissingMatch(self, haves, wants, expected):
        for sha, path in self.store.find_missing_objects(haves, wants):
            self.assertTrue(
                sha in expected,
                "(%s,%s) erroneously reported as missing" % (sha, path))
            expected.remove(sha)

        self.assertEqual(
            len(expected), 0,
            "some objects are not reported as missing: %s" % (expected, ))
 def setUp(self):
     super(MissingObjectFinderTest, self).setUp()
     self.store = MemoryObjectStore()
     self.commits = []
Beispiel #21
0
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, b'commit'),
            (Blob.type_num, b'blob'),
            (Tree.type_num, b'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, b'blob'),
            (OFS_DELTA, (0, b'blob1')),
            (OFS_DELTA, (0, b'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, b'blob'),
            (OFS_DELTA, (0, b'blob1')),
            (OFS_DELTA, (1, b'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, b'blob1')),
            (Blob.type_num, (b'blob')),
            (REF_DELTA, (1, b'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, b'blob1')),
            (Blob.type_num, (b'blob')),
            (REF_DELTA, (1, b'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, b'blob1')),
            (Blob.type_num, (b'blob')),
            (OFS_DELTA, (1, b'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, b'blob'),
            (REF_DELTA, (2, b'blob2')),
            (OFS_DELTA, (0, b'blob1')),
            (OFS_DELTA, (1, b'blob3')),
            (OFS_DELTA, (0, b'bob')),
        ])
        self.assertEntriesMatch([0, 2, 4, 1, 3], entries,
                                self.make_pack_iter(f))

    def test_long_chain(self):
        n = 100
        objects_spec = [(Blob.type_num, b'blob')]
        for i in range(n):
            objects_spec.append(
                (OFS_DELTA, (i, b'blob' + str(i).encode('ascii'))))
        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, b'blob')]
        for i in range(n):
            objects_spec.append(
                (OFS_DELTA, (0, b'blob' + str(i).encode('ascii'))))
        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([b'blob'])
        f = BytesIO()
        entries = build_pack(f, [(REF_DELTA, (blob.id, b'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([b'blob'])
        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (1, b'blob2')),
            (REF_DELTA, (blob.id, b'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([b'blob'])
        blob2, = self.store_blobs([b'blob2'])
        assert blob.id < blob2.id

        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (blob.id, b'blob2')),
            (REF_DELTA, (0, b'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([b'blob'])
        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (blob.id, b'blob1')),
            (REF_DELTA, (blob.id, b'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([b'foo', b'bar'])
        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (b1.id, b'foo1')),
            (REF_DELTA, (b2.id, b'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([b'blob'])
        f = BytesIO()
        build_pack(f, [(REF_DELTA, (blob.id, b'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([b'foo', b'bar', b'baz'])
        f = BytesIO()
        build_pack(f, [
            (REF_DELTA, (1, b'foo99')),
            (REF_DELTA, (b1.id, b'foo1')),
            (REF_DELTA, (b2.id, b'bar2')),
            (REF_DELTA, (b3.id, b'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]), ))
Beispiel #22
0
 def setUp(self):
     super(DeltaChainIteratorTests, self).setUp()
     self.store = MemoryObjectStore()
     self.fetched = set()
 def setUp(self):
     super(DiffTestCase, self).setUp()
     self.store = MemoryObjectStore()
     self.empty_tree = self.commit_tree([])
Beispiel #24
0
 def setUp(self):
     super(TestGreenThreadsMissingObjectFinder, self).setUp()
     self.store = MemoryObjectStore()
     self.cmt_amount = 10
     self.objs = init_store(self.store, self.cmt_amount)
Beispiel #25
0
 def setUp(self):
     super(TestGreenThreadsObjectStoreIterator, self).setUp()
     self.store = MemoryObjectStore()
     self.cmt_amount = 10
     self.objs = init_store(self.store, self.cmt_amount)
 def setUp(self):
     super(BuildCommitGraphTest, self).setUp()
     self.store = MemoryObjectStore()
Beispiel #27
0
class WalkerTest(TestCase):
    def setUp(self):
        super(WalkerTest, self).setUp()
        self.store = MemoryObjectStore()

    def make_commits(self, commit_spec, **kwargs):
        times = kwargs.pop('times', [])
        attrs = kwargs.pop('attrs', {})
        for i, t in enumerate(times):
            attrs.setdefault(i + 1, {})['commit_time'] = t
        return build_commit_graph(self.store,
                                  commit_spec,
                                  attrs=attrs,
                                  **kwargs)

    def make_linear_commits(self, num_commits, **kwargs):
        commit_spec = []
        for i in range(1, num_commits + 1):
            c = [i]
            if i > 1:
                c.append(i - 1)
            commit_spec.append(c)
        return self.make_commits(commit_spec, **kwargs)

    def assertWalkYields(self, expected, *args, **kwargs):
        walker = Walker(self.store, *args, **kwargs)
        expected = list(expected)
        for i, entry in enumerate(expected):
            if isinstance(entry, Commit):
                expected[i] = TestWalkEntry(entry, None)
        actual = list(walker)
        self.assertEqual(expected, actual)

    def test_tag(self):
        c1, c2, c3 = self.make_linear_commits(3)
        t2 = make_tag(target=c2)
        self.store.add_object(t2)
        self.assertWalkYields([c2, c1], [t2.id])

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1], [c1.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c2, c1], [c3.id, c1.id])
        self.assertWalkYields([c3, c2], [c3.id], exclude=[c1.id])
        self.assertWalkYields([c3, c2], [c3.id, c1.id], exclude=[c1.id])
        self.assertWalkYields([c3], [c3.id, c1.id], exclude=[c2.id])

    def test_missing(self):
        cs = list(reversed(self.make_linear_commits(20)))
        self.assertWalkYields(cs, [cs[0].id])

        # Exactly how close we can get to a missing commit depends on our
        # implementation (in particular the choice of _MAX_EXTRA_COMMITS), but
        # we should at least be able to walk some history in a broken repo.
        del self.store[cs[-1].id]
        for i in range(1, 11):
            self.assertWalkYields(cs[:i], [cs[0].id], max_entries=i)
        self.assertRaises(MissingCommitError, Walker, self.store, [cs[-1].id])

    def test_branch(self):
        c1, x2, x3, y4 = self.make_commits([[1], [2, 1], [3, 2], [4, 1]])
        self.assertWalkYields([x3, x2, c1], [x3.id])
        self.assertWalkYields([y4, c1], [y4.id])
        self.assertWalkYields([y4, x2, c1], [y4.id, x2.id])
        self.assertWalkYields([y4, x2], [y4.id, x2.id], exclude=[c1.id])
        self.assertWalkYields([y4, x3], [y4.id, x3.id], exclude=[x2.id])
        self.assertWalkYields([y4], [y4.id], exclude=[x3.id])
        self.assertWalkYields([x3, x2], [x3.id], exclude=[y4.id])

    def test_merge(self):
        c1, c2, c3, c4 = self.make_commits([[1], [2, 1], [3, 1], [4, 2, 3]])
        self.assertWalkYields([c4, c3, c2, c1], [c4.id])
        self.assertWalkYields([c3, c1], [c3.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c4, c3], [c4.id], exclude=[c2.id])
        self.assertWalkYields([c4, c2], [c4.id], exclude=[c3.id])

    def test_reverse(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id], reverse=True)

    def test_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], max_entries=3)
        self.assertWalkYields([c3, c2], [c3.id], max_entries=2)
        self.assertWalkYields([c3], [c3.id], max_entries=1)

    def test_reverse_after_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id],
                              max_entries=3,
                              reverse=True)
        self.assertWalkYields([c2, c3], [c3.id], max_entries=2, reverse=True)
        self.assertWalkYields([c3], [c3.id], max_entries=1, reverse=True)

    def test_changes_one_parent(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_a2 = make_object(Blob, data=b'a2')
        blob_b2 = make_object(Blob, data=b'b2')
        c1, c2 = self.make_linear_commits(2,
                                          trees={
                                              1: [(b'a', blob_a1)],
                                              2: [(b'a', blob_a2),
                                                  (b'b', blob_b2)]
                                          })
        e1 = TestWalkEntry(c1, [TreeChange.add((b'a', F, blob_a1.id))])
        e2 = TestWalkEntry(c2, [
            TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id),
                       (b'a', F, blob_a2.id)),
            TreeChange.add((b'b', F, blob_b2.id))
        ])
        self.assertWalkYields([e2, e1], [c2.id])

    def test_changes_multiple_parents(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        c1, c2, c3 = self.make_commits(
            [[1], [2], [3, 1, 2]],
            trees={
                1: [(b'a', blob_a1)],
                2: [(b'b', blob_b2)],
                3: [(b'a', blob_a3), (b'b', blob_b2)]
            })
        # a is a modify/add conflict and b is not conflicted.
        changes = [[
            TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id),
                       (b'a', F, blob_a3.id)),
            TreeChange.add((b'a', F, blob_a3.id)),
        ]]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              exclude=[c1.id, c2.id])

    def test_path_matches(self):
        walker = Walker(None, [], paths=[b'foo', b'bar', b'baz/quux'])
        self.assertTrue(walker._path_matches(b'foo'))
        self.assertTrue(walker._path_matches(b'foo/a'))
        self.assertTrue(walker._path_matches(b'foo/a/b'))
        self.assertTrue(walker._path_matches(b'bar'))
        self.assertTrue(walker._path_matches(b'baz/quux'))
        self.assertTrue(walker._path_matches(b'baz/quux/a'))

        self.assertFalse(walker._path_matches(None))
        self.assertFalse(walker._path_matches(b'oops'))
        self.assertFalse(walker._path_matches(b'fool'))
        self.assertFalse(walker._path_matches(b'baz'))
        self.assertFalse(walker._path_matches(b'baz/quu'))

    def test_paths(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        blob_b3 = make_object(Blob, data=b'b3')
        c1, c2, c3 = self.make_linear_commits(3,
                                              trees={
                                                  1: [(b'a', blob_a1)],
                                                  2: [(b'a', blob_a1),
                                                      (b'x/b', blob_b2)],
                                                  3: [(b'a', blob_a3),
                                                      (b'x/b', blob_b3)]
                                              })

        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'a'])
        self.assertWalkYields([c3, c2], [c3.id], paths=[b'x/b'])

        # All changes are included, not just for requested paths.
        changes = [
            TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id),
                       (b'a', F, blob_a3.id)),
            TreeChange(CHANGE_MODIFY, (b'x/b', F, blob_b2.id),
                       (b'x/b', F, blob_b3.id)),
        ]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              max_entries=1,
                              paths=[b'a'])

    def test_paths_subtree(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2, c3 = self.make_linear_commits(3,
                                              trees={
                                                  1: [(b'x/a', blob_a)],
                                                  2: [(b'b', blob_b),
                                                      (b'x/a', blob_a)],
                                                  3: [(b'b', blob_b),
                                                      (b'x/a', blob_a),
                                                      (b'x/b', blob_b)]
                                              })
        self.assertWalkYields([c2], [c3.id], paths=[b'b'])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'x'])

    def test_paths_max_entries(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2 = self.make_linear_commits(2,
                                          trees={
                                              1: [(b'a', blob_a)],
                                              2: [(b'a', blob_a),
                                                  (b'b', blob_b)]
                                          })
        self.assertWalkYields([c2], [c2.id], paths=[b'b'], max_entries=1)
        self.assertWalkYields([c1], [c1.id], paths=[b'a'], max_entries=1)

    def test_paths_merge(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_a2 = make_object(Blob, data=b'a2')
        blob_a3 = make_object(Blob, data=b'a3')
        x1, y2, m3, m4 = self.make_commits(
            [[1], [2], [3, 1, 2], [4, 1, 2]],
            trees={
                1: [(b'a', blob_a1)],
                2: [(b'a', blob_a2)],
                3: [(b'a', blob_a3)],
                4: [(b'a', blob_a1)]
            })  # Non-conflicting
        self.assertWalkYields([m3, y2, x1], [m3.id], paths=[b'a'])
        self.assertWalkYields([y2, x1], [m4.id], paths=[b'a'])

    def test_changes_with_renames(self):
        blob = make_object(Blob, data=b'blob')
        c1, c2 = self.make_linear_commits(2,
                                          trees={
                                              1: [(b'a', blob)],
                                              2: [(b'b', blob)]
                                          })
        entry_a = (b'a', F, blob.id)
        entry_b = (b'b', F, blob.id)
        changes_without_renames = [
            TreeChange.delete(entry_a),
            TreeChange.add(entry_b)
        ]
        changes_with_renames = [TreeChange(CHANGE_RENAME, entry_a, entry_b)]
        self.assertWalkYields([TestWalkEntry(c2, changes_without_renames)],
                              [c2.id],
                              max_entries=1)
        detector = RenameDetector(self.store)
        self.assertWalkYields([TestWalkEntry(c2, changes_with_renames)],
                              [c2.id],
                              max_entries=1,
                              rename_detector=detector)

    def test_follow_rename(self):
        blob = make_object(Blob, data=b'blob')
        names = [b'a', b'a', b'b', b'b', b'c', b'c']

        trees = dict((i + 1, [(n, blob, F)]) for i, n in enumerate(names))
        c1, c2, c3, c4, c5, c6 = self.make_linear_commits(6, trees=trees)
        self.assertWalkYields([c5], [c6.id], paths=[b'c'])

        def e(n):
            return (n, F, blob.id)

        self.assertWalkYields([
            TestWalkEntry(c5, [TreeChange(CHANGE_RENAME, e(b'b'), e(b'c'))]),
            TestWalkEntry(c3, [TreeChange(CHANGE_RENAME, e(b'a'), e(b'b'))]),
            TestWalkEntry(c1, [TreeChange.add(e(b'a'))])
        ], [c6.id],
                              paths=[b'c'],
                              follow=True)

    def test_follow_rename_remove_path(self):
        blob = make_object(Blob, data=b'blob')
        _, _, _, c4, c5, c6 = self.make_linear_commits(6,
                                                       trees={
                                                           1: [(b'a', blob),
                                                               (b'c', blob)],
                                                           2: [],
                                                           3: [],
                                                           4: [(b'b', blob)],
                                                           5: [(b'a', blob)],
                                                           6: [(b'c', blob)]
                                                       })

        def e(n):
            return (n, F, blob.id)

        # Once the path changes to b, we aren't interested in a or c anymore.
        self.assertWalkYields([
            TestWalkEntry(c6, [TreeChange(CHANGE_RENAME, e(b'a'), e(b'c'))]),
            TestWalkEntry(c5, [TreeChange(CHANGE_RENAME, e(b'b'), e(b'a'))]),
            TestWalkEntry(c4, [TreeChange.add(e(b'b'))])
        ], [c6.id],
                              paths=[b'c'],
                              follow=True)

    def test_since(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=0)
        self.assertWalkYields([c3, c2], [c3.id], since=1)
        self.assertWalkYields([c3, c2], [c3.id], since=99)
        self.assertWalkYields([c3, c2], [c3.id], since=100)
        self.assertWalkYields([c3], [c3.id], since=101)
        self.assertWalkYields([c3], [c3.id], since=199)
        self.assertWalkYields([c3], [c3.id], since=200)
        self.assertWalkYields([], [c3.id], since=201)
        self.assertWalkYields([], [c3.id], since=300)

    def test_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], until=-1)
        self.assertWalkYields([c1], [c3.id], until=0)
        self.assertWalkYields([c1], [c3.id], until=1)
        self.assertWalkYields([c1], [c3.id], until=99)
        self.assertWalkYields([c2, c1], [c3.id], until=100)
        self.assertWalkYields([c2, c1], [c3.id], until=101)
        self.assertWalkYields([c2, c1], [c3.id], until=199)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=200)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=201)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=300)

    def test_since_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], since=100, until=99)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1, until=201)
        self.assertWalkYields([c2], [c3.id], since=100, until=100)
        self.assertWalkYields([c2], [c3.id], since=50, until=150)

    def test_since_over_scan(self):
        commits = self.make_linear_commits(
            11, times=[9, 0, 1, 2, 3, 4, 5, 8, 6, 7, 9])
        c8, _, c10, c11 = commits[-4:]
        del self.store[commits[0].id]
        # c9 is older than we want to walk, but is out of order with its
        # parent, so we need to walk past it to get to c8.
        # c1 would also match, but we've deleted it, and it should get pruned
        # even with over-scanning.
        self.assertWalkYields([c11, c10, c8], [c11.id], since=7)

    def assertTopoOrderEqual(self, expected_commits, commits):
        entries = [TestWalkEntry(c, None) for c in commits]
        actual_ids = [e.commit.id for e in list(_topo_reorder(entries))]
        self.assertEqual([c.id for c in expected_commits], actual_ids)

    def test_topo_reorder_linear(self):
        commits = self.make_linear_commits(5)
        commits.reverse()
        for perm in permutations(commits):
            self.assertTopoOrderEqual(commits, perm)

    def test_topo_reorder_multiple_parents(self):
        c1, c2, c3 = self.make_commits([[1], [2], [3, 1, 2]])
        # Already sorted, so totally FIFO.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c3, c1, c2])

        # c3 causes one parent to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c1, c3, c2])

        # c3 causes both parents to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c2, c3])
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c1, c3])

    def test_topo_reorder_multiple_children(self):
        c1, c2, c3 = self.make_commits([[1], [2, 1], [3, 1]])

        # c2 and c3 are FIFO but c1 moves to the end.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c1, c2])
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c3, c2])

        self.assertTopoOrderEqual([c2, c3, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c2, c3, c1], [c2, c1, c3])
        self.assertTopoOrderEqual([c2, c3, c1], [c1, c2, c3])

    def test_out_of_order_children(self):
        c1, c2, c3, c4, c5 = self.make_commits(
            [[1], [2, 1], [3, 2], [4, 1], [5, 3, 4]], times=[2, 1, 3, 4, 5])
        self.assertWalkYields([c5, c4, c3, c1, c2], [c5.id])
        self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id], order=ORDER_TOPO)

    def test_out_of_order_with_exclude(self):
        # Create the following graph:
        # c1-------x2---m6
        #   \          /
        #    \-y3--y4-/--y5
        # Due to skew, y5 is the oldest commit.
        c1, x2, y3, y4, y5, m6 = self.make_commits(
            [[1], [2, 1], [3, 1], [4, 3], [5, 4], [6, 2, 4]],
            times=[2, 3, 4, 5, 1, 6])
        self.assertWalkYields([m6, y4, y3, x2, c1], [m6.id])
        # Ensure that c1..y4 get excluded even though they're popped from the
        # priority queue long before y5.
        self.assertWalkYields([m6, x2], [m6.id], exclude=[y5.id])

    def test_empty_walk(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], exclude=[c3.id])
Beispiel #28
0
 def setUp(self):
     super(FindShallowTests, self).setUp()
     self._store = MemoryObjectStore()
Beispiel #29
0
class FindShallowTests(TestCase):
    def setUp(self):
        super(FindShallowTests, self).setUp()
        self._store = MemoryObjectStore()

    def make_commit(self, **attrs):
        commit = make_commit(**attrs)
        self._store.add_object(commit)
        return commit

    def make_linear_commits(self, n, message=b''):
        commits = []
        parents = []
        for _ in range(n):
            commits.append(self.make_commit(parents=parents, message=message))
            parents = [commits[-1].id]
        return commits

    def assertSameElements(self, expected, actual):
        self.assertEqual(set(expected), set(actual))

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)

        self.assertEqual((set([c3.id]), set([])),
                         _find_shallow(self._store, [c3.id], 1))
        self.assertEqual((set([c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 2))
        self.assertEqual((set([c1.id]), set([c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 3))
        self.assertEqual((set([]), set([c1.id, c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 4))

    def test_multiple_independent(self):
        a = self.make_linear_commits(2, message=b'a')
        b = self.make_linear_commits(2, message=b'b')
        c = self.make_linear_commits(2, message=b'c')
        heads = [a[1].id, b[1].id, c[1].id]

        self.assertEqual((set([a[0].id, b[0].id, c[0].id]), set(heads)),
                         _find_shallow(self._store, heads, 2))

    def test_multiple_overlapping(self):
        # Create the following commit tree:
        # 1--2
        #  \
        #   3--4
        c1, c2 = self.make_linear_commits(2)
        c3 = self.make_commit(parents=[c1.id])
        c4 = self.make_commit(parents=[c3.id])

        # 1 is shallow along the path from 4, but not along the path from 2.
        self.assertEqual((set([c1.id]), set([c1.id, c2.id, c3.id, c4.id])),
                         _find_shallow(self._store, [c2.id, c4.id], 3))

    def test_merge(self):
        c1 = self.make_commit()
        c2 = self.make_commit()
        c3 = self.make_commit(parents=[c1.id, c2.id])

        self.assertEqual((set([c1.id, c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 2))

    def test_tag(self):
        c1, c2 = self.make_linear_commits(2)
        tag = make_tag(c2, name=b'tag')
        self._store.add_object(tag)

        self.assertEqual((set([c1.id]), set([c2.id])),
                         _find_shallow(self._store, [tag.id], 2))
Beispiel #30
0
 def setUp(self):
     super(WalkerTest, self).setUp()
     self.store = MemoryObjectStore()