From: Alberto Leiva Popper Date: Wed, 31 Jul 2024 19:48:01 +0000 (-0600) Subject: Wednesday X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=28a7f15b392e571cf759f677f7cf26dc9ef317a2;p=thirdparty%2FFORT-validator.git Wednesday --- diff --git a/src/Makefile.am b/src/Makefile.am index 56f16aee..62f74736 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ fort_SOURCES += asn1/signed_data.h asn1/signed_data.c fort_SOURCES += base64.h base64.c fort_SOURCES += cache.c cache.h fort_SOURCES += cachent.c cachent.h +fort_SOURCES += cachetmp.c cachetmp.h fort_SOURCES += certificate_refs.h certificate_refs.c fort_SOURCES += cert_stack.h cert_stack.c fort_SOURCES += common.c common.h diff --git a/src/cache.c b/src/cache.c index ac7fb75d..d955b53c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -7,10 +7,10 @@ #include "cache.h" #include -#include #include #include "alloc.h" +#include "cachetmp.h" #include "common.h" #include "config.h" #include "configure_ac.h" @@ -46,13 +46,10 @@ static struct rpki_cache { // time_t startup_ts; /* When we started the last validation */ } cache; -static atomic_uint file_counter; - #define CACHE_METAFILE "cache.json" #define TAGNAME_VERSION "fort-version" #define CACHEDIR_TAG "CACHEDIR.TAG" -#define TMPDIR "tmp" #define TAL_METAFILE "tal.json" #define TAGNAME_TYPE "type" @@ -180,7 +177,7 @@ init_tmp_dir(void) char *dirname; int error; - dirname = get_cache_filename(TMPDIR, true); + dirname = get_cache_filename(CACHE_TMPDIR, true); error = mkdir(dirname, true); if (error != EEXIST) @@ -211,37 +208,6 @@ cache_teardown(void) free(filename); } -/* - * Returns a unique temporary file name in the local cache. Note, it's a name, - * and it's pretty much reserved. The file itself will not be created. - * - * The file will not be automatically deleted when it is closed or the program - * terminates. - * - * The name of the function is inherited from tmpfile(3). - * - * The resulting string needs to be released. - */ -int -cache_tmpfile(char **filename) -{ - struct path_builder pb; - int error; - - error = pb_init_cache(&pb, TMPDIR); - if (error) - return error; - - error = pb_append_u32(&pb, atomic_fetch_add(&file_counter, 1u)); - if (error) { - pb_cleanup(&pb); - return error; - } - - *filename = pb.string; - return 0; -} - //static char * //get_tal_json_filename(void) //{ @@ -337,8 +303,8 @@ cache_tmpfile(char **filename) static void load_tal_json(void) { - cache.rsync = cachent_create_root(false); - cache.https = cachent_create_root(true); + cache.rsync = cachent_root_rsync(); + cache.https = cachent_root_https(); // char *filename; // json_t *root; @@ -562,6 +528,7 @@ static int dl_http(struct cache_node *node) { char *tmppath; + time_t mtim; bool changed; int error; @@ -574,17 +541,17 @@ dl_http(struct cache_node *node) if (error) return error; + mtim = time(NULL); // XXX + error = http_download(node->url, tmppath, node->mtim, &changed); if (error) { free(tmppath); 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->flags |= CNF_CACHED | CNF_FRESH; + if (changed) + node->mtim = mtim; node->tmppath = tmppath; return 0; } @@ -826,7 +793,7 @@ rmf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) static void cleanup_tmp(void) { - char *tmpdir = get_cache_filename(TMPDIR, true); + char *tmpdir = get_cache_filename(CACHE_TMPDIR, true); if (nftw(tmpdir, rmf, 32, FTW_DEPTH | FTW_PHYS)) pr_op_warn("Cannot empty the cache's tmp directory: %s", strerror(errno)); diff --git a/src/cache.h b/src/cache.h index e5378e07..213fa8bb 100644 --- a/src/cache.h +++ b/src/cache.h @@ -7,8 +7,6 @@ void cache_setup(void); /* Init this module */ void cache_teardown(void); /* Destroy this module */ -int cache_tmpfile(char **); /* Return new unique path in /tmp/ */ - void cache_prepare(void); /* Prepare cache for new validation cycle */ void cache_commit(void); /* Finish successful validation cycle */ /* XXX Huh. Looks like this could use a cache_rollback() */ diff --git a/src/cachent.c b/src/cachent.c index e7f4da03..44b252e4 100644 --- a/src/cachent.c +++ b/src/cachent.c @@ -7,20 +7,32 @@ #include "types/path.h" #include "types/url.h" -struct cache_node * -cachent_create_root(bool https) +static struct cache_node * +cachent_root(char const *schema, char const *dir) { struct cache_node *root; root = pzalloc(sizeof(struct cache_node)); - root->url = pstrdup(https ? "https://" : "rsync://"); - root->path = join_paths(config_get_local_repository(), - https ? "https" : "rsync"); + root->url = (char *)schema; + root->path = join_paths(config_get_local_repository(), dir); root->name = strrchr(root->path, '/') + 1; + root->flags = CNF_FREE_PATH; return root; } +struct cache_node * +cachent_root_rsync(void) +{ + return cachent_root("rsync://", "rsync"); +} + +struct cache_node * +cachent_root_https(void) +{ + return cachent_root("https://", "https"); +} + /* Preorder. @cb returns whether the children should be traversed. */ int cachent_traverse(struct cache_node *root, bool (*cb)(struct cache_node *)) @@ -129,10 +141,13 @@ provide(struct cache_node *parent, char const *url, child->url = pstrndup(url, name - url + namelen); child->path = inherit_path(parent->path, name, namelen); child->name = child->url + (name - url); + child->flags = CNF_FREE_URL | CNF_FREE_PATH; if ((parent->flags & RSYNC_INHERIT) == RSYNC_INHERIT) - child->flags = RSYNC_INHERIT; - if (parent->tmppath && !(parent->flags & CNF_RSYNC)) + child->flags |= RSYNC_INHERIT; + if (parent->tmppath && !(parent->flags & CNF_RSYNC)) { child->tmppath = inherit_path(parent->tmppath, name, namelen); + child->flags |= CNF_FREE_TMPPATH; + } child->parent = parent; HASH_ADD_KEYPTR(hh, parent->children, child->name, namelen, child); @@ -196,9 +211,12 @@ __delete_node(struct cache_node *node) if (node->parent != NULL) HASH_DEL(node->parent->children, node); - free(node->url); - free(node->path); - free(node->tmppath); + if (node->flags & CNF_FREE_URL) + free(node->url); + if (node->flags & CNF_FREE_PATH) + free(node->path); + if (node->flags & CNF_FREE_TMPPATH) + free(node->tmppath); free(node); return valid; @@ -246,7 +264,6 @@ print_node(struct cache_node *node, unsigned int tabs) printf("%s", (node->flags & CNF_RSYNC) ? "rsync " : ""); printf("%s", (node->flags & CNF_CACHED) ? "cached " : ""); printf("%s", (node->flags & CNF_FRESH) ? "fresh " : ""); - printf("%s", (node->flags & CNF_CHANGED) ? "changed " : ""); printf("%s", (node->flags & CNF_TOUCHED) ? "touched " : ""); printf("%s", (node->flags & CNF_VALID) ? "valid " : ""); printf("%s", (node->flags & CNF_NOTIFICATION) ? "notification " : ""); diff --git a/src/cachent.h b/src/cachent.h index e70114e4..97143c9d 100644 --- a/src/cachent.h +++ b/src/cachent.h @@ -21,11 +21,6 @@ * "Allegedly" because we might have rsync'd an ancestor. */ #define CNF_FRESH (1 << 2) -/* - * Did it change between the previous cycle and the current one? - * (This is HTTP and RRDP only; rsync doesn't tell us.) - */ -#define CNF_CHANGED (1 << 3) /* Was it read during the current cycle? */ #define CNF_TOUCHED (1 << 4) /* @@ -41,6 +36,10 @@ /* Withdrawn by RRDP? */ #define CNF_WITHDRAWN (1 << 7) +#define CNF_FREE_URL (1 << 8) +#define CNF_FREE_PATH (1 << 9) +#define CNF_FREE_TMPPATH (1 << 10) + /* * Flags for children of downloaded rsync nodes that should be cleaned later. * (FRESH prevents redownload.) @@ -67,7 +66,7 @@ struct cache_node { char *tmppath; /* path/to/cache/tmp/1234 */ /* Only if flags & CNF_NOTIFICATION */ - struct cachefile_notification notif; + struct cachefile_notification rrdp; struct cache_node *parent; /* Tree parent */ struct cache_node *children; /* Tree children */ @@ -75,7 +74,8 @@ struct cache_node { UT_hash_handle hh; /* Hash table hook */ }; -struct cache_node *cachent_create_root(bool); +struct cache_node *cachent_root_rsync(void); +struct cache_node *cachent_root_https(void); int cachent_traverse(struct cache_node *, bool (*cb)(struct cache_node *)); diff --git a/src/cachetmp b/src/cachetmp new file mode 100644 index 00000000..e69de29b diff --git a/src/cachetmp.c b/src/cachetmp.c new file mode 100644 index 00000000..60ff6181 --- /dev/null +++ b/src/cachetmp.c @@ -0,0 +1,37 @@ +#include "cachetmp.h" + +#include +#include "types/path.h" + +static atomic_uint file_counter; + +/* + * Returns a unique temporary file name in the local cache. Note, it's a name, + * and it's pretty much reserved. The file itself will not be created. + * + * The file will not be automatically deleted when it is closed or the program + * terminates. + * + * The name of the function is inherited from tmpfile(3). + * + * The resulting string needs to be released. + */ +int +cache_tmpfile(char **filename) +{ + struct path_builder pb; + int error; + + error = pb_init_cache(&pb, CACHE_TMPDIR); + if (error) + return error; + + error = pb_append_u32(&pb, atomic_fetch_add(&file_counter, 1u)); + if (error) { + pb_cleanup(&pb); + return error; + } + + *filename = pb.string; + return 0; +} diff --git a/src/cachetmp.h b/src/cachetmp.h new file mode 100644 index 00000000..dec35d11 --- /dev/null +++ b/src/cachetmp.h @@ -0,0 +1,8 @@ +#ifndef SRC_CACHETMP_H_ +#define SRC_CACHETMP_H_ + +#define CACHE_TMPDIR "tmp" + +int cache_tmpfile(char **); /* Return new unique path in /tmp/ */ + +#endif /* SRC_CACHETMP_H_ */ diff --git a/src/file.c b/src/file.c index 3d37337a..184f8d36 100644 --- a/src/file.c +++ b/src/file.c @@ -62,7 +62,8 @@ file_write(char const *file_name, char const *mode, FILE **result) } int -file_write_full(char const *path, unsigned char *content, size_t content_len) +file_write_full(char const *path, unsigned char const *content, + size_t content_len) { FILE *out; size_t written; diff --git a/src/file.h b/src/file.h index 64e36cea..8e76f7d0 100644 --- a/src/file.h +++ b/src/file.h @@ -25,7 +25,7 @@ struct file_contents { int file_open(char const *, FILE **, struct stat *); int file_write(char const *, char const *, FILE **); -int file_write_full(char const *, unsigned char *, size_t); +int file_write_full(char const *, unsigned char const *, size_t); void file_close(FILE *); int file_load(char const *, struct file_contents *, bool); diff --git a/src/hash.c b/src/hash.c index 1155fb32..ec78b653 100644 --- a/src/hash.c +++ b/src/hash.c @@ -163,6 +163,8 @@ hash_validate_file(struct hash_algorithm const *algorithm, char const *path, size_t actual_len; int error; + pr_val_debug("Validating file hash: %s", path); + error = hash_file(algorithm, path, actual, &actual_len); if (error) return error; diff --git a/src/relax_ng.c b/src/relax_ng.c index e3d909e6..4ae956bb 100644 --- a/src/relax_ng.c +++ b/src/relax_ng.c @@ -56,7 +56,7 @@ relax_ng_init(void) xmlInitParser(); - rngparser = xmlRelaxNGNewMemParserCtxt(RRDP_V1_RNG, RRDP_V1_RNG_SIZE); + rngparser = xmlRelaxNGNewMemParserCtxt(RRDP_V1_RNG, strlen(RRDP_V1_RNG)); if (rngparser == NULL) { error = pr_op_err("XML parser init error: xmlRelaxNGNewMemParserCtxt() returned NULL"); goto cleanup_parser; diff --git a/src/relax_ng.h b/src/relax_ng.h index 4a3f780a..eeb22f70 100644 --- a/src/relax_ng.h +++ b/src/relax_ng.h @@ -160,8 +160,6 @@ " " \ "" -#define RRDP_V1_RNG_SIZE strlen(RRDP_V1_RNG) - int relax_ng_init(void); void relax_ng_cleanup(void); diff --git a/src/rrdp.c b/src/rrdp.c index 0332d05f..94f239d3 100644 --- a/src/rrdp.c +++ b/src/rrdp.c @@ -71,7 +71,7 @@ struct withdraw { struct parser_args { struct rrdp_session *session; - struct cache_node *rpp; + struct cache_node *notif; }; static BIGNUM * @@ -479,21 +479,31 @@ delete_file(char const *path) } static int -handle_publish(xmlTextReaderPtr reader, struct cache_node *rpp) +handle_publish(xmlTextReaderPtr reader, struct cache_node *notif) { struct publish tag = { 0 }; - struct cache_node *node; + struct cache_node *subtree, *node; int error; error = parse_publish(reader, &tag); if (error) goto end; + pr_val_debug("- publish %s", tag.meta.uri); + + if (!notif->rrdp.subtree) { + subtree = pzalloc(sizeof(struct cache_node)); + subtree->url = "rsync://"; + subtree->path = notif->path; + subtree->name = strrchr(subtree->path, '/') + 1; + subtree->tmppath = notif->tmppath; + notif->rrdp.subtree = subtree; + } - // XXX Not going to pass URL validation. - node = cachent_provide(rpp, tag.meta.uri); + node = cachent_provide(notif->rrdp.subtree, tag.meta.uri); if (!node) { + // XXX outdated msg error = pr_val_err("Broken RRDP: is attempting to create file '%s' outside of its publication point '%s'.", - tag.meta.uri, rpp->url); + tag.meta.uri, notif->url); goto end; } @@ -517,6 +527,7 @@ handle_publish(xmlTextReaderPtr reader, struct cache_node *rpp) goto end; } + pr_val_debug("Caching file: %s", node->tmppath); error = file_write_full(node->tmppath, tag.content, tag.content_len); end: metadata_cleanup(&tag.meta); @@ -525,7 +536,7 @@ end: metadata_cleanup(&tag.meta); } static int -handle_withdraw(xmlTextReaderPtr reader, struct cache_node *rpp) +handle_withdraw(xmlTextReaderPtr reader, struct cache_node *notif) { struct withdraw tag = { 0 }; struct cache_node *node; @@ -535,11 +546,13 @@ handle_withdraw(xmlTextReaderPtr reader, struct cache_node *rpp) if (error) goto end; - // XXX Not going to pass URL validation. - node = cachent_provide(rpp, tag.meta.uri); + pr_val_debug("- withdraw: %s", tag.meta.uri); + + node = cachent_provide(notif->rrdp.subtree, tag.meta.uri); if (!node) { + // XXX outdated msg error = pr_val_err("Broken RRDP: is attempting to delete file '%s' outside of its publication point '%s'.", - tag.meta.uri, rpp->url); + tag.meta.uri, notif->url); goto end; } @@ -738,13 +751,14 @@ xml_read_notif(xmlTextReaderPtr reader, void *arg) } static int -parse_notification(struct cache_node *notif, struct update_notification *result) +parse_notification(char const *url, char const *path, + struct update_notification *result) { int error; - update_notification_init(result, notif->url); + update_notification_init(result, url); - error = relax_ng_parse(notif->tmppath, xml_read_notif, result); + error = relax_ng_parse(path, xml_read_notif, result); if (error) update_notification_cleanup(result); @@ -764,7 +778,7 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg) switch (type) { case XML_READER_TYPE_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH)) - error = handle_publish(reader, args->rpp); + error = handle_publish(reader, args->notif); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT)) error = validate_session(reader, args->session); else @@ -781,9 +795,9 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg) static int parse_snapshot(struct rrdp_session *session, char const *path, - struct cache_node *rpp) + struct cache_node *notif) { - struct parser_args args = { .session = session, .rpp = rpp }; + struct parser_args args = { .session = session, .notif = notif }; return relax_ng_parse(path, xml_read_snapshot, &args); } @@ -840,21 +854,21 @@ dl_tmp(char const *url, char **path) } static int -handle_snapshot(struct update_notification *notif, struct cache_node *rpp) +handle_snapshot(struct update_notification *new, struct cache_node *notif) { char *tmppath; int error; - pr_val_debug("Processing snapshot '%s'.", notif->snapshot.uri); - fnstack_push(notif->snapshot.uri); + pr_val_debug("Processing snapshot '%s'.", new->snapshot.uri); + fnstack_push(new->snapshot.uri); - error = dl_tmp(notif->snapshot.uri, &tmppath); + error = dl_tmp(new->snapshot.uri, &tmppath); if (error) goto end1; - error = validate_hash(¬if->snapshot, tmppath); + error = validate_hash(&new->snapshot, tmppath); if (error) goto end2; - error = parse_snapshot(¬if->session, tmppath, rpp); + error = parse_snapshot(&new->session, tmppath, notif); delete_file(tmppath); end2: free(tmppath); @@ -875,9 +889,9 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg) switch (type) { case XML_READER_TYPE_ELEMENT: if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH)) - error = handle_publish(reader, args->rpp); + error = handle_publish(reader, args->notif); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_WITHDRAW)) - error = handle_withdraw(reader, args->rpp); + error = handle_withdraw(reader, args->notif); else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA)) error = validate_session(reader, args->session); else @@ -894,7 +908,7 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg) static int parse_delta(struct update_notification *notif, struct notification_delta *delta, - char const *path, struct cache_node *node) + char const *path, struct cache_node *notif_node) { struct parser_args args; struct rrdp_session session; @@ -907,14 +921,14 @@ parse_delta(struct update_notification *notif, struct notification_delta *delta, session.session_id = notif->session.session_id; session.serial = delta->serial; args.session = &session; - args.rpp = node; + args.notif = notif_node; return relax_ng_parse(path, xml_read_delta, &args); } static int handle_delta(struct update_notification *notif, - struct notification_delta *delta, struct cache_node *node) + struct notification_delta *delta, struct cache_node *notif_node) { char *tmppath; int error; @@ -925,7 +939,7 @@ handle_delta(struct update_notification *notif, error = dl_tmp(delta->meta.uri, &tmppath); if (error) goto end; - error = parse_delta(notif, delta, tmppath, node); + error = parse_delta(notif, delta, tmppath, notif_node); delete_file(tmppath); free(tmppath); @@ -934,7 +948,7 @@ end: fnstack_pop(); } static int -handle_deltas(struct update_notification *notif, struct cache_node *node) +handle_deltas(struct update_notification *notif, struct cache_node *notif_node) { struct rrdp_serial *old; struct rrdp_serial *new; @@ -948,7 +962,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *node) return -ENOENT; } - old = &node->notif.session.serial; + old = ¬if_node->rrdp.session.serial; new = ¬if->session.serial; pr_val_debug("Handling RRDP delta serials %s-%s.", old->str, new->str); @@ -971,7 +985,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *node) old->str, new->str); for (d = notif->deltas.len - diff; d < notif->deltas.len; d++) { - error = handle_delta(notif, ¬if->deltas.array[d], node); + error = handle_delta(notif, ¬if->deltas.array[d], notif_node); if (error) return error; } @@ -1072,39 +1086,59 @@ update_notif(struct cachefile_notification *old, struct update_notification *new return 0; } -static int -dl_notif(struct cache_node *notif) +static bool +dl_notif(struct cache_node *notif, struct update_notification *new) { char *tmppath; + time_t mtim; bool changed; - int error; - error = cache_tmpfile(&tmppath); - if (error) - return error; + notif->dlerr = cache_tmpfile(&tmppath); + if (notif->dlerr) + return false; - error = http_download(notif->url, tmppath, notif->mtim, &changed); - if (error) { - free(tmppath); - return error; + mtim = time(NULL); // XXX + changed = false; + notif->dlerr = http_download(notif->url, tmppath, notif->mtim, &changed); + notif->flags |= CNF_FRESH; + + if (notif->dlerr) + goto end; + if (!changed) { + pr_val_debug("The Notification has not changed."); + goto end; } - // XXX notif->flags |= CNF_CACHED | CNF_FRESH; - if (changed) { - notif->mtim = time(NULL); // XXX - notif->tmppath = tmppath; - } else { - free(tmppath); + notif->mtim = mtim; /* XXX should happen much later */ + notif->dlerr = parse_notification(notif->url, tmppath, new); + if (notif->dlerr) + goto end; + + if (remove(tmppath) == -1) { + notif->dlerr = errno; + pr_val_err("Can't remove notification's temporal file: %s", + strerror(notif->dlerr)); + goto end; + } + if (mkdir(tmppath, 0777) == -1) { + notif->dlerr = errno; + pr_val_err("Can't create notification's temporal directory: %s", + strerror(notif->dlerr)); + goto end; } - return 0; + notif->tmppath = tmppath; + return true; + +end: free(tmppath); + return false; } /* * Downloads the Update Notification @notif, and updates the cache accordingly. * * "Updates the cache accordingly" means it downloads the missing deltas or - * snapshot, and explodes them into @rpp's tmp directory. + * snapshot, and explodes them into @notif's tmp directory. */ int rrdp_update(struct cache_node *notif) @@ -1112,62 +1146,39 @@ rrdp_update(struct cache_node *notif) struct cachefile_notification *old; struct update_notification new; int serial_cmp; - int error; fnstack_push(notif->url); pr_val_debug("Processing notification."); - /////////////////////////////////////////////////////////////////////// - - error = dl_notif(notif); - if (error) - goto end; - - if (!notif->tmppath) { - pr_val_debug("The Notification has not changed."); - goto end; - } - - error = parse_notification(notif, &new); - if (error) - goto end; - - remove(notif->tmppath); // XXX - if (mkdir(notif->tmppath, 0777) == -1) { - error = errno; - pr_val_err("Can't create notification's temporal directory: %s", - strerror(error)); - goto clean_notif; - } - - /////////////////////////////////////////////////////////////////////// + if (!dl_notif(notif, &new)) + goto end; /* Unchanged or error */ pr_val_debug("New session/serial: %s/%s", new.session.session_id, new.session.serial.str); if (!(notif->flags & CNF_NOTIFICATION)) { pr_val_debug("This is a new Notification."); - error = handle_snapshot(&new, notif); - if (error) + notif->dlerr = handle_snapshot(&new, notif); + if (notif->dlerr) goto clean_notif; notif->flags |= CNF_NOTIFICATION; - init_notif(¬if->notif, &new); + init_notif(¬if->rrdp, &new); goto end; } - old = ¬if->notif; + old = ¬if->rrdp; serial_cmp = BN_cmp(old->session.serial.num, new.session.serial.num); if (serial_cmp < 0) { pr_val_debug("The Notification's serial changed."); - error = validate_session_desync(old, &new); - if (error) + notif->dlerr = validate_session_desync(old, &new); + if (notif->dlerr) goto snapshot_fallback; - error = handle_deltas(&new, notif); - if (error) + notif->dlerr = handle_deltas(&new, notif); + if (notif->dlerr) goto snapshot_fallback; - error = update_notif(old, &new); - if (!error) + notif->dlerr = update_notif(old, &new); + if (!notif->dlerr) goto end; /* * The files are exploded and usable, but @cached is not @@ -1190,8 +1201,8 @@ rrdp_update(struct cache_node *notif) snapshot_fallback: pr_val_debug("Falling back to snapshot."); - error = handle_snapshot(&new, notif); - if (error) + notif->dlerr = handle_snapshot(&new, notif); + if (notif->dlerr) goto clean_notif; reset_notif: @@ -1202,9 +1213,8 @@ reset_notif: clean_notif: update_notification_cleanup(&new); -end: - fnstack_pop(); - return error; +end: fnstack_pop(); + return notif->dlerr; } #define TAGNAME_SESSION "session_id" diff --git a/src/rrdp.h b/src/rrdp.h index e5ab5380..d88a5b0a 100644 --- a/src/rrdp.h +++ b/src/rrdp.h @@ -31,6 +31,7 @@ struct rrdp_hash { */ struct cachefile_notification { struct rrdp_session session; + struct cache_node *subtree; /* * The 1st one contains the hash of the session.serial delta. * The 2nd one contains the hash of the session.serial - 1 delta. diff --git a/src/types/map.c b/src/types/map.c index 6b11c541..87ab958c 100644 --- a/src/types/map.c +++ b/src/types/map.c @@ -3,7 +3,7 @@ #include #include "alloc.h" -#include "cache.h" +#include "cachetmp.h" #include "common.h" #include "config.h" #include "config/filename_format.h" diff --git a/test/cache_test.c b/test/cache_test.c index 04db54fb..dcedef53 100644 --- a/test/cache_test.c +++ b/test/cache_test.c @@ -7,9 +7,11 @@ #include "common.c" #include "cache.c" #include "cachent.c" +#include "cachetmp.c" #include "cache_util.c" #include "file.c" #include "mock.c" +#include "mock_https.c" #include "types/path.c" #include "types/str.c" #include "types/url.c" @@ -17,8 +19,6 @@ /* Mocks */ static unsigned int rsync_counter; /* Times the rsync function was called */ -static unsigned int https_counter; /* Times the https function was called */ -static int dl_error; int rsync_download(char const *src, char const *dst, char const *cmpdir) @@ -38,32 +38,10 @@ rsync_download(char const *src, char const *dst, char const *cmpdir) return 0; } -int -http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) -{ - char cmd[61]; - - https_counter++; - - if (dl_error) { - *changed = false; - return dl_error; - } - - ck_assert_int_eq(0, mkdir_p(dst, false, 0777)); - - ck_assert(snprintf(cmd, sizeof(cmd), "touch %s", dst) < sizeof(cmd)); - ck_assert_int_eq(0, system(cmd)); - - *changed = true; - return 0; -} - MOCK_ABORT_INT(rrdp_update, struct cache_node *notif) __MOCK_ABORT(rrdp_notif2json, json_t *, NULL, struct cachefile_notification *notif) MOCK_VOID(rrdp_notif_free, struct cachefile_notification *notif) MOCK_ABORT_INT(rrdp_json2notif, json_t *json, struct cachefile_notification **result) -MOCK(cfg_cache_threshold, time_t, 60 * 60 * 24 * 7, void) MOCK_VOID(__delete_node_cb, struct cache_node const *node) /* Helpers */ @@ -74,8 +52,7 @@ setup_test(void) dl_error = 0; ck_assert_int_eq(0, system("rm -rf tmp/")); cache_prepare(); - ck_assert_int_eq(0, system("mkdir -p tmp/rsync")); - ck_assert_int_eq(0, system("mkdir -p tmp/https")); + ck_assert_int_eq(0, system("mkdir -p tmp/rsync tmp/https tmp/tmp")); } static int @@ -172,38 +149,6 @@ ck_path(struct cache_node *node) return true; } -static void -ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual) -{ - struct cache_node *echild, *achild, *tmp; - - PR_DEBUG_MSG("Comparing %s vs %s", expected->url, actual->url); - - ck_assert_str_eq(expected->url, actual->url); - ck_assert_str_eq(expected->path, actual->path); - ck_assert_str_eq(expected->name, actual->name); - ck_assert_int_eq(expected->flags, actual->flags); - if (expected->tmppath) - ck_assert_str_eq(expected->tmppath, actual->tmppath); - else - ck_assert_ptr_eq(NULL, actual->tmppath); - - HASH_ITER(hh, expected->children, echild, tmp) { - HASH_FIND(hh, actual->children, echild->name, - strlen(echild->name), achild); - if (achild == NULL) - ck_abort_msg("Expected not found: %s", echild->url); - ck_assert_cachent_eq(echild, achild); - } - - HASH_ITER(hh, actual->children, achild, tmp) { - HASH_FIND(hh, expected->children, achild->name, - strlen(achild->name), echild); - if (echild == NULL) - ck_abort_msg("Actual not found: %s", achild->url); - } -} - static void ck_cache(struct cache_node *rsync, struct cache_node *https) { @@ -236,13 +181,13 @@ ck_cache(struct cache_node *rsync, struct cache_node *https) static void ck_cache_rsync(struct cache_node *rsync) { - ck_cache(rsync, hunode("", NULL)); + ck_cache(rsync, hunode(HE2UP, NULL)); } static void ck_cache_https(struct cache_node *https) { - ck_cache(runode("", NULL), https); + ck_cache(runode(RE2UP, NULL), https); } static time_t @@ -274,7 +219,7 @@ static bool unfreshen(struct cache_node *node) { PR_DEBUG_MSG("Unfreshening %s.", node->url); - node->flags &= ~(CNF_FRESH | CNF_CHANGED | CNF_VALID); + node->flags &= ~(CNF_FRESH | CNF_VALID); node->mtim = epoch; return true; } @@ -310,14 +255,6 @@ new_iteration(bool outdate) cache_print(); } -//static void -//cache_reset(struct rpki_cache *cache) -//{ -// struct cache_node *node, *tmp; -// HASH_ITER(hh, cache->ht, node, tmp) -// delete_node(cache, node); -//} - static void cleanup_test(void) { @@ -343,17 +280,16 @@ START_TEST(test_cache_download_rsync) printf("==== Startup ====\n"); run_dl_rsync("rsync://a.b.c/d", 0, 1); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), NULL), NULL)); - /* Redownload same file, nothing should happen */ - printf("==== Redownload sample file ====\n"); + printf("==== Redownload same file, nothing should happen ====\n"); run_dl_rsync("rsync://a.b.c/d", 0, 0); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), NULL), NULL)); /* * rsyncs are recursive, which means if we've been recently asked to @@ -362,10 +298,10 @@ START_TEST(test_cache_download_rsync) printf("==== Don't redownload child ====\n"); run_dl_rsync("rsync://a.b.c/d/e", 0, 0); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", - rufnode("a.b.c/d/e", VALIDATED, NULL), NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", + rufnode(RO2UP("a.b.c/d/e"), VALIDATED, NULL), NULL), NULL), NULL)); /* * rsyncs get truncated, because it results in much faster @@ -376,29 +312,28 @@ START_TEST(test_cache_download_rsync) printf("==== rsync truncated ====\n"); run_dl_rsync("rsync://x.y.z/m/n/o", 0, 1); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", - rufnode("a.b.c/d/e", VALIDATED, NULL), NULL), NULL), - runode("x.y.z", - ruftnode("x.y.z/m", DOWNLOADED, "tmp/tmp/1", - rufnode("x.y.z/m/n", BRANCH, - rufnode("x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL)); - - /* Sibling */ + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", + rufnode(RO2UP("a.b.c/d/e"), VALIDATED, NULL), NULL), NULL), + runode(RO2UP("x.y.z"), + ruftnode(RO2UP("x.y.z/m"), DOWNLOADED, "tmp/tmp/1", + rufnode(RO2UP("x.y.z/m/n"), BRANCH, + rufnode(RO2UP("x.y.z/m/n/o"), VALIDATED, NULL), NULL), NULL), NULL), NULL)); + printf("==== Sibling ====\n"); run_dl_rsync("rsync://a.b.c/e/f", 0, 1); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", - rufnode("a.b.c/d/e", VALIDATED, NULL), NULL), - ruftnode("a.b.c/e", DOWNLOADED, "tmp/tmp/2", - rufnode("a.b.c/e/f", VALIDATED, NULL), NULL), NULL), - runode("x.y.z", - ruftnode("x.y.z/m", DOWNLOADED, "tmp/tmp/1", - rufnode("x.y.z/m/n", BRANCH, - rufnode("x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", + rufnode(RO2UP("a.b.c/d/e"), VALIDATED, NULL), NULL), + ruftnode(RO2UP("a.b.c/e"), DOWNLOADED, "tmp/tmp/2", + rufnode(RO2UP("a.b.c/e/f"), VALIDATED, NULL), NULL), NULL), + runode(RO2UP("x.y.z"), + ruftnode(RO2UP("x.y.z/m"), DOWNLOADED, "tmp/tmp/1", + rufnode(RO2UP("x.y.z/m/n"), BRANCH, + rufnode(RO2UP("x.y.z/m/n/o"), VALIDATED, NULL), NULL), NULL), NULL), NULL)); cleanup_test(); } @@ -408,32 +343,33 @@ START_TEST(test_cache_download_rsync_error) { setup_test(); + printf("==== Startup ====\n"); 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( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), - rufnode("a.b.c/e", FAILED, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), + rufnode(RO2UP("a.b.c/e"), FAILED, NULL), NULL), NULL)); - /* Regardless of error, not reattempted because same iteration */ + printf("==== Regardless of error, not reattempted because same iteration ====\n"); dl_error = EINVAL; run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), - rufnode("a.b.c/e", FAILED, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), + rufnode(RO2UP("a.b.c/e"), FAILED, NULL), NULL), NULL)); dl_error = 0; run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), - rufnode("a.b.c/e", FAILED, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), + rufnode(RO2UP("a.b.c/e"), FAILED, NULL), NULL), NULL)); cleanup_test(); } @@ -443,34 +379,28 @@ START_TEST(test_cache_cleanup_rsync) { setup_test(); - /* - * First iteration: Tree is created. No prunes, because nothing's - * outdated. - */ - printf("==== First iteration: Tree is created ====\n"); + printf("==== First iteration: Tree is created. No prunes, because nothing's outdated ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/d", 0, 1); run_dl_rsync("rsync://a.b.c/e", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", FULL, NULL), - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), FULL, NULL), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); - /* One iteration with no changes, for paranoia */ - printf("==== No changes, for paranoia ====\n"); + printf("==== One iteration with no changes, for paranoia ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/d", 0, 1); run_dl_rsync("rsync://a.b.c/e", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", FULL, NULL), - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), FULL, NULL), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); - /* Add one sibling */ printf("==== Add one sibling ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/d", 0, 1); @@ -478,92 +408,85 @@ START_TEST(test_cache_cleanup_rsync) run_dl_rsync("rsync://a.b.c/f", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", FULL, NULL), - rufnode("a.b.c/e", FULL, NULL), - rufnode("a.b.c/f", FULL, NULL), NULL), NULL)); - - /* Nodes don't get updated, but they're still too young. */ - printf("==== Still too young ====\n"); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), FULL, NULL), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), + rufnode(RO2UP("a.b.c/f"), FULL, NULL), NULL), NULL)); + + printf("==== Nodes don't get updated, but they're still too young ====\n"); new_iteration(false); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", STALE, NULL), - rufnode("a.b.c/e", STALE, NULL), - rufnode("a.b.c/f", STALE, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), STALE, NULL), + rufnode(RO2UP("a.b.c/e"), STALE, NULL), + rufnode(RO2UP("a.b.c/f"), STALE, NULL), NULL), NULL)); - /* Remove some branches */ printf("==== Remove some branches ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/d", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), FULL, NULL), NULL), NULL)); - /* Remove old branch and add sibling at the same time */ - printf("==== Remove old branch + add sibling ====\n"); + printf("==== Remove old branch and add sibling at the same time ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/e", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); - /* Try child */ printf("==== Try child ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/e/f/g", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); - /* Parent again */ printf("==== Parent again ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/e", 0, 1); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); - /* Empty the tree */ printf("==== Empty the tree ====\n"); new_iteration(true); run_cleanup(); - ck_cache_rsync(runode("", NULL)); + ck_cache_rsync(runode(RE2UP, NULL)); - /* Node exists, but file doesn't */ printf("==== Node exists, but file doesn't ====\n"); new_iteration(true); run_dl_rsync("rsync://a.b.c/e", 0, 1); run_dl_rsync("rsync://a.b.c/f", 0, 1); ck_cache_rsync( - runode("", - runode("a.b.c", - ruftnode("a.b.c/e", FULL, "tmp/tmp/B", NULL), - ruftnode("a.b.c/f", FULL, "tmp/tmp/C", NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/e"), FULL, "tmp/tmp/B", NULL), + ruftnode(RO2UP("a.b.c/f"), FULL, "tmp/tmp/C", NULL), NULL), NULL)); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/e", FULL, NULL), - rufnode("a.b.c/f", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), + rufnode(RO2UP("a.b.c/f"), FULL, NULL), NULL), NULL)); ck_assert_int_eq(0, file_rm_rf("tmp/rsync/a.b.c/f")); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/e", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/e"), FULL, NULL), NULL), NULL)); cleanup_test(); } @@ -573,45 +496,38 @@ START_TEST(test_cache_cleanup_rsync_error) { setup_test(); - /* Set up */ printf("==== Set up ====\n"); 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( - runode("", - runode("a.b.c", - ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), - rufnode("a.b.c/e", FAILED, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + ruftnode(RO2UP("a.b.c/d"), FULL, "tmp/tmp/0", NULL), + rufnode(RO2UP("a.b.c/e"), FAILED, NULL), NULL), NULL)); - /* Node gets deleted because cached file doesn't exist */ - printf("==== Node deleted because file not found ====\n"); + printf("==== Node deleted because file doesn't exist ====\n"); run_cleanup(); ck_cache_rsync( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", FULL, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("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. - */ printf("==== Node and file preserved because young ====\n"); + /* (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( - runode("", - runode("a.b.c", - rufnode("a.b.c/d", DOWNLOADED, NULL), NULL), NULL)); + runode(RE2UP, + runode(RO2UP("a.b.c"), + rufnode(RO2UP("a.b.c/d"), DOWNLOADED, NULL), NULL), NULL)); - /* Error is old; gets deleted */ - printf("==== Error deleted because old ====\n"); + printf("==== Error node deleted because old ====\n"); new_iteration(true); run_cleanup(); - ck_cache_rsync(runode("", NULL)); + ck_cache_rsync(runode(RE2UP, NULL)); cleanup_test(); } @@ -619,7 +535,7 @@ END_TEST /* XXX ================================================================ */ -static const int HDOWNLOADED = CNF_CACHED | CNF_FRESH | CNF_CHANGED; +static const int HDOWNLOADED = CNF_CACHED | CNF_FRESH; static const int HVALIDATED = CNF_CACHED | CNF_VALID; static const int HFULL = HDOWNLOADED | HVALIDATED; static const int HFAILED = CNF_FRESH; @@ -628,33 +544,33 @@ START_TEST(test_cache_download_https) { setup_test(); - /* Download *file* e. */ + printf("==== Download *file* e ====\n"); run_dl_https("https://a.b.c/d/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - hunode("a.b.c/d", - huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hunode(HO2UP("a.b.c/d"), + huftnode(HO2UP("a.b.c/d/e"), HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL)); - /* Download something else 1 */ + printf("==== Download something else 1 ====\n"); run_dl_https("https://a.b.c/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - hunode("a.b.c/d", - huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), - huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hunode(HO2UP("a.b.c/d"), + huftnode(HO2UP("a.b.c/d/e"), HFULL, "tmp/tmp/0", NULL), NULL), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/1", NULL), NULL), NULL)); - /* Download something else 2 */ + printf("==== Download something else 2 ====\n"); run_dl_https("https://x.y.z/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - hunode("a.b.c/d", - huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), - huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), - hunode("x.y.z", - huftnode("x.y.z/e", HFULL, "tmp/tmp/2", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hunode(HO2UP("a.b.c/d"), + huftnode(HO2UP("a.b.c/d/e"), HFULL, "tmp/tmp/0", NULL), NULL), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/1", NULL), NULL), + hunode(HO2UP("x.y.z"), + huftnode(HO2UP("x.y.z/e"), HFULL, "tmp/tmp/2", NULL), NULL), NULL)); cleanup_test(); } @@ -664,26 +580,27 @@ START_TEST(test_cache_download_https_error) { setup_test(); + printf("==== Startup ====\n"); 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( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), - huftnode("a.b.c/e", HFAILED, NULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), + huftnode(HO2UP("a.b.c/e"), HFAILED, NULL, NULL), NULL), NULL)); - /* Regardless of error, not reattempted because same iteration */ + printf("==== Regardless of error, not reattempted because same iteration ====\n"); 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( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), - huftnode("a.b.c/e", HFAILED, NULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), + huftnode(HO2UP("a.b.c/e"), HFAILED, NULL, NULL), NULL), NULL)); cleanup_test(); } @@ -695,135 +612,133 @@ START_TEST(test_cache_cleanup_https) { setup_test(); - /* First iteration; make a tree and clean it */ + printf("==== First iteration; make a tree and clean it ====\n"); 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( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/d", HFULL, NULL), - hufnode("a.b.c/e", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/d"), HFULL, NULL), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), NULL), NULL)); - /* Remove one branch */ + printf("==== Remove one branch ====\n"); new_iteration(true); run_dl_https("https://a.b.c/d", 0, 1); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/d", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/d"), HFULL, NULL), NULL), NULL)); - /* Change the one branch */ + printf("==== Change the one branch ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e", 0, 1); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), NULL), NULL)); - /* Add a child to the same branch, do not update the old one */ + printf("==== Add a child to the same branch, do not update the old one ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e/f/g", 0, 1); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hunode("a.b.c/e", - hunode("a.b.c/e/f", - hufnode("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. - */ + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hunode(HO2UP("a.b.c/e"), + hunode(HO2UP("a.b.c/e/f"), + hufnode(HO2UP("a.b.c/e/f/g"), HFULL, NULL), NULL), NULL), NULL), NULL)); + + printf("==== Download parent, do not update child ====\n"); + /* (Children need to die, because parent is now a file) */ new_iteration(true); run_dl_https("https://a.b.c/e/f", 0, 1); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hunode("a.b.c/e", - hufnode("a.b.c/e/f", HFULL, NULL), NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hunode(HO2UP("a.b.c/e"), + hufnode(HO2UP("a.b.c/e/f"), HFULL, NULL), NULL), NULL), NULL)); - /* Do it again. */ + printf("==== Do it again ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e", 0, 1); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), NULL), NULL)); - /* Empty the tree */ + printf("==== Empty the tree ====\n"); new_iteration(true); run_cleanup(); - ck_cache_https(hunode("", NULL)); + ck_cache_https(hunode(HE2UP, NULL)); - /* Node exists, but file doesn't */ + printf("==== Node exists, but file doesn't ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e", 0, 1); run_dl_https("https://a.b.c/f/g/h", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/e", HFULL, "tmp/tmp/7", NULL), - hunode("a.b.c/f", - hunode("a.b.c/f/g", - huftnode("a.b.c/f/g/h", HFULL, "tmp/tmp/8", NULL), NULL), NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/7", NULL), + hunode(HO2UP("a.b.c/f"), + hunode(HO2UP("a.b.c/f/g"), + huftnode(HO2UP("a.b.c/f/g/h"), HFULL, "tmp/tmp/8", NULL), NULL), NULL), NULL), NULL)); run_cleanup(); /* Move from tmp/tmp to tmp/https */ ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL), - hunode("a.b.c/f", - hunode("a.b.c/f/g", - hufnode("a.b.c/f/g/h", HFULL, NULL), NULL), NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), + hunode(HO2UP("a.b.c/f"), + hunode(HO2UP("a.b.c/f/g"), + hufnode(HO2UP("a.b.c/f/g/h"), HFULL, NULL), NULL), NULL), NULL), NULL)); ck_assert_int_eq(0, file_rm_rf("tmp/https/a.b.c/f/g/h")); run_cleanup(); /* Actual test */ ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), NULL), NULL)); - /* Temporal version disappears before we get a commit */ + printf("==== Temporal version disappears before we get a commit ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/e", HFULL, "tmp/tmp/9", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/9", NULL), NULL), NULL)); ck_assert_int_eq(0, file_rm_rf("tmp/tmp/9")); run_cleanup(); - ck_cache_https(hunode("", NULL)); + ck_cache_https(hunode(HE2UP, NULL)); - /* Temporal version disappears after we get a commit */ + printf("==== Temporal version disappears after we get a commit ====\n"); new_iteration(true); run_dl_https("https://a.b.c/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/e", HFULL, "tmp/tmp/A", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/A", NULL), NULL), NULL)); run_cleanup(); /* Commit */ ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL, NULL), NULL), NULL)); new_iteration(false); run_dl_https("https://a.b.c/e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/e", HFULL, "tmp/tmp/B", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/B", NULL), NULL), NULL)); ck_assert_int_eq(0, file_rm_rf("tmp/tmp/B")); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/e", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/e"), HFULL, NULL), NULL), NULL)); cleanup_test(); } @@ -833,46 +748,46 @@ START_TEST(test_cache_cleanup_https_error) { setup_test(); - /* Set up */ + printf("==== Set up ====\n"); 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); PR_DEBUG; ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), - hufnode("a.b.c/e", HFAILED, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), + hufnode(HO2UP("a.b.c/e"), HFAILED, NULL), NULL), NULL)); - /* Deleted because file ENOENT. */ + printf("==== Deleted because file ENOENT ====\n"); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/d", HFULL, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/d"), HFULL, NULL), NULL), NULL)); - /* Fail d */ + printf("==== Fail d ====\n"); new_iteration(false); dl_error = -EINVAL; run_dl_https("https://a.b.c/d", -EINVAL, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/d", CNF_CACHED | CNF_FRESH, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/d"), CNF_CACHED | CNF_FRESH, NULL), NULL), NULL)); - /* Not deleted, because not old */ + printf("==== Not deleted, because not old ====\n"); new_iteration(false); run_cleanup(); ck_cache_https( - hunode("", - hunode("a.b.c", - hufnode("a.b.c/d", CNF_CACHED, NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + hufnode(HO2UP("a.b.c/d"), CNF_CACHED, NULL), NULL), NULL)); - /* Become old */ + printf("==== Become old ====\n"); new_iteration(true); run_cleanup(); - ck_cache_https(hunode("", NULL)); + ck_cache_https(hunode(HE2UP, NULL)); cleanup_test(); } @@ -884,28 +799,28 @@ START_TEST(test_dots) run_dl_https("https://a.b.c/d", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), NULL), NULL)); run_dl_https("https://a.b.c/d/.", 0, 0); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), NULL), NULL)); run_dl_https("https://a.b.c/d/e/..", 0, 0); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), NULL), NULL)); run_dl_https("https://a.b.c/./d/../e", 0, 1); ck_cache_https( - hunode("", - hunode("a.b.c", - huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), - huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL)); + hunode(HE2UP, + hunode(HO2UP("a.b.c"), + huftnode(HO2UP("a.b.c/d"), HFULL, "tmp/tmp/0", NULL), + huftnode(HO2UP("a.b.c/e"), HFULL, "tmp/tmp/1", NULL), NULL), NULL)); cleanup_test(); } @@ -1144,6 +1059,7 @@ int main(void) int tests_failed; suite = thread_pool_suite(); + dls[0] = "Fort\n"; runner = srunner_create(suite); srunner_run_all(runner, CK_NORMAL); diff --git a/test/cache_util.c b/test/cache_util.c index 85a121ff..74475bf5 100644 --- a/test/cache_util.c +++ b/test/cache_util.c @@ -1,29 +1,63 @@ #include "cache_util.h" +#include #include #include "types/uthash.h" -static struct cache_node * -node(char const *schema, char const *path, int flags, char const *tmpdir, +static int +cnf_clean(int flags) +{ + return flags & ~(CNF_FREE_URL | CNF_FREE_PATH | CNF_FREE_TMPPATH); +} + +void +ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual) +{ + struct cache_node *echild, *achild, *tmp; + + PR_DEBUG_MSG("Comparing %s vs %s", expected->url, actual->url); + + ck_assert_str_eq(expected->url, actual->url); + ck_assert_str_eq(expected->path, actual->path); + ck_assert_str_eq(expected->name, actual->name); + ck_assert_int_eq(cnf_clean(expected->flags), cnf_clean(actual->flags)); + if (expected->tmppath) + ck_assert_str_eq(expected->tmppath, actual->tmppath); + else + ck_assert_ptr_eq(NULL, actual->tmppath); + + HASH_ITER(hh, expected->children, echild, tmp) { + HASH_FIND(hh, actual->children, echild->name, + strlen(echild->name), achild); + if (achild == NULL) + ck_abort_msg("Expected not found: %s", echild->url); + ck_assert_cachent_eq(echild, achild); + } + + HASH_ITER(hh, actual->children, achild, tmp) { + HASH_FIND(hh, expected->children, achild->name, + strlen(achild->name), echild); + if (echild == NULL) + ck_abort_msg("Actual not found: %s", achild->url); + } +} + +struct cache_node * +vcreate_node(char const *url, char const *path, int flags, char const *tmppath, va_list children) { struct cache_node *result; struct cache_node *child; char buffer[64]; - char const *slash; result = pzalloc(sizeof(struct cache_node)); - ck_assert(snprintf(buffer, 64, "%s://%s", schema, path) < 64); - result->url = pstrdup(buffer); - slash = (path[0] == 0) ? "" : "/"; - ck_assert(snprintf(buffer, 64, "tmp/%s%s%s", schema, slash, path) < 64); - result->path = pstrdup(buffer); - + result->url = (char *)url; + result->path = (char *)path; result->name = strrchr(result->path, '/') + 1; ck_assert_ptr_ne(NULL, result->name); result->flags = flags; - result->tmppath = tmpdir ? pstrdup(tmpdir) : NULL; + result->tmppath = (char *)tmppath; while ((child = va_arg(children, struct cache_node *)) != NULL) { HASH_ADD_KEYPTR(hh, result->children, child->name, @@ -35,78 +69,76 @@ node(char const *schema, char const *path, int flags, char const *tmpdir, } struct cache_node * -ruftnode(char const *path, int flags, char const *tmpdir, ...) +ruftnode(char const *url, char const *path, int flags, char const *tmppath, ...) { struct cache_node *result; va_list children; - va_start(children, tmpdir); - result = node("rsync", path, flags, tmpdir, children); + va_start(children, tmppath); + result = vcreate_node(url, path, flags, tmppath, children); va_end(children); return result; } struct cache_node * -rufnode(char const *path, int flags, ...) +rufnode(char const *url, char const *path, int flags, ...) { struct cache_node *result; va_list children; va_start(children, flags); - result = node("rsync", path, flags, NULL, children); + result = vcreate_node(url, path, flags, NULL, children); va_end(children); return result; } struct cache_node * -runode(char const *path, ...) +runode(char const *url, char const *path, ...) { struct cache_node *result; va_list children; va_start(children, path); - result = node("rsync", path, 0, NULL, children); + result = vcreate_node(url, path, 0, NULL, children); va_end(children); return result; } struct cache_node * -huftnode(char const *path, int flags, char const *tmpdir, ...) +huftnode(char const *url, char const *path, int flags, char const *tmppath, ...) { struct cache_node *result; va_list children; - va_start(children, tmpdir); - result = node("https", path, flags, tmpdir, children); + va_start(children, tmppath); + result = vcreate_node(url, path, flags, tmppath, children); va_end(children); return result; } -struct cache_node * -hufnode(char const *path, int flags, ...) +struct cache_node *hufnode(char const *url, char const *path, int flags, ...) { struct cache_node *result; va_list children; va_start(children, flags); - result = node("https", path, flags, NULL, children); + result = vcreate_node(url, path, flags, NULL, children); va_end(children); return result; } -struct cache_node * -hunode(char const *path, ...) +struct cache_node *hunode(char const *url, char const *path, ...) { struct cache_node *result; va_list children; va_start(children, path); - result = node("https", path, 0, NULL, children); + result = vcreate_node(url, path, 0, NULL, children); va_end(children); return result; diff --git a/test/cache_util.h b/test/cache_util.h index 2b3f1949..185895ad 100644 --- a/test/cache_util.h +++ b/test/cache_util.h @@ -4,12 +4,27 @@ #include #include "cachent.h" -struct cache_node *ruftnode(char const *, int , char const *, ...); -struct cache_node *rufnode(char const *, int , ...); -struct cache_node *runode(char const *, ...); +void ck_assert_cachent_eq(struct cache_node *, struct cache_node *); -struct cache_node *huftnode(char const *, int , char const *, ...); -struct cache_node *hufnode(char const *, int , ...); -struct cache_node *hunode(char const *, ...); +struct cache_node *vcreate_node(char const *, char const *, int, char const *, va_list); + +// XXX Rename ? +struct cache_node *ruftnode(char const *, char const *, int, char const *, ...); +struct cache_node *rufnode(char const *, char const *, int, ...); +struct cache_node *runode(char const *, char const *, ...); + +struct cache_node *huftnode(char const *, char const *, int, char const *, ...); +struct cache_node *hufnode(char const *, char const *, int, ...); +struct cache_node *hunode(char const *, char const *, ...); + +/* rsync offset to url + path */ +#define RO2UP(offset) "rsync://" offset, "tmp/rsync/" offset +/* https offset to url + path */ +#define HO2UP(offset) "https://" offset, "tmp/https/" offset + +/* rsync empty to url + path */ +#define RE2UP "rsync://", "tmp/rsync" +/* https empty to url + path */ +#define HE2UP "https://", "tmp/https" #endif /* TEST_CACHE_UTIL_H_ */ diff --git a/test/cachent_test.c b/test/cachent_test.c index e3e1c070..8ffe46ad 100644 --- a/test/cachent_test.c +++ b/test/cachent_test.c @@ -20,14 +20,14 @@ START_TEST(test_delete) { struct cache_node *root, *a, *b; - a = runode("a", NULL); + a = runode(RO2UP("a"), NULL); dn = 0; cachent_delete(a); ck_assert_uint_eq(1, dn); ck_assert_str_eq("a", deleted[0]); - a = runode("a", NULL); - root = runode("", a, NULL); + a = runode(RO2UP("a"), NULL); + root = runode(RE2UP, a, NULL); dn = 0; cachent_delete(a); ck_assert_ptr_eq(NULL, root->children); @@ -39,23 +39,23 @@ START_TEST(test_delete) ck_assert_uint_eq(1, dn); ck_assert_str_eq("rsync", deleted[0]); - b = runode("a/b", - runode("a/b/c", NULL), - runode("a/b/d", NULL), - runode("a/b/e", NULL), - runode("a/b/f", NULL), NULL); - a = runode("a", + b = runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), + runode(RO2UP("a/b/d"), NULL), + runode(RO2UP("a/b/e"), NULL), + runode(RO2UP("a/b/f"), NULL), NULL); + a = runode(RO2UP("a"), b, - runode("a/g", - runode("a/g/h", - runode("a/g/h/i", NULL), NULL), - runode("a/g/j", - runode("a/g/j/k", NULL), NULL), - runode("a/g/l", - runode("a/g/l/m", NULL), NULL), - runode("a/g/n", - runode("a/g/n/o", NULL), NULL), NULL), NULL); - root = runode("", a, NULL); + runode(RO2UP("a/g"), + runode(RO2UP("a/g/h"), + runode(RO2UP("a/g/h/i"), NULL), NULL), + runode(RO2UP("a/g/j"), + runode(RO2UP("a/g/j/k"), NULL), NULL), + runode(RO2UP("a/g/l"), + runode(RO2UP("a/g/l/m"), NULL), NULL), + runode(RO2UP("a/g/n"), + runode(RO2UP("a/g/n/o"), NULL), NULL), NULL), NULL); + root = runode(RE2UP, a, NULL); dn = 0; cachent_delete(b); @@ -124,36 +124,36 @@ START_TEST(test_traverse) root = NULL; ck_traverse(root, NULL); - root = runode("a", NULL); + root = runode(RO2UP("a"), NULL); ck_traverse(root, "tmp/rsync/a", NULL); - root = runode("a", - runode("a/b", NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", NULL); - root = runode("a", - runode("a/b", - runode("a/b/c", NULL), NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", "tmp/rsync/a/b/c", NULL); - root = runode("a", - runode("a/b", - runode("a/b/c", NULL), - runode("a/b/d", NULL), NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), + runode(RO2UP("a/b/d"), NULL), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", "tmp/rsync/a/b/c", "tmp/rsync/a/b/d", NULL); - root = runode("a", - runode("a/b", - runode("a/b/c", NULL), - runode("a/b/d", NULL), NULL), - runode("a/e", NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), + runode(RO2UP("a/b/d"), NULL), NULL), + runode(RO2UP("a/e"), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", @@ -161,11 +161,11 @@ START_TEST(test_traverse) "tmp/rsync/a/b/d", "tmp/rsync/a/e", NULL); - root = runode("a", - runode("a/b", NULL), - runode("a/c", - runode("a/c/d", NULL), - runode("a/c/e", NULL), NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), NULL), + runode(RO2UP("a/c"), + runode(RO2UP("a/c/d"), NULL), + runode(RO2UP("a/c/e"), NULL), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", @@ -173,13 +173,13 @@ START_TEST(test_traverse) "tmp/rsync/a/c/d", "tmp/rsync/a/c/e", NULL); - root = runode("a", - runode("a/b", - runode("a/b/c", NULL), - runode("a/b/d", NULL), NULL), - runode("a/e", - runode("a/e/f", NULL), - runode("a/e/g", NULL), NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), + runode(RO2UP("a/b/d"), NULL), NULL), + runode(RO2UP("a/e"), + runode(RO2UP("a/e/f"), NULL), + runode(RO2UP("a/e/g"), NULL), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", @@ -189,21 +189,21 @@ START_TEST(test_traverse) "tmp/rsync/a/e/f", "tmp/rsync/a/e/g", NULL); - root = runode("a", - runode("a/b", - runode("a/b/c", NULL), - runode("a/b/d", NULL), - runode("a/b/e", NULL), - runode("a/b/f", NULL), NULL), - runode("a/g", - runode("a/g/h", - runode("a/g/h/i", NULL), NULL), - runode("a/g/j", - runode("a/g/j/k", NULL), NULL), - runode("a/g/l", - runode("a/g/l/m", NULL), NULL), - runode("a/g/n", - runode("a/g/n/o", NULL), NULL), NULL), NULL); + root = runode(RO2UP("a"), + runode(RO2UP("a/b"), + runode(RO2UP("a/b/c"), NULL), + runode(RO2UP("a/b/d"), NULL), + runode(RO2UP("a/b/e"), NULL), + runode(RO2UP("a/b/f"), NULL), NULL), + runode(RO2UP("a/g"), + runode(RO2UP("a/g/h"), + runode(RO2UP("a/g/h/i"), NULL), NULL), + runode(RO2UP("a/g/j"), + runode(RO2UP("a/g/j/k"), NULL), NULL), + runode(RO2UP("a/g/l"), + runode(RO2UP("a/g/l/m"), NULL), NULL), + runode(RO2UP("a/g/n"), + runode(RO2UP("a/g/n/o"), NULL), NULL), NULL), NULL); ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", @@ -227,7 +227,7 @@ START_TEST(test_provide) { struct cache_node *rsync, *abc, *d, *e, *f, *g, *h, *ee; - rsync = cachent_create_root(false); + rsync = cachent_root_rsync(); ck_assert_ptr_ne(NULL, rsync); ck_assert_ptr_eq(NULL, rsync->parent); ck_assert_str_eq("rsync://", rsync->url); diff --git a/test/hash_test.c b/test/hash_test.c index ffeee35f..eb1a3b5b 100644 --- a/test/hash_test.c +++ b/test/hash_test.c @@ -6,11 +6,8 @@ #include "file.c" #include "hash.c" #include "mock.c" -#include "types/map.c" #include "types/path.c" -MOCK_ABORT_INT(cache_tmpfile, char **filename) - /* Actually mostly tests libcrypto's sanity, not Fort's. */ START_TEST(test_hash) { diff --git a/test/mock.c b/test/mock.c index 40bd6803..7df1a8e4 100644 --- a/test/mock.c +++ b/test/mock.c @@ -113,7 +113,9 @@ v6addr2str2(struct in6_addr const *addr) MOCK_NULL(config_get_slurm, char const *, void) MOCK(config_get_tal, char const *, "tal/", void) MOCK(config_get_local_repository, char const *, "tmp", void) +MOCK(cfg_cache_threshold, time_t, 60 * 60 * 24 * 7, void) MOCK(config_get_mode, enum mode, STANDALONE, void) +MOCK_UINT(config_get_rrdp_delta_threshold, 5, void) MOCK_TRUE(config_get_rsync_enabled, void) MOCK_UINT(config_get_rsync_priority, 50, void) MOCK_TRUE(config_get_http_enabled, void) diff --git a/test/mock_https.c b/test/mock_https.c new file mode 100644 index 00000000..c7fefbd3 --- /dev/null +++ b/test/mock_https.c @@ -0,0 +1,35 @@ +#include "http.h" + +#include +#include "file.h" + +static int dl_error; +static char const *dls[8]; +static unsigned int https_counter; /* Times http_download() was called */ + +int +http_download(char const *url, char const *path, curl_off_t ims, bool *changed) +{ + char const *content; + + if (dl_error) { + printf("Simulating failed HTTP download.\n"); + https_counter++; + if (changed) + *changed = false; + return dl_error; + } + + printf("Simulating HTTP download: %s -> %s\n", url, path); + + content = dls[https_counter++]; + if (!content) + ck_abort_msg("Test was not expecting an HTTP download."); + + ck_assert_int_eq(0, file_write_full(path, + (unsigned char const *)content, strlen(content))); + + if (changed) + *changed = true; + return 0; +} diff --git a/test/rrdp_test.c b/test/rrdp_test.c index 28e0d232..20c379ef 100644 --- a/test/rrdp_test.c +++ b/test/rrdp_test.c @@ -5,6 +5,7 @@ #include "alloc.c" #include "base64.c" #include "cachent.c" +#include "cachetmp.c" #include "common.c" #include "file.c" #include "hash.c" @@ -17,32 +18,17 @@ /* Mocks */ -int -cache_tmpfile(char **filename) -{ - static unsigned int file_counter = 0; - char *result; - int written; - - result = pmalloc(10); - written = snprintf(result, 10, "tmp/%u", file_counter++); - ck_assert(4 < written && written < 10); - - *filename = result; - return 0; -} - MOCK_VOID(fnstack_push, char const *file) MOCK_VOID(fnstack_pop, void) MOCK_VOID(__delete_node_cb, struct cache_node const *node) -MOCK_UINT(config_get_rrdp_delta_threshold, 5, void) MOCK_ABORT_INT(http_download, char const *url, char const *path, curl_off_t ims, bool *changed) /* Mocks end */ static void -ck_rrdp_session(char const *session, char const *serial, struct rrdp_session *actual) +ck_rrdp_session(char const *session, char const *serial, + struct rrdp_session *actual) { BIGNUM *bn; @@ -398,7 +384,8 @@ init_regular_notif(struct update_notification *notif, unsigned long serial, ...) } static void -validate_cachefile_notif(struct cachefile_notification *notif, unsigned long __serial, ...) +validate_cachefile_notif(struct cachefile_notification *notif, + unsigned long __serial, ...) { struct rrdp_serial serial; va_list args; @@ -465,27 +452,16 @@ START_TEST(test_update_notif) } END_TEST -static void -init_map(struct cache_node *map, char *url, char *path) -{ - memset(map, 0, sizeof(*map)); - - map->url = url; - map->path = path; - map->tmppath = path; - map->name = strrchr(path, '/') + 1; -} - START_TEST(test_parse_notification_ok) { - struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-ok.xml"); - ck_assert_int_eq(0, parse_notification(&map, ¬if)); + ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + "resources/rrdp/notif-ok.xml", ¬if)); - ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); + ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", + (char const *)notif.session.session_id); ck_assert_str_eq("3", (char const *)notif.session.serial.str); ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); @@ -495,12 +471,14 @@ START_TEST(test_parse_notification_ok) ck_assert_uint_eq(2, notif.deltas.len); ck_assert_str_eq("2", (char const *)notif.deltas.array[0].serial.str); - ck_assert_str_eq("https://host/9d-8/2/delta.xml", notif.deltas.array[0].meta.uri); + ck_assert_str_eq("https://host/9d-8/2/delta.xml", + notif.deltas.array[0].meta.uri); ck_assert_uint_eq(32, notif.deltas.array[0].meta.hash_len); validate_01234_hash(notif.deltas.array[0].meta.hash); ck_assert_str_eq("3", (char const *)notif.deltas.array[1].serial.str); - ck_assert_str_eq("https://host/9d-8/3/delta.xml", notif.deltas.array[1].meta.uri); + ck_assert_str_eq("https://host/9d-8/3/delta.xml", + notif.deltas.array[1].meta.uri); ck_assert_uint_eq(32, notif.deltas.array[1].meta.hash_len); validate_01234_hash(notif.deltas.array[0].meta.hash); @@ -511,14 +489,14 @@ END_TEST START_TEST(test_parse_notification_0deltas) { - struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-0deltas.xml"); - ck_assert_int_eq(0, parse_notification(&map, ¬if)); + ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + "resources/rrdp/notif-0deltas.xml", ¬if)); - ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); + ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", + (char const *)notif.session.session_id); ck_assert_str_eq("3", (char const *)notif.session.serial.str); ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); @@ -538,17 +516,19 @@ START_TEST(test_parse_notification_large_serial) struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-large-serial.xml"); - ck_assert_int_eq(0, parse_notification(&map, ¬if)); + ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + "resources/rrdp/notif-large-serial.xml", ¬if)); - ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); + ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", + (char const *)notif.session.session_id); /* * This seems to be the largest positive integer libxml2 supports, * at least by default. It's significantly larger than 2^64. * It's not as many digits as I was expecting though. * Maybe research if it's possible to increase it further. */ - ck_assert_str_eq("999999999999999999999999", (char const *)notif.session.serial.str); + ck_assert_str_eq("999999999999999999999999", + (char const *)notif.session.serial.str); ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); @@ -564,12 +544,11 @@ END_TEST static void test_parse_notification_error(char *file) { - struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_map(&map, "https://host/notification.xml", file); - ck_assert_int_eq(-EINVAL, parse_notification(&map, ¬if)); + ck_assert_int_eq(-EINVAL, + parse_notification("https://host/notification.xml", file, ¬if)); relax_ng_cleanup(); } diff --git a/test/rrdp_update_test.c b/test/rrdp_update_test.c index 2896e42e..303fc904 100644 --- a/test/rrdp_update_test.c +++ b/test/rrdp_update_test.c @@ -3,9 +3,15 @@ #include "alloc.c" #include "base64.c" #include "cachent.c" +#include "cachetmp.c" +#include "cache_util.c" #include "common.c" +#include "file.c" +#include "hash.c" #include "json_util.c" #include "mock.c" +#include "mock_https.c" +#include "relax_ng.c" #include "rrdp.c" #include "types/path.c" #include "types/url.c" @@ -14,59 +20,41 @@ MOCK_VOID(fnstack_push, char const *file) MOCK_VOID(fnstack_pop, void) -MOCK_UINT(config_get_rrdp_delta_threshold, 5, void) MOCK_VOID(__delete_node_cb, struct cache_node const *node) -MOCK(hash_get_sha256, struct hash_algorithm const *, NULL, void) -MOCK_INT(hash_validate_file, 0, struct hash_algorithm const *algorithm, - char const *path, unsigned char const *expected, size_t expected_len) -MOCK_INT(file_write_full, 0, char const *path, unsigned char *content, - size_t content_len) - -int -cache_tmpfile(char **filename) + +/* Utils */ + +static void +setup_test(void) { - *filename = pstrdup("tmp/a"); - return 0; + ck_assert_int_eq(0, system("rm -rf tmp/")); + ck_assert_int_eq(0, system("mkdir -p tmp/rsync tmp/https tmp/tmp")); + ck_assert_int_eq(0, hash_setup()); + ck_assert_int_eq(0, relax_ng_init()); } -int -http_download(char const *url, char const *path, curl_off_t ims, bool *changed) +static void +cleanup_test(void) { - printf("http_download(): %s -> %s\n", url, path); - if (changed) - *changed = true; - return 0; +// ck_assert_int_eq(0, system("rm -rf tmp/")); + hash_teardown(); + relax_ng_cleanup(); } -static char const *dls[8]; -static unsigned int d; - -int -relax_ng_parse(const char *path, xml_read_cb cb, void *arg) +static void +ck_file(char const *path) { - xmlTextReaderPtr reader; - int read; - - /* TODO (warning) "XML_CHAR_ENCODING_NONE" */ - reader = xmlReaderForMemory(dls[d], strlen(dls[d]), path, "UTF-8", 0); - if (reader == NULL) - return pr_val_err("Unable to open %s (Cause unavailable).", path); - d++; - - while ((read = xmlTextReaderRead(reader)) == 1) { -// ck_assert_int_eq(1, xmlTextReaderIsValid(reader)); - ck_assert_int_eq(0, cb(reader, arg)); - } - - ck_assert_int_eq(read, 0); -// ck_assert_int_eq(1, xmlTextReaderIsValid(reader)); - - xmlFreeTextReader(reader); - return 0; + FILE *file; + char buffer[8] = { 0 }; + + file = fopen(path, "rb"); + ck_assert_ptr_ne(NULL, file); + ck_assert_int_eq(5, fread(buffer, 1, 8, file)); + ck_assert_int_ne(0, feof(file)); + ck_assert_int_eq(0, fclose(file)); + ck_assert_str_eq("Fort\n", buffer); } -/* Tests */ - #define NHDR(serial) "" c "" +/* Tests */ + START_TEST(startup) { +#define NOTIF_PATH "tmp/https/host/notification.xml" struct cache_node notif; + setup_test(); + memset(¬if, 0, sizeof(notif)); notif.url = "https://host/notification.xml"; - notif.path = "tmp/https/host/notification.xml"; + notif.path = NOTIF_PATH; notif.name = "notification.xml"; dls[0] = NHDR("3") - NSS("https://host/9d-8/3/snapshot.xml", "0123456789abcdefABCDEF0123456789abcdefABCDEF0123456789abcdefABCD") + NSS("https://host/9d-8/3/snapshot.xml", "0c84fb949e7b5379ae091b86c41bb1a33cb91636b154b86ad1b1dedd44651a25") NTAIL; - dls[1] = SHDR("3") PBLSH("rsync://a/b/c.cer", "Rm9ydA==") STAIL; + dls[1] = SHDR("3") PBLSH("rsync://a/b/c.cer", "Rm9ydAo=") STAIL; dls[2] = NULL; - d = 0; + https_counter = 0; ck_assert_int_eq(0, rrdp_update(¬if)); + ck_assert_uint_eq(2, https_counter); + ck_file("tmp/tmp/0/a/b/c.cer"); + ck_assert_cachent_eq( + ruftnode("rsync://", NOTIF_PATH, 0, "tmp/tmp/0", + ruftnode("rsync://a", NOTIF_PATH "/a", 0, "tmp/tmp/0/a", + ruftnode("rsync://a/b", NOTIF_PATH "/a/b", 0, "tmp/tmp/0/a/b", + ruftnode("rsync://a/b/c.cer", NOTIF_PATH "/a/b/c.cer", 0, "tmp/tmp/0/a/b/c.cer", NULL), + NULL), + NULL), + NULL), + notif.rrdp.subtree + ); + + dls[1] = NULL; + https_counter = 0; + ck_assert_int_eq(0, rrdp_update(¬if)); + ck_assert_uint_eq(1, https_counter); + ck_file("tmp/tmp/0/a/b/c.cer"); + ck_assert_cachent_eq( + ruftnode("rsync://", NOTIF_PATH, 0, "tmp/tmp/0", + ruftnode("rsync://a", NOTIF_PATH "/a", 0, "tmp/tmp/0/a", + ruftnode("rsync://a/b", NOTIF_PATH "/a/b", 0, "tmp/tmp/0/a/b", + ruftnode("rsync://a/b/c.cer", NOTIF_PATH "/a/b/c.cer", 0, "tmp/tmp/0/a/b/c.cer", NULL), + NULL), + NULL), + NULL), + notif.rrdp.subtree + ); + + cleanup_test(); } END_TEST diff --git a/test/rtr/db/deltas_array_test.c b/test/rtr/db/deltas_array_test.c index b48d6fd0..4676ea8f 100644 --- a/test/rtr/db/deltas_array_test.c +++ b/test/rtr/db/deltas_array_test.c @@ -13,11 +13,7 @@ #define TOTAL_CREATED 15 static struct deltas *created[TOTAL_CREATED]; -unsigned int -config_get_deltas_lifetime(void) -{ - return 5; -} +MOCK_UINT(config_get_deltas_lifetime, 5, void) static int foreach_cb(struct deltas *deltas, void *arg)