Hash :
ffd264d9
Author :
Date :
2017-05-03T14:51:23
tests: repo: fix repo discovery tests on overlayfs Debian and Ubuntu often use schroot to build their DEB packages in a controlled environment. Depending on how schroot is configured, our tests regarding repository discovery break due to not being able to find the repositories anymore. It turns out that these errors occur when the schroot is configured to use an overlayfs on the directory structures. The reason for this failure is that we usually refrain from discovering repositories across devices. But unfortunately, overlayfs does not have consistent device identifiers for all its files but will instead use the device number of the filesystem the file stems from. So whenever we cross boundaries between the upper and lower layer of the overlay, we will fail to properly detect the repository and bail out. This commit fixes the issue by enabling cross-device discovery in our tests. While it would be preferable to have this turned off, it probably won't do much harm anyway as we set up our tests in a temporary location outside of the parent repository.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
#include "clar_libgit2.h"
#include "odb.h"
#include "fileops.h"
#include "repository.h"
#define TEMP_REPO_FOLDER "temprepo/"
#define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git"
#define SUB_REPOSITORY_FOLDER_NAME "sub_repo"
#define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME
#define SUB_REPOSITORY_GITDIR SUB_REPOSITORY_FOLDER "/.git"
#define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub"
#define REPOSITORY_ALTERNATE_FOLDER DISCOVER_FOLDER "/alternate_sub_repo"
#define REPOSITORY_ALTERNATE_FOLDER_SUB REPOSITORY_ALTERNATE_FOLDER "/sub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB "/subsub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/subsubsub"
#define ALTERNATE_MALFORMED_FOLDER1 DISCOVER_FOLDER "/alternate_malformed_repo1"
#define ALTERNATE_MALFORMED_FOLDER2 DISCOVER_FOLDER "/alternate_malformed_repo2"
#define ALTERNATE_MALFORMED_FOLDER3 DISCOVER_FOLDER "/alternate_malformed_repo3"
#define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo"
static void ensure_repository_discover(const char *start_path,
const char *ceiling_dirs,
const char *expected_path)
{
git_buf found_path = GIT_BUF_INIT, resolved = GIT_BUF_INIT;
git_buf_attach(&resolved, p_realpath(expected_path, NULL), 0);
cl_assert(resolved.size > 0);
cl_git_pass(git_path_to_dir(&resolved));
cl_git_pass(git_repository_discover(&found_path, start_path, 1, ceiling_dirs));
cl_assert_equal_s(found_path.ptr, resolved.ptr);
git_buf_free(&resolved);
git_buf_free(&found_path);
}
static void write_file(const char *path, const char *content)
{
git_file file;
int error;
if (git_path_exists(path)) {
cl_git_pass(p_unlink(path));
}
file = git_futils_creat_withpath(path, 0777, 0666);
cl_assert(file >= 0);
error = p_write(file, content, strlen(content) * sizeof(char));
p_close(file);
cl_git_pass(error);
}
//no check is performed on ceiling_dirs length, so be sure it's long enough
static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path)
{
git_buf pretty_path = GIT_BUF_INIT;
char ceiling_separator[2] = { GIT_PATH_LIST_SEPARATOR, '\0' };
cl_git_pass(git_path_prettify_dir(&pretty_path, path, NULL));
if (ceiling_dirs->size > 0)
git_buf_puts(ceiling_dirs, ceiling_separator);
git_buf_puts(ceiling_dirs, pretty_path.ptr);
git_buf_free(&pretty_path);
cl_assert(git_buf_oom(ceiling_dirs) == 0);
}
static git_buf discovered;
static git_buf ceiling_dirs;
void test_repo_discover__initialize(void)
{
git_repository *repo;
const mode_t mode = 0777;
git_futils_mkdir_r(DISCOVER_FOLDER, mode);
git_buf_init(&discovered, 0);
git_buf_init(&ceiling_dirs, 0);
append_ceiling_dir(&ceiling_dirs, TEMP_REPO_FOLDER);
cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1));
git_repository_free(repo);
cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0));
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode));
write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT);
write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, mode));
write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, mode));
write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, mode));
write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n");
cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, mode));
write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist");
git_repository_free(repo);
}
void test_repo_discover__cleanup(void)
{
git_buf_free(&discovered);
git_buf_free(&ceiling_dirs);
cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_repo_discover__discovering_repo_with_exact_path_succeeds(void)
{
cl_git_pass(git_repository_discover(&discovered, DISCOVER_FOLDER, 0, ceiling_dirs.ptr));
cl_git_pass(git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs.ptr));
}
void test_repo_discover__discovering_nonexistent_dir_fails(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, DISCOVER_FOLDER "-nonexistent", 0, NULL));
}
void test_repo_discover__discovering_repo_with_subdirectory_succeeds(void)
{
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
}
void test_repo_discover__discovering_repository_with_alternative_gitdir_succeeds(void)
{
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
}
void test_repo_discover__discovering_repository_with_malformed_alternative_gitdir_fails(void)
{
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs.ptr));
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs.ptr));
cl_git_fail(git_repository_discover(&discovered, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs.ptr));
}
void test_repo_discover__discovering_repository_with_ceiling(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER_SUB);
/* this must pass as ceiling_directories cannot prevent the current
* working directory to be checked */
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
}
void test_repo_discover__other_ceiling(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
/* this must pass as ceiling_directories cannot predent the current
* working directory to be checked */
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs.ptr));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&discovered, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs.ptr));
}
void test_repo_discover__ceiling_should_not_affect_gitdir_redirection(void)
{
append_ceiling_dir(&ceiling_dirs, SUB_REPOSITORY_FOLDER);
/* gitfile redirection should not be affected by ceiling directories */
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs.ptr, DISCOVER_FOLDER);
}
void test_repo_discover__discovery_starting_at_file_succeeds(void)
{
int fd;
cl_assert((fd = p_creat(SUB_REPOSITORY_FOLDER "/file", 0600)) >= 0);
cl_assert(p_close(fd) == 0);
ensure_repository_discover(SUB_REPOSITORY_FOLDER "/file", ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR);
}
void test_repo_discover__discovery_starting_at_system_root_causes_no_hang(void)
{
#ifdef GIT_WIN32
git_buf out = GIT_BUF_INIT;
cl_git_fail(git_repository_discover(&out, "C:/", 0, NULL));
cl_git_fail(git_repository_discover(&out, "//localhost/", 0, NULL));
#endif
}