From: Alberto Leiva Popper Date: Tue, 16 Jul 2024 18:19:28 +0000 (-0600) Subject: Tuesday X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f5251d0261b801db30b5685787428189f2c86af5;p=thirdparty%2FFORT-validator.git Tuesday --- diff --git a/src/cache/local_cache.c b/src/cache/local_cache.c index ccc8e7fe..2aa72671 100644 --- a/src/cache/local_cache.c +++ b/src/cache/local_cache.c @@ -30,6 +30,8 @@ /* XXX force RRDP if one RPP fails to validate by rsync? */ +typedef int (*dl_cb)(struct cache_node *rpp); + struct cached_file { char *url; char *path; @@ -558,23 +560,41 @@ dl_rsync(struct cache_node *rpp) return 0; } -/* static int dl_http(struct cache_node *node) { + char *path; + bool changed; + int error; + if (!config_get_http_enabled()) { pr_val_debug("HTTP is disabled."); return 1; } - return http_download_cache_node(node); + error = cache_tmpfile(&path); + if (error) + return error; + + error = http_download(node->url, path, node->mtim, &changed); + if (error) { + free(path); + return error; + } + + node->flags |= CNF_CACHED | CNF_FRESH; // XXX on notification, preserve node but not file + if (changed) { + node->flags |= CNF_CHANGED; + node->mtim = time(NULL); // XXX catch -1 + } + node->tmpdir = path; + return 0; } -*/ /* @uri is either a caRepository or a rpkiNotify */ static int -try_uri(char const *uri, int (*download)(struct cache_node *), - maps_dl_cb validate, void *arg) +try_uri(char const *uri, struct cache_node *root, + dl_cb download, maps_dl_cb validate, void *arg) { struct cache_node *rpp; int error; @@ -584,7 +604,7 @@ try_uri(char const *uri, int (*download)(struct cache_node *), pr_val_debug("Trying %s (%s)...", uri, download ? "online" : "offline"); - rpp = cachent_provide(cache.rsync, uri); + rpp = cachent_provide(root, uri); if (!rpp) return pr_val_err("Malformed URL: %s", uri); @@ -606,11 +626,51 @@ try_uri(char const *uri, int (*download)(struct cache_node *), return error; } - /* XXX commit the files (later, during cleanup) */ pr_val_debug("RPP validated successfully."); return 0; } +static int +try_uris(struct strlist *uris, struct cache_node *root, + char const *prefix, dl_cb dl, maps_dl_cb cb, void *arg) +{ + char **str; + int error; + + ARRAYLIST_FOREACH(uris, str) + if (str_starts_with(*str, prefix)) { + error = try_uri(*str, root, dl, cb, arg); + if (error <= 0) + return error; + } + + return 1; +} + +int +cache_download_uri(struct strlist *uris, maps_dl_cb cb, void *arg) +{ + char **_str, *str; + int error; + + // XXX mutex + // XXX review result signs + + /* Online attempts */ + error = try_uris(uris, cache.https, "https://", dl_http, cb, arg); + if (error <= 0) + return error; + error = try_uris(uris, cache.rsync, "rsync://", dl_rsync, cb, arg); + if (error <= 0) + return error; + + /* Offline attempts */ + error = try_uris(uris, cache.https, "https://", NULL, cb, arg); + if (error <= 0) + return error; + return try_uris(uris, cache.rsync, "rsync://", NULL, cb, arg); +} + /** * XXX outdated comment * @@ -630,29 +690,23 @@ cache_download_alt(struct sia_uris *uris, maps_dl_cb cb, void *arg) int error; // XXX Make sure somewhere validates rpkiManifest matches caRepository. - /* XXX mutex */ -// /* XXX if parent is downloaded, child is downloaded. */ -// mft = cachent_provide(cache.rsync, uris->rpkiManifest); -// -// if (mft->flags & CNF_FRESH) -// return cb(mft->rpp, arg); // XXX can rpp be NULL? /* Online attempts */ // XXX review result signs // XXX normalize rpkiNotify & caRepository? - error = try_uri(uris->rpkiNotify, dl_rrdp, cb, arg); + error = try_uri(uris->rpkiNotify, cache.https, dl_rrdp, cb, arg); if (error <= 0) return error; - error = try_uri(uris->caRepository, dl_rsync, cb, arg); + error = try_uri(uris->caRepository, cache.rsync, dl_rsync, cb, arg); if (error <= 0) return error; /* Offline attempts */ - error = try_uri(uris->rpkiNotify, NULL, cb, arg); + error = try_uri(uris->rpkiNotify, cache.https, NULL, cb, arg); if (error <= 0) return error; - return try_uri(uris->caRepository, NULL, cb, arg); + return try_uri(uris->caRepository, cache.rsync, NULL, cb, arg); } void @@ -889,15 +943,15 @@ nftw_remove_abandoned(const char *path, const struct stat *st, } } else if (S_ISREG(st->st_mode)) { - if ((msm->flags & CNF_RSYNC) || !pm || (pm->flags & CNF_WITHDRAWN)) { - clock_gettime(CLOCK_REALTIME, &now); // XXX - PR_DEBUG_MSG("%ld > %ld", now.tv_sec - st->st_atim.tv_sec, cfg_cache_threshold()); - if (now.tv_sec - st->st_atim.tv_sec > cfg_cache_threshold()) { - pr_op_debug("Too old; abandoned."); - goto abandoned; - } - pr_op_debug("Still young; preserving."); + +// if ((msm->flags & CNF_RSYNC) || !pm || (pm->flags & CNF_WITHDRAWN)) + clock_gettime(CLOCK_REALTIME, &now); // XXX + PR_DEBUG_MSG("%ld > %ld", now.tv_sec - st->st_atim.tv_sec, cfg_cache_threshold()); + if (now.tv_sec - st->st_atim.tv_sec > cfg_cache_threshold()) { + pr_op_debug("Too old; abandoned."); + goto abandoned; } + pr_op_debug("Still young; preserving."); } else { pr_op_debug("Unknown type; abandoned."); @@ -981,12 +1035,10 @@ cleanup_cache(void) pr_op_debug("Cleaning up old abandoned and unknown cache files."); remove_abandoned(); - pr_op_debug("Cleaning up leftover nodes."); + pr_op_debug("Cleaning up orphaned nodes."); remove_leftover_nodes(); cachent_traverse(cache.rsync, remove_orphaned); cachent_traverse(cache.https, remove_orphaned); - - /* XXX delete nodes for which no file exists? */ } void diff --git a/src/cache/local_cache.h b/src/cache/local_cache.h index 9a899a89..593ee146 100644 --- a/src/cache/local_cache.h +++ b/src/cache/local_cache.h @@ -2,6 +2,7 @@ #define SRC_CACHE_LOCAL_CACHE_H_ #include "cache/cachent.h" +#include "types/str.h" void cache_setup(void); /* Init this module */ void cache_teardown(void); /* Destroy this module */ @@ -31,6 +32,7 @@ void sias_cleanup(struct sia_uris *); * XXX rename */ typedef int (*maps_dl_cb)(struct cache_node *rpp, void *arg); +int cache_download_uri(struct strlist *, maps_dl_cb, void *); int cache_download_alt(struct sia_uris *, maps_dl_cb, void *); void cache_print(void); /* Dump cache in stdout. Recursive; tests only */ diff --git a/src/common.c b/src/common.c index d5f9ec25..6aee1b82 100644 --- a/src/common.c +++ b/src/common.c @@ -238,31 +238,16 @@ valid_file_or_dir(char const *location, bool check_file) return result; } -/* - * > 0: exists - * = 0: !exists - * < 0: error - */ static int -dir_exists(char const *path) +stat_dir(char const *path) { struct stat meta; - int error; - - if (stat(path, &meta) != 0) { - error = errno; - if (error == ENOENT) - return 0; - pr_op_err_st("stat() failed: %s", strerror(error)); - return -error; - } - - if (!S_ISDIR(meta.st_mode)) { - return pr_op_err_st("Path '%s' exists and is not a directory.", - path); - } - return 1; + if (stat(path, &meta) != 0) + return errno; + if (!S_ISDIR(meta.st_mode)) + return ENOTDIR; + return 0; } static int @@ -270,13 +255,17 @@ ensure_dir(char const *path, mode_t mode) { int error; - if (mkdir(path, mode) != 0) { + /* + * Perplexingly, mkdir() returns EEXIST instead of ENOTDIR when the + * path actually refers to a file. + * So it looks like this stat() is unavoidable. + */ + if (stat_dir(path) == ENOTDIR && remove(path)) + return errno; + + if (mkdir(path, mode)) { error = errno; - if (error != EEXIST) { - pr_op_err_st("Error while making directory '%s': %s", - path, strerror(error)); - return error; - } + return (error == EEXIST) ? 0 : error; } return 0; @@ -299,27 +288,33 @@ mkdir_p(char const *_path, bool include_basename, mode_t mode) *last_slash = '\0'; } - result = dir_exists(path); /* short circuit */ - if (result > 0) { - result = 0; - goto end; - } else if (result < 0) { + result = stat_dir(path); /* short circuit */ + if (result == 0) + goto end; /* Already exists */ + if (result != ENOENT && result != ENOTDIR) { + pr_op_err_st("Error during stat(%s): %s", + path, strerror(result)); goto end; } + if (result == ENOTDIR) + pr_op_err_st("stack tracing..."); + for (i = 1; path[i] != '\0'; i++) { if (path[i] == '/') { path[i] = '\0'; result = ensure_dir(path, mode); path[i] = '/'; - if (result != 0) - goto end; /* error msg already printed */ + if (result != 0) { + pr_op_err_st("Error during mkdir(%s): %s", + path, strerror(result)); + goto end; + } } } result = ensure_dir(path, mode); -end: - free(path); +end: free(path); return result; } diff --git a/src/data_structure/path_builder.c b/src/data_structure/path_builder.c index 68b99ba7..e444a0b3 100644 --- a/src/data_structure/path_builder.c +++ b/src/data_structure/path_builder.c @@ -224,6 +224,12 @@ join_paths(char const *path1, char const *path2) char *result; int written; + // XXX needed? + if (path1[0] == 0) + return pstrdup(path2); + if (path2[0] == 0) + return pstrdup(path1); + n = strlen(path1) + strlen(path2) + 2; result = pmalloc(n); diff --git a/src/file.c b/src/file.c index bd27d4fe..909268c5 100644 --- a/src/file.c +++ b/src/file.c @@ -176,7 +176,7 @@ end: free(dst); * Move all the files contained in @src to @dst, overwriting when necessary, * not touching files that exist in @dst but not in @src. * - * Both directories have to already exist. + * @src must exist. * * @src: cache/tmp/123 * @dst: cache/rsync/a.b.c/d/e @@ -184,6 +184,12 @@ end: free(dst); int file_merge_into(char const *src, char const *dst) { + int error; + + error = mkdir_p(dst, false, 0777); + if (error) + return error; + src_offset = strlen(src); merge_dst = dst; /* TODO (performance) optimize that 32 */ diff --git a/src/http/http.c b/src/http/http.c index 3e67596e..714cdd6f 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -432,40 +432,3 @@ http_download_direct(char const *src, char const *dst) pr_val_info("HTTP GET: %s -> %s", src, dst); return http_fetch(src, dst, 0, NULL); } - -int -http_download_tmp(char const *url, char const **path, - curl_off_t ims, bool *changed) -{ - int error; - - error = cache_tmpfile(path); - if (error) - return error; - - error = http_download(url, *path, ims, changed); - if (error) - free(*path); - - return error; -} - -int -http_download_cache_node(struct cache_node *node) -{ - char *path; - bool changed; - int error; - - error = http_download_tmp(node->url, &path, node->mtim, &changed); - if (error) - return error; - - node->flags |= CNF_FRESH; // XXX on notification, preserve node but not file - if (changed) { - node->flags |= CNF_CHANGED; - node->mtim = time(NULL); // XXX catch -1 - } - node->tmpdir = path; - return 0; -} diff --git a/src/http/http.h b/src/http/http.h index 55b63f87..981aa1ba 100644 --- a/src/http/http.h +++ b/src/http/http.h @@ -8,7 +8,5 @@ void http_cleanup(void); int http_download(char const *, char const *, curl_off_t, bool *); int http_download_direct(char const *, char const *); -int http_download_tmp(char const *, char const **, curl_off_t, bool *); -int http_download_cache_node(struct cache_node *); #endif /* SRC_HTTP_HTTP_H_ */ diff --git a/src/object/tal.c b/src/object/tal.c index 35ab767b..2002c372 100644 --- a/src/object/tal.c +++ b/src/object/tal.c @@ -267,7 +267,7 @@ do_file_validation(void *arg) goto end; args.db = db_table_create(); - thread->error = cache_download_alt(&args.tal.urls, MAP_HTTP, + thread->error = cache_download_urls(&args.tal.urls, __handle_tal_map, &args); if (thread->error) { pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.", diff --git a/test/Makefile.am b/test/Makefile.am index a2805cbb..28ada82f 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,7 +12,7 @@ if USE_TESTS # _CFLAGS is not defined. # Otherwise it must be included manually: # mumble_mumble_CFLAGS = ${AM_CFLAGS} flag1 flag2 flag3 ... -AM_CFLAGS = -pedantic -Wall +AM_CFLAGS = -pedantic -Wall -Wno-unused #AM_CFLAGS += -Wno-unused AM_CFLAGS += -std=c99 -D_DEFAULT_SOURCE=1 -D_XOPEN_SOURCE=700 -D_BSD_SOURCE=1 AM_CFLAGS += -I../src -DUNIT_TESTING ${CHECK_CFLAGS} ${XML2_CFLAGS} ${JANSSON_CFLAGS} diff --git a/test/cache/local_cache_test.c b/test/cache/local_cache_test.c index 303fe5dc..b224f532 100644 --- a/test/cache/local_cache_test.c +++ b/test/cache/local_cache_test.c @@ -50,7 +50,7 @@ rsync_download(char const *src, char const *dst, bool is_directory) } int -http_download(char const *url, char const *path, curl_off_t ims, bool *changed) +http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) { char cmd[61]; @@ -61,9 +61,9 @@ http_download(char const *url, char const *path, curl_off_t ims, bool *changed) return dl_error; } - ck_assert_int_eq(0, mkdir_p(path, false, 0777)); + ck_assert_int_eq(0, mkdir_p(dst, false, 0777)); - ck_assert(snprintf(cmd, sizeof(cmd), "touch %s", path) < sizeof(cmd)); + ck_assert(snprintf(cmd, sizeof(cmd), "touch %s", dst) < sizeof(cmd)); ck_assert_int_eq(0, system(cmd)); *changed = true; @@ -79,7 +79,7 @@ MOCK(cfg_cache_threshold, time_t, 60 * 60 * 24 * 7, void) /* Helpers */ static void -setup_test(bool dl_type) +setup_test(void) { dl_error = 0; ck_assert_int_eq(0, system("rm -rf tmp/")); @@ -100,7 +100,7 @@ static void run_dl_rsync(char const *caRepository, int expected_error, unsigned int expected_calls) { - static struct sia_uris sias; + struct sia_uris sias; sias.caRepository = pstrdup(caRepository); sias.rpkiNotify = NULL; @@ -117,6 +117,25 @@ run_dl_rsync(char const *caRepository, int expected_error, sias_cleanup(&sias); } +static void +run_dl_https(char const *url, int expected_error, unsigned int expected_calls) +{ + struct strlist uris; + + strlist_init(&uris); + strlist_add(&uris, pstrdup(url)); + + rsync_counter = 0; + https_counter = 0; + printf("---- Downloading... ----\n"); + ck_assert_int_eq(expected_error, cache_download_uri(&uris, okay, NULL)); + printf("---- Downloaded. ----\n"); + ck_assert_uint_eq(0, rsync_counter); + ck_assert_uint_eq(expected_calls, https_counter); + + strlist_cleanup(&uris); +} + static int print_file(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) @@ -162,38 +181,6 @@ ck_path(struct cache_node *node, char const *_) return true; } -//static struct cache_node * -//cachent_find(struct cache_node *root, char const *url) -//{ -// struct cache_node *node, *child; -// struct tokenizer tkn; -// -// node = root; -// token_init(&tkn, url); -// if (!token_next(&tkn)) -// ck_abort_msg("Path too short: %s", url); -// if (strncmp(root->name, tkn.str, tkn.len) != 0) { -// ck_abort_msg("Root doesn't match: %s != %.*s", -// root->name, (int)tkn.len, tkn.str); -// } -// -// while (token_next(&tkn)) { -// if (tkn.len == 1 && tkn.str[0] == '.') -// continue; -// if (tkn.len == 2 && tkn.str[0] == '.' && tkn.str[1] == '.') -// node = node->parent; -// -// HASH_FIND(hh, node->children, tkn.str, tkn.len, child); -// if (child == NULL) -// ck_abort_msg("Child not found: %s > %.*s", -// node->name, (int)tkn.len, tkn.str); -// -// node = child; -// } -// -// return node; -//} - static void ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual) { @@ -260,6 +247,12 @@ ck_cache_rsync(struct cache_node *rsync) ck_cache(rsync, unode("https", NULL)); } +static void +ck_cache_https(struct cache_node *https) +{ + ck_cache(unode("rsync", NULL), https); +} + static time_t epoch; static bool @@ -291,10 +284,15 @@ nftw_unfreshen(const char *fpath, const struct stat *sb, int typeflag, static void new_iteration(bool outdate) { + pr_op_debug("--- Unfreshening... ---"); epoch = outdate ? get_days_ago(30) : get_days_ago(1); cachent_traverse(cache.rsync, unfreshen); + cachent_traverse(cache.https, unfreshen); ck_assert_int_eq(0, nftw("tmp/rsync", nftw_unfreshen, 32, FTW_PHYS)); ck_assert_int_eq(0, nftw("tmp/https", nftw_unfreshen, 32, FTW_PHYS)); + + pr_op_debug("---- Tree now stale. ----"); + cache_print(); } //static void @@ -325,7 +323,7 @@ static const int FAILED = CNF_FRESH; START_TEST(test_cache_download_rsync) { - setup_test(false); + setup_test(); run_dl_rsync("rsync://a.b.c/d", 0, 1); ck_cache_rsync( @@ -388,7 +386,7 @@ END_TEST START_TEST(test_cache_download_rsync_error) { - setup_test(false); + setup_test(); dl_error = 0; run_dl_rsync("rsync://a.b.c/d", 0, 1); @@ -423,7 +421,7 @@ END_TEST START_TEST(test_cache_cleanup_rsync) { - setup_test(true); + setup_test(); /* * First iteration: Tree is created. No prunes, because nothing's @@ -551,182 +549,219 @@ START_TEST(test_cache_cleanup_rsync) } END_TEST -//START_TEST(test_cache_cleanup_rsync_error) -//{ -// setup_test(); -// -// /* Set up */ -// dl_error = false; -// run_dl_rsync("rsync://a.b.c/d", 0, 1); -// dl_error = true; -// run_dl_rsync("rsync://a.b.c/e", -EINVAL, 1); -// ck_cache( -// NODE("rsync://a.b.c/d/", 0, 1, true), -// NODE("rsync://a.b.c/e/", -EINVAL, 0, false), -// NULL); -// -// /* Node gets deleted because cached file doesn't exist */ -// do_cleanup(); -// ck_cache(NODE("rsync://a.b.c/d/", 0, 1, true), NULL); -// -// /* -// * Node and file do not get deleted, because the failure is still not -// * that old. -// * Deletion does not depend on success or failure. -// */ -// new_iteration(false); -// dl_error = true; -// run_dl_rsync("rsync://a.b.c/d", -EINVAL, 1); -// ck_cache(NODE("rsync://a.b.c/d/", -EINVAL, 1, true), NULL); -// -// /* Error is old; gets deleted */ -// new_iteration(true); -// do_cleanup(); -// ck_cache(NULL); -// -// cleanup_test(); -//} -//END_TEST -// -//START_TEST(test_cache_download_https) -//{ -// setup_test(); -// -// /* Download *file* e. */ -// run_cache_download("https://a.b.c/d/e", 0, 0, 1); -// ck_cache(NODE("https://a.b.c/d/e", 0, 1, 1), NULL); -// -// /* Download something else 1 */ -// run_cache_download("https://a.b.c/e", 0, 0, 1); -// ck_cache( -// NODE("https://a.b.c/d/e", 0, 1, 1), -// NODE("https://a.b.c/e", 0, 1, 1), -// NULL); -// -// /* Download something else 2 */ -// run_cache_download("https://x.y.z/e", 0, 0, 1); -// ck_cache( -// NODE("https://a.b.c/d/e", 0, 1, 1), -// NODE("https://a.b.c/e", 0, 1, 1), -// NODE("https://x.y.z/e", 0, 1, 1), -// NULL); -// -// cleanup_test(); -//} -//END_TEST -// -//START_TEST(test_cache_download_https_error) -//{ -// setup_test(); -// -// dl_error = false; -// run_cache_download("https://a.b.c/d", 0, 0, 1); -// dl_error = true; -// run_cache_download("https://a.b.c/e", -EINVAL, 0, 1); -// ck_cache( -// NODE("https://a.b.c/d", 0, 1, 1), -// NODE("https://a.b.c/e", -EINVAL, 0, 0), -// NULL); -// -// /* Regardless of error, not reattempted because same iteration */ -// dl_error = true; -// run_cache_download("https://a.b.c/d", 0, 0, 0); -// dl_error = false; -// run_cache_download("https://a.b.c/e", -EINVAL, 0, 0); -// ck_cache( -// NODE("https://a.b.c/d", 0, 1, 1), -// NODE("https://a.b.c/e", -EINVAL, 0, 0), -// NULL); -// -// cleanup_test(); -//} -//END_TEST -// -//START_TEST(test_cache_cleanup_https) -//{ -// setup_test(); -// -// /* First iteration; make a tree and clean it */ -// new_iteration(true); -// run_cache_download("https://a.b.c/d", 0, 0, 1); -// run_cache_download("https://a.b.c/e", 0, 0, 1); -// do_cleanup(); -// ck_cache( -// NODE("https://a.b.c/d", 0, 1, 1), -// NODE("https://a.b.c/e", 0, 1, 1), -// NULL); -// -// /* Remove one branch */ -// new_iteration(true); -// run_cache_download("https://a.b.c/d", 0, 0, 1); -// do_cleanup(); -// ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL); -// -// /* Change the one branch */ -// new_iteration(true); -// run_cache_download("https://a.b.c/e", 0, 0, 1); -// do_cleanup(); -// ck_cache(NODE("https://a.b.c/e", 0, 1, 1), NULL); -// -// /* Add a child to the same branch, do not update the old one */ -// new_iteration(true); -// run_cache_download("https://a.b.c/e/f/g", 0, 0, 1); -// do_cleanup(); -// ck_cache( -// NODE("https://a.b.c/e/f/g", 0, 1, 1), NULL); -// +START_TEST(test_cache_cleanup_rsync_error) +{ + setup_test(); + + /* Set up */ + dl_error = 0; + run_dl_rsync("rsync://a.b.c/d", 0, 1); + dl_error = -EINVAL; + run_dl_rsync("rsync://a.b.c/e", -EINVAL, 1); + ck_cache_rsync( + unode("rsync", + unode("rsync/a.b.c", + uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL), + ufnode("rsync/a.b.c/e", FAILED, NULL), NULL), NULL)); + + /* Node gets deleted because cached file doesn't exist */ + run_cleanup(); + ck_cache_rsync( + unode("rsync", + unode("rsync/a.b.c", + ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL)); + + /* + * Node and file do not get deleted, because the failure is still not + * that old. + * Deletion does not depend on success or failure. + */ + new_iteration(false); + dl_error = -EINVAL; + run_dl_rsync("rsync://a.b.c/d", -EINVAL, 1); + ck_cache_rsync( + unode("rsync", + unode("rsync/a.b.c", + ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL)); + + /* Error is old; gets deleted */ + new_iteration(true); + run_cleanup(); + ck_cache_rsync(unode("rsync", NULL)); + + cleanup_test(); +} +END_TEST + +static const int HDOWNLOADED = CNF_CACHED | CNF_FRESH | CNF_CHANGED; +static const int HVALIDATED = CNF_CACHED | CNF_VALID; +static const int HFULL = HDOWNLOADED | HVALIDATED; +static const int HFAILED = CNF_FRESH; + +START_TEST(test_cache_download_https) +{ + setup_test(); + + /* Download *file* e. */ + run_dl_https("https://a.b.c/d/e", 0, 1); + ck_cache_https( + unode("https", + unode("https/a.b.c", + unode("https/a.b.c/d", + uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL)); + + /* Download something else 1 */ + run_dl_https("https://a.b.c/e", 0, 1); + ck_cache_https( + unode("https", + unode("https/a.b.c", + unode("https/a.b.c/d", + uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), + uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL)); + + /* Download something else 2 */ + run_dl_https("https://x.y.z/e", 0, 1); + ck_cache_https( + unode("https", + unode("https/a.b.c", + unode("https/a.b.c/d", + uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), + uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), + unode("https/x.y.z", + uftnode("https/x.y.z/e", HFULL, "tmp/tmp/2", NULL), NULL), NULL)); + + cleanup_test(); +} +END_TEST + +START_TEST(test_cache_download_https_error) +{ + setup_test(); + + dl_error = 0; + run_dl_https("https://a.b.c/d", 0, 1); + dl_error = -EINVAL; + run_dl_https("https://a.b.c/e", -EINVAL, 1); + ck_cache_https( + unode("https", + unode("https/a.b.c", + uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL), + uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL)); + + /* Regardless of error, not reattempted because same iteration */ + dl_error = -EINVAL; + run_dl_https("https://a.b.c/d", 0, 0); + dl_error = 0; + run_dl_https("https://a.b.c/e", -EINVAL, 0); + ck_cache_https( + unode("https", + unode("https/a.b.c", + uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL), + uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL)); + + cleanup_test(); +} +END_TEST + +// XXX not testing alts so far + +START_TEST(test_cache_cleanup_https) +{ + setup_test(); + + /* First iteration; make a tree and clean it */ + new_iteration(true); + run_dl_https("https://a.b.c/d", 0, 1); + run_dl_https("https://a.b.c/e", 0, 1); + run_cleanup(); + ck_cache_https( + unode("https", + unode("https/a.b.c", + ufnode("https/a.b.c/d", HFULL, NULL), + ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL)); + + /* Remove one branch */ + new_iteration(true); + run_dl_https("https://a.b.c/d", 0, 1); + run_cleanup(); + ck_cache_https( + unode("https", + unode("https/a.b.c", + ufnode("https/a.b.c/d", HFULL, NULL), NULL), NULL)); + + /* Change the one branch */ + new_iteration(true); + run_dl_https("https://a.b.c/e", 0, 1); + run_cleanup(); + ck_cache_https( + unode("https", + unode("https/a.b.c", + ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL)); + + /* Add a child to the same branch, do not update the old one */ + new_iteration(true); + PR_DEBUG; + run_dl_https("https://a.b.c/e/f/g", 0, 1); + run_cleanup(); + ck_cache_https( + unode("https", + unode("https/a.b.c", + unode("https/a.b.c/e", + unode("https/a.b.c/e/f", + ufnode("https/a.b.c/e/f/g", HFULL, NULL), NULL), NULL), NULL), NULL)); + // /* // * Download parent, do not update child. // * Children need to die, because parent is now a file. // */ // new_iteration(true); -// run_cache_download("https://a.b.c/e/f", 0, 0, 1); -// do_cleanup(); +// run_dl_https("https://a.b.c/e/f", 0, 1); +// run_cleanup(); // ck_cache(NODE("https://a.b.c/e/f", 0, 1, 1), NULL); // // /* Do it again. */ // new_iteration(true); -// run_cache_download("https://a.b.c/e", 0, 0, 1); -// do_cleanup(); +// run_dl_https("https://a.b.c/e", 0, 1); +// run_cleanup(); // ck_cache(NODE("https://a.b.c/e", 0, 1, 1), NULL); // // /* Empty the tree */ // new_iteration(true); -// do_cleanup(); +// run_cleanup(); // ck_cache(NULL); // // /* Node exists, but file doesn't */ // new_iteration(true); -// run_cache_download("https://a.b.c/e", 0, 0, 1); -// run_cache_download("https://a.b.c/f/g/h", 0, 0, 1); +// run_dl_https("https://a.b.c/e", 0, 1); +// run_dl_https("https://a.b.c/f/g/h", 0, 1); // ck_cache( // NODE("https://a.b.c/e", 0, 1, 1), // NODE("https://a.b.c/f/g/h", 0, 1, 1), // NULL); // ck_assert_int_eq(0, file_rm_rf("tmp/https/a.b.c/f/g/h")); -// do_cleanup(); +// run_cleanup(); // ck_cache(NODE("https://a.b.c/e", 0, 1, 1), NULL); -// -// cleanup_test(); -//} -//END_TEST -// + + cleanup_test(); +} +END_TEST + //START_TEST(test_cache_cleanup_https_error) //{ // setup_test(); // // /* Set up */ // dl_error = false; -// run_cache_download("https://a.b.c/d", 0, 0, 1); +// run_dl_https("https://a.b.c/d", 0, 1); // dl_error = true; -// run_cache_download("https://a.b.c/e", -EINVAL, 0, 1); +// run_dl_https("https://a.b.c/e", -EINVAL, 1); // ck_cache( // NODE("https://a.b.c/d", 0, 1, 1), // NODE("https://a.b.c/e", -EINVAL, 0, 0), // NULL); // // /* Deleted because file ENOENT. */ -// do_cleanup(); +// run_cleanup(); // ck_cache( // NODE("https://a.b.c/d", 0, 1, 1), // NULL); @@ -734,17 +769,17 @@ END_TEST // /* Fail d */ // new_iteration(false); // dl_error = true; -// run_cache_download("https://a.b.c/d", -EINVAL, 0, 1); +// run_dl_https("https://a.b.c/d", -EINVAL, 1); // ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL); // // /* Not deleted, because not old */ // new_iteration(false); -// do_cleanup(); +// run_cleanup(); // ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL); // // /* Become old */ // new_iteration(true); -// do_cleanup(); +// run_cleanup(); // ck_cache(NULL); // // cleanup_test(); @@ -970,15 +1005,15 @@ static Suite *thread_pool_suite(void) TCase *rsync, *https, *dot, *meta, *recover; rsync = tcase_create("rsync"); - tcase_add_test(rsync, test_cache_download_rsync); - tcase_add_test(rsync, test_cache_download_rsync_error); - tcase_add_test(rsync, test_cache_cleanup_rsync); +// tcase_add_test(rsync, test_cache_download_rsync); +// tcase_add_test(rsync, test_cache_download_rsync_error); +// tcase_add_test(rsync, test_cache_cleanup_rsync); // tcase_add_test(rsync, test_cache_cleanup_rsync_error); https = tcase_create("https"); // tcase_add_test(https, test_cache_download_https); // tcase_add_test(https, test_cache_download_https_error); -// tcase_add_test(https, test_cache_cleanup_https); + tcase_add_test(https, test_cache_cleanup_https); // tcase_add_test(https, test_cache_cleanup_https_error); dot = tcase_create("dot");