Commit f148258a35e17d8eacfb91c32ca2b74503e946f0

Patrick Steinhardt 2017-06-12T16:19:45

tests: odb: add tests with multiple backends Previous to pulling out and extending the fake backend, it was quite cumbersome to write tests for very specific scenarios regarding backends. But as we have made it more generic, it has become much easier to do so. As such, this commit adds multiple tests for scenarios with multiple backends for the ODB. The changes also include a test for a very targeted scenario. When one backend found a matching object via `read_prefix`, but the last backend returns `GIT_ENOTFOUND` and when object hash verification is turned off, we fail to reset the error code to `GIT_OK`. This causes us to segfault later on, when doing a double-free on the returned object.

diff --git a/tests/odb/backend/multiple.c b/tests/odb/backend/multiple.c
new file mode 100644
index 0000000..1c6068d
--- /dev/null
+++ b/tests/odb/backend/multiple.c
@@ -0,0 +1,121 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "backend_helpers.h"
+
+#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
+
+static git_repository *_repo;
+static git_odb_object *_obj;
+static fake_backend *_fake_empty;
+static fake_backend *_fake_filled;
+
+static git_oid _existing_oid;
+
+static const fake_object _objects_filled[] = {
+	{ EXISTING_HASH, "" },
+	{ NULL, NULL }
+};
+
+static const fake_object _objects_empty[] = {
+	{ NULL, NULL }
+};
+
+void test_odb_backend_multiple__initialize(void)
+{
+	git_odb_backend *backend;
+
+	git_oid_fromstr(&_existing_oid, EXISTING_HASH);
+
+	_obj = NULL;
+	_repo = cl_git_sandbox_init("testrepo.git");
+
+	cl_git_pass(build_fake_backend(&backend, _objects_filled));
+	_fake_filled = (fake_backend *)backend;
+
+	cl_git_pass(build_fake_backend(&backend, _objects_empty));
+	_fake_empty = (fake_backend *)backend;
+}
+
+void test_odb_backend_multiple__cleanup(void)
+{
+	git_odb_object_free(_obj);
+	cl_git_sandbox_cleanup();
+}
+
+void test_odb_backend_multiple__read_with_empty_first_succeeds(void)
+{
+	git_odb *odb;
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50));
+
+	cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid));
+
+	cl_assert_equal_i(1, _fake_filled->read_calls);
+	cl_assert_equal_i(1, _fake_empty->read_calls);
+}
+
+void test_odb_backend_multiple__read_with_first_matching_stops(void)
+{
+	git_odb *odb;
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 10));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+	cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid));
+
+	cl_assert_equal_i(1, _fake_filled->read_calls);
+	cl_assert_equal_i(0, _fake_empty->read_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_empty_succeeds(void)
+{
+	git_odb *odb;
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50));
+
+	cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+	cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+	cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_matching_reads_both(void)
+{
+	git_odb *odb;
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+	cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+	cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+	cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+}
+
+void test_odb_backend_multiple__read_prefix_with_first_matching_succeeds_without_hash_verification(void)
+{
+	git_odb *odb;
+
+	git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0);
+
+	cl_git_pass(git_repository_odb__weakptr(&odb, _repo));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10));
+	cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50));
+
+	cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7));
+
+	/*
+	 * Both backends should be checked as we have to check
+	 * for collisions
+	 */
+	cl_assert_equal_i(1, _fake_filled->read_prefix_calls);
+	cl_assert_equal_i(1, _fake_empty->read_prefix_calls);
+
+	git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1);
+}