From 2add34d0fbe47e44d17912e2431f57c6935026ef Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 12 Jun 2017 14:53:46 +0200 Subject: [PATCH 1/4] tests: odb: move fake backend into its own file The fake backend used by the test suite `odb::backend::nonrefreshing` is useful to have some low-level tests for the ODB layer. As such, we move the implementation into its own `backend_helpers` module. --- tests/odb/backend/backend_helpers.c | 119 ++++++++++++++++++++++ tests/odb/backend/backend_helpers.h | 18 ++++ tests/odb/backend/nonrefreshing.c | 149 +++------------------------- 3 files changed, 149 insertions(+), 137 deletions(-) create mode 100644 tests/odb/backend/backend_helpers.c create mode 100644 tests/odb/backend/backend_helpers.h diff --git a/tests/odb/backend/backend_helpers.c b/tests/odb/backend/backend_helpers.c new file mode 100644 index 000000000..21b33b939 --- /dev/null +++ b/tests/odb/backend/backend_helpers.c @@ -0,0 +1,119 @@ +#include "clar_libgit2.h" +#include "git2/sys/odb_backend.h" +#include "backend_helpers.h" + +static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) +{ + fake_backend *fake; + + GIT_UNUSED(oid); + + fake = (fake_backend *)backend; + + fake->exists_calls++; + + return (fake->error_code == GIT_OK); +} + +static int fake_backend__read( + void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + fake_backend *fake; + + GIT_UNUSED(buffer_p); + GIT_UNUSED(len_p); + GIT_UNUSED(type_p); + GIT_UNUSED(oid); + + fake = (fake_backend *)backend; + + fake->read_calls++; + + *len_p = 0; + *buffer_p = NULL; + *type_p = GIT_OBJ_BLOB; + + return fake->error_code; +} + +static int fake_backend__read_header( + size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + fake_backend *fake; + + GIT_UNUSED(len_p); + GIT_UNUSED(type_p); + GIT_UNUSED(oid); + + fake = (fake_backend *)backend; + + fake->read_header_calls++; + + *len_p = 0; + *type_p = GIT_OBJ_BLOB; + + return fake->error_code; +} + +static int fake_backend__read_prefix( + git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *short_oid, size_t len) +{ + fake_backend *fake; + + GIT_UNUSED(buffer_p); + GIT_UNUSED(len_p); + GIT_UNUSED(type_p); + GIT_UNUSED(short_oid); + GIT_UNUSED(len); + + fake = (fake_backend *)backend; + + fake->read_prefix_calls++; + + git_oid_cpy(out_oid, &fake->oid); + *len_p = 0; + *buffer_p = NULL; + *type_p = GIT_OBJ_BLOB; + + return fake->error_code; +} + +static void fake_backend__free(git_odb_backend *_backend) +{ + fake_backend *backend; + + backend = (fake_backend *)_backend; + + git__free(backend); +} + +int build_fake_backend( + git_odb_backend **out, + git_error_code error_code, + const git_oid *oid) +{ + fake_backend *backend; + + backend = git__calloc(1, sizeof(fake_backend)); + GITERR_CHECK_ALLOC(backend); + + backend->parent.version = GIT_ODB_BACKEND_VERSION; + + backend->parent.refresh = NULL; + backend->error_code = error_code; + + backend->parent.read = fake_backend__read; + backend->parent.read_prefix = fake_backend__read_prefix; + backend->parent.read_header = fake_backend__read_header; + backend->parent.exists = fake_backend__exists; + backend->parent.free = &fake_backend__free; + + git_oid_cpy(&backend->oid, oid); + + *out = (git_odb_backend *)backend; + + return 0; +} diff --git a/tests/odb/backend/backend_helpers.h b/tests/odb/backend/backend_helpers.h new file mode 100644 index 000000000..04bd844b2 --- /dev/null +++ b/tests/odb/backend/backend_helpers.h @@ -0,0 +1,18 @@ +#include "git2/sys/odb_backend.h" + +typedef struct { + git_odb_backend parent; + + git_error_code error_code; + git_oid oid; + + int exists_calls; + int read_calls; + int read_header_calls; + int read_prefix_calls; +} fake_backend; + +int build_fake_backend( + git_odb_backend **out, + git_error_code error_code, + const git_oid *oid); diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c index f12ac741c..efc285a6f 100644 --- a/tests/odb/backend/nonrefreshing.c +++ b/tests/odb/backend/nonrefreshing.c @@ -1,153 +1,28 @@ #include "clar_libgit2.h" -#include "git2/sys/odb_backend.h" #include "repository.h" - -typedef struct fake_backend { - git_odb_backend parent; - - git_error_code error_code; - - int exists_calls; - int read_calls; - int read_header_calls; - int read_prefix_calls; -} fake_backend; +#include "backend_helpers.h" static git_repository *_repo; static fake_backend *_fake; -static git_oid _oid; #define HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" #define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" -static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->exists_calls++; - - return (fake->error_code == GIT_OK); -} - -static int fake_backend__read( - void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_calls++; - - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_header( - size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_header_calls++; - - *len_p = 0; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_prefix( - git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *short_oid, size_t len) -{ - fake_backend *fake; - - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(short_oid); - GIT_UNUSED(len); - - fake = (fake_backend *)backend; - - fake->read_prefix_calls++; - - git_oid_cpy(out_oid, &_oid); - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static void fake_backend__free(git_odb_backend *_backend) -{ - fake_backend *backend; - - backend = (fake_backend *)_backend; - - git__free(backend); -} - -static int build_fake_backend( - git_odb_backend **out, - git_error_code error_code) -{ - fake_backend *backend; - - backend = git__calloc(1, sizeof(fake_backend)); - GITERR_CHECK_ALLOC(backend); - - backend->parent.version = GIT_ODB_BACKEND_VERSION; - - backend->parent.refresh = NULL; - backend->error_code = error_code; - - backend->parent.read = fake_backend__read; - backend->parent.read_prefix = fake_backend__read_prefix; - backend->parent.read_header = fake_backend__read_header; - backend->parent.exists = fake_backend__exists; - backend->parent.free = &fake_backend__free; - - *out = (git_odb_backend *)backend; - - return 0; -} - static void setup_repository_and_backend(git_error_code error_code, const char *hash) { git_odb *odb = NULL; git_odb_backend *backend = NULL; + git_oid oid; _repo = cl_git_sandbox_init("testrepo.git"); - cl_git_pass(build_fake_backend(&backend, error_code)); + cl_git_pass(git_oid_fromstr(&oid, hash)); + cl_git_pass(build_fake_backend(&backend, error_code, &oid)); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_pass(git_odb_add_backend(odb, backend, 10)); _fake = (fake_backend *)backend; - - cl_git_pass(git_oid_fromstr(&_oid, hash)); } void test_odb_backend_nonrefreshing__cleanup(void) @@ -162,7 +37,7 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(false, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(false, git_odb_exists(odb, &_fake->oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -174,7 +49,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_fail_with( - git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY), + git_object_lookup(&obj, _repo, &_fake->oid, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_calls); @@ -187,7 +62,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_fail_with( - git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY), + git_object_lookup_prefix(&obj, _repo, &_fake->oid, 7, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -204,7 +79,7 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void) cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_fail_with( - git_odb_read_header(&len, &type, odb, &_oid), + git_odb_read_header(&len, &type, odb, &_fake->oid), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_header_calls); @@ -217,7 +92,7 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, HASH); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(true, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(true, git_odb_exists(odb, &_fake->oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -228,7 +103,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, EMPTY_HASH); - cl_git_pass(git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup(&obj, _repo, &_fake->oid, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_calls); @@ -241,7 +116,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, EMPTY_HASH); - cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_fake->oid, 7, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -258,7 +133,7 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void) cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid)); + cl_git_pass(git_odb_read_header(&len, &type, odb, &_fake->oid)); cl_assert_equal_i(1, _fake->read_header_calls); } From 369cb45fc300e6a7951c5c9a65bbf0c0f6f32f16 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 12 Jun 2017 15:21:58 +0200 Subject: [PATCH 2/4] tests: do not reuse OID from backend In order to make the fake backend more useful, we want to enable it holding multiple object references. To do so, we need to decouple it from the single fake OID it currently holds, which we simply move up into the calling tests. --- tests/odb/backend/nonrefreshing.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c index efc285a6f..42da31201 100644 --- a/tests/odb/backend/nonrefreshing.c +++ b/tests/odb/backend/nonrefreshing.c @@ -8,6 +8,9 @@ static fake_backend *_fake; #define HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" #define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" +static git_oid _oid; +static git_oid _empty_oid; + static void setup_repository_and_backend(git_error_code error_code, const char *hash) { git_odb *odb = NULL; @@ -25,6 +28,12 @@ static void setup_repository_and_backend(git_error_code error_code, const char * _fake = (fake_backend *)backend; } +void test_odb_backend_nonrefreshing__initialize(void) +{ + git_oid_fromstr(&_oid, HASH); + git_oid_fromstr(&_empty_oid, EMPTY_HASH); +} + void test_odb_backend_nonrefreshing__cleanup(void) { cl_git_sandbox_cleanup(); @@ -37,7 +46,7 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(false, git_odb_exists(odb, &_fake->oid)); + cl_assert_equal_b(false, git_odb_exists(odb, &_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -49,7 +58,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_fail_with( - git_object_lookup(&obj, _repo, &_fake->oid, GIT_OBJ_ANY), + git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_calls); @@ -62,7 +71,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void) setup_repository_and_backend(GIT_ENOTFOUND, HASH); cl_git_fail_with( - git_object_lookup_prefix(&obj, _repo, &_fake->oid, 7, GIT_OBJ_ANY), + git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -79,7 +88,7 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void) cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_fail_with( - git_odb_read_header(&len, &type, odb, &_fake->oid), + git_odb_read_header(&len, &type, odb, &_oid), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_header_calls); @@ -92,7 +101,7 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, HASH); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(true, git_odb_exists(odb, &_fake->oid)); + cl_assert_equal_b(true, git_odb_exists(odb, &_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -103,7 +112,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, EMPTY_HASH); - cl_git_pass(git_object_lookup(&obj, _repo, &_fake->oid, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup(&obj, _repo, &_empty_oid, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_calls); @@ -116,7 +125,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void) setup_repository_and_backend(GIT_OK, EMPTY_HASH); - cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_fake->oid, 7, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_empty_oid, 7, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -133,7 +142,7 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void) cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_git_pass(git_odb_read_header(&len, &type, odb, &_fake->oid)); + cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid)); cl_assert_equal_i(1, _fake->read_header_calls); } From 6e010bb126360d084b1c38056728c7fd3286a443 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 12 Jun 2017 15:43:56 +0200 Subject: [PATCH 3/4] tests: odb: allow passing fake objects to the fake backend Right now, the fake backend is quite restrained in the way how it works: we pass it an OID which it is to return later as well as an error code we want it to return. While this is sufficient for existing tests, we can make the fake backend a little bit more generic in order to allow us testing for additional scenarios. To do so, we change the backend to not accept an error code and OID which it is to return for queries, but instead a simple array of OIDs with their respective blob contents. On each query, the fake backend simply iterates through this array and returns the first matching object. --- tests/odb/backend/backend_helpers.c | 83 +++++++++++++++++------------ tests/odb/backend/backend_helpers.h | 13 +++-- tests/odb/backend/nonrefreshing.c | 58 ++++++++------------ 3 files changed, 78 insertions(+), 76 deletions(-) diff --git a/tests/odb/backend/backend_helpers.c b/tests/odb/backend/backend_helpers.c index 21b33b939..26537029d 100644 --- a/tests/odb/backend/backend_helpers.c +++ b/tests/odb/backend/backend_helpers.c @@ -2,83 +2,99 @@ #include "git2/sys/odb_backend.h" #include "backend_helpers.h" +static int search_object(const fake_object **out, fake_backend *fake, const git_oid *oid, size_t len) +{ + const fake_object *obj = fake->objects; + + while (obj && obj->oid) { + git_oid current_oid; + + git_oid_fromstr(¤t_oid, obj->oid); + + if (git_oid_ncmp(¤t_oid, oid, len) == 0) { + if (out) + *out = obj; + return 0; + } + + obj++; + } + + return GIT_ENOTFOUND; +} + static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) { fake_backend *fake; - GIT_UNUSED(oid); - fake = (fake_backend *)backend; fake->exists_calls++; - return (fake->error_code == GIT_OK); + return search_object(NULL, fake, oid, GIT_OID_RAWSZ) == GIT_OK; } static int fake_backend__read( void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { + const fake_object *obj; fake_backend *fake; - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - fake = (fake_backend *)backend; fake->read_calls++; - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; + if (search_object(&obj, fake, oid, GIT_OID_RAWSZ) == 0) { + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + return 0; + } - return fake->error_code; + return GIT_ENOTFOUND; } static int fake_backend__read_header( size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { + const fake_object *obj; fake_backend *fake; - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - fake = (fake_backend *)backend; fake->read_header_calls++; - *len_p = 0; - *type_p = GIT_OBJ_BLOB; + if (search_object(&obj, fake, oid, GIT_OID_RAWSZ) == 0) { + *len_p = strlen(obj->content); + *type_p = GIT_OBJ_BLOB; + return 0; + } - return fake->error_code; + return GIT_ENOTFOUND; } static int fake_backend__read_prefix( git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *short_oid, size_t len) { + const fake_object *obj; fake_backend *fake; - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(short_oid); - GIT_UNUSED(len); - fake = (fake_backend *)backend; fake->read_prefix_calls++; - git_oid_cpy(out_oid, &fake->oid); - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; + if (search_object(&obj, fake, short_oid, len) == 0) { + git_oid_fromstr(out_oid, obj->oid); + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + return 0; + } - return fake->error_code; + return GIT_ENOTFOUND; } static void fake_backend__free(git_odb_backend *_backend) @@ -92,8 +108,7 @@ static void fake_backend__free(git_odb_backend *_backend) int build_fake_backend( git_odb_backend **out, - git_error_code error_code, - const git_oid *oid) + const fake_object *objects) { fake_backend *backend; @@ -103,7 +118,7 @@ int build_fake_backend( backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->parent.refresh = NULL; - backend->error_code = error_code; + backend->objects = objects; backend->parent.read = fake_backend__read; backend->parent.read_prefix = fake_backend__read_prefix; @@ -111,8 +126,6 @@ int build_fake_backend( backend->parent.exists = fake_backend__exists; backend->parent.free = &fake_backend__free; - git_oid_cpy(&backend->oid, oid); - *out = (git_odb_backend *)backend; return 0; diff --git a/tests/odb/backend/backend_helpers.h b/tests/odb/backend/backend_helpers.h index 04bd844b2..6cc1ce90d 100644 --- a/tests/odb/backend/backend_helpers.h +++ b/tests/odb/backend/backend_helpers.h @@ -1,18 +1,21 @@ #include "git2/sys/odb_backend.h" typedef struct { - git_odb_backend parent; + const char *oid; + const char *content; +} fake_object; - git_error_code error_code; - git_oid oid; +typedef struct { + git_odb_backend parent; int exists_calls; int read_calls; int read_header_calls; int read_prefix_calls; + + const fake_object *objects; } fake_backend; int build_fake_backend( git_odb_backend **out, - git_error_code error_code, - const git_oid *oid); + const fake_object *objects); diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c index 42da31201..6abc0c6d2 100644 --- a/tests/odb/backend/nonrefreshing.c +++ b/tests/odb/backend/nonrefreshing.c @@ -5,22 +5,25 @@ static git_repository *_repo; static fake_backend *_fake; -#define HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" -#define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" +#define NONEXISTING_HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" +#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" -static git_oid _oid; -static git_oid _empty_oid; +static const fake_object _objects[] = { + { EXISTING_HASH, "" }, + { NULL, NULL } +}; -static void setup_repository_and_backend(git_error_code error_code, const char *hash) +static git_oid _nonexisting_oid; +static git_oid _existing_oid; + +static void setup_repository_and_backend(void) { git_odb *odb = NULL; git_odb_backend *backend = NULL; - git_oid oid; _repo = cl_git_sandbox_init("testrepo.git"); - cl_git_pass(git_oid_fromstr(&oid, hash)); - cl_git_pass(build_fake_backend(&backend, error_code, &oid)); + cl_git_pass(build_fake_backend(&backend, _objects)); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_pass(git_odb_add_backend(odb, backend, 10)); @@ -30,8 +33,9 @@ static void setup_repository_and_backend(git_error_code error_code, const char * void test_odb_backend_nonrefreshing__initialize(void) { - git_oid_fromstr(&_oid, HASH); - git_oid_fromstr(&_empty_oid, EMPTY_HASH); + git_oid_fromstr(&_nonexisting_oid, NONEXISTING_HASH); + git_oid_fromstr(&_existing_oid, EXISTING_HASH); + setup_repository_and_backend(); } void test_odb_backend_nonrefreshing__cleanup(void) @@ -43,10 +47,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void) { git_odb *odb; - setup_repository_and_backend(GIT_ENOTFOUND, HASH); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(false, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(false, git_odb_exists(odb, &_nonexisting_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -55,10 +57,8 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND, HASH); - cl_git_fail_with( - git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY), + git_object_lookup(&obj, _repo, &_nonexisting_oid, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_calls); @@ -68,10 +68,8 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND, HASH); - cl_git_fail_with( - git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY), + git_object_lookup_prefix(&obj, _repo, &_nonexisting_oid, 7, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -83,12 +81,10 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_ENOTFOUND, HASH); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_fail_with( - git_odb_read_header(&len, &type, odb, &_oid), + git_odb_read_header(&len, &type, odb, &_nonexisting_oid), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_header_calls); @@ -98,10 +94,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void) { git_odb *odb; - setup_repository_and_backend(GIT_OK, HASH); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(true, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(true, git_odb_exists(odb, &_existing_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -110,9 +104,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK, EMPTY_HASH); - - cl_git_pass(git_object_lookup(&obj, _repo, &_empty_oid, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup(&obj, _repo, &_existing_oid, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_calls); @@ -123,9 +115,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK, EMPTY_HASH); - - cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_empty_oid, 7, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_existing_oid, 7, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -138,11 +128,9 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_OK, HASH); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid)); + cl_git_pass(git_odb_read_header(&len, &type, odb, &_existing_oid)); cl_assert_equal_i(1, _fake->read_header_calls); } @@ -151,8 +139,6 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_when_revparsing_a_full { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND, HASH); - cl_git_fail_with( git_revparse_single(&obj, _repo, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), GIT_ENOTFOUND); From f148258a35e17d8eacfb91c32ca2b74503e946f0 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 12 Jun 2017 16:19:45 +0200 Subject: [PATCH 4/4] 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. --- tests/odb/backend/multiple.c | 121 +++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 tests/odb/backend/multiple.c diff --git a/tests/odb/backend/multiple.c b/tests/odb/backend/multiple.c new file mode 100644 index 000000000..1c6068df3 --- /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); +}