]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Thursday
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 11 Jul 2024 22:22:14 +0000 (16:22 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 12 Jul 2024 17:34:49 +0000 (11:34 -0600)
16 files changed:
src/cache/cachent.h
src/cache/local_cache.c
src/common.c
src/common.h
src/file.c
src/file.h
src/rrdp.c
src/rrdp.h
test/Makefile.am
test/cache/cachent_test.c
test/cache/common.c [deleted file]
test/cache/common.h [deleted file]
test/cache/local_cache_test.c
test/cache/util.c [new file with mode: 0644]
test/cache/util.h [new file with mode: 0644]
test/mock.c

index 5f9107b78be83585e3889ab82bffb700eca99542..7443b7932882dcce2b672fdc1a648ab106cd5527 100644 (file)
@@ -8,6 +8,7 @@
 
 /* XXX rename "touched" and "validated" into "preserve"? */
 
+// XXX trees now separated; consider removing this flag
 #define CNF_RSYNC              (1 << 0)
 /*
  * Do we have a (full) copy in the cache?
 
 // XXX rename to cache_entity or cachent
 struct cache_node {
-       char const *name; /* Points to the last component of @url */
+       char const *name;       /* Points to the last component of @url XXX redundant */
        char *url;
        int flags;
-       /* Last successful download time, or zero */
-       time_t mtim;
+
+       int dlerr;              /* Result code of recent download attempt */
+       time_t mtim;            /* Last successful download time, or zero */
+
        /*
         * If flags & CNF_FRESH, path to the temporal directory where we
         * downloaded the latest refresh.
@@ -60,17 +63,13 @@ struct cache_node {
         */
        char *tmpdir;
 
-       struct cache_node *rpp; // XXX delete?
-
-       /* Only if flags & CNF_NOTIFICATION. */
+       /* Only if flags & CNF_NOTIFICATION */
 //     struct cachefile_notification notif;
 
-       /* Tree parent. Only defined during cleanup. */
-       struct cache_node *parent;
-       /* Tree children. */
-       struct cache_node *children;
+       struct cache_node *parent;      /* Tree parent */
+       struct cache_node *children;    /* Tree children */
 
-       UT_hash_handle hh; /* Hash table hook */
+       UT_hash_handle hh;              /* Hash table hook */
 };
 
 struct cache_node *cachent_create_root(char const *);
index 52cba691fbdc3bc34cada13c6466f478ab4a4d9f..2b0d64471c79e98cf908dc8aa05c7b441c96a673 100644 (file)
@@ -3,6 +3,7 @@
  *
  * - We only need to keep nodes for the rsync root.
  * - The tree traverse only needs to touch files.
+ * - RRDP needs caging.
  */
 
 #include "cache/local_cache.h"
@@ -241,16 +242,16 @@ cache_tmpfile(char **filename)
        return 0;
 }
 
-static char *
-get_tal_json_filename(void)
-{
-       struct path_builder pb;
-       return pb_init_cache(&pb, TAL_METAFILE) ? NULL : pb.string;
-}
-
-static struct cache_node *
-json2node(json_t *json)
-{
+//static char *
+//get_tal_json_filename(void)
+//{
+//     struct path_builder pb;
+//     return pb_init_cache(&pb, TAL_METAFILE) ? NULL : pb.string;
+//}
+//
+//static struct cache_node *
+//json2node(json_t *json)
+//{
 //     struct cache_node *node;
 //     char const *type_str;
 //     enum map_type type;
@@ -330,8 +331,8 @@ json2node(json_t *json)
 //     map_refput(node->map);
 //     rrdp_notif_free(node->notif);
 //     free(node);
-       return NULL;
-}
+//     return NULL;
+//}
 
 static void
 load_tal_json(void)
@@ -388,9 +389,9 @@ cache_prepare(void)
        load_tal_json();
 }
 
-static json_t *
-node2json(struct cache_node *node)
-{
+//static json_t *
+//node2json(struct cache_node *node)
+//{
 //     json_t *json;
 //     char const *type;
 //     json_t *notification;
@@ -434,19 +435,19 @@ node2json(struct cache_node *node)
 //
 //cancel:
 //     json_decref(json);
-       return NULL;
-}
-
-static json_t *
-build_tal_json(struct rpki_cache *cache)
-{
+//     return NULL;
+//}
+//
+//static json_t *
+//build_tal_json(struct rpki_cache *cache)
+//{
 //     struct cache_node *node, *tmp;
 //     json_t *root, *child;
 //
 //     root = json_array_new();
 //     if (root == NULL)
-               return NULL;
-
+//             return NULL;
+//
 //     HASH_ITER(hh, cache->ht, node, tmp) {
 //             child = node2json(node);
 //             if (child != NULL && json_array_append_new(root, child)) {
@@ -457,7 +458,7 @@ build_tal_json(struct rpki_cache *cache)
 //     }
 //
 //     return root;
-}
+//}
 
 static void
 write_tal_json(void)
@@ -529,28 +530,28 @@ get_rsync_module(struct cache_node *node)
        return node;
 }
 
-static struct cache_node *
-get_rsync_rpp(char const *caRepository, struct cache_node *rpkiManifest)
+static int
+dl_rrdp(struct cache_node *rpp)
 {
-       struct cache_node *node;
-       char *normal;
+       int error;
 
-       normal = url_normalize(caRepository);
-       if (normal == NULL)
-               return NULL;
+       if (!config_get_http_enabled()) {
+               pr_val_debug("HTTP is disabled.");
+               return 1;
+       }
 
-       for (node = rpkiManifest; node != NULL; node = node->parent)
-               if (strcmp(node->url, normal) == 0) {
-                       free(normal);
-                       return node;
-               }
+       // XXX needs to add all files to node.
+       // Probably also update node itself.
+       // XXX maybe pr_crit() on !mft->parent?
+       error = rrdp_update(rpp);
+       if (error)
+               pr_val_debug("RRDP RPP: Failed refresh.");
 
-       free(normal);
-       return NULL;
+       return error;
 }
 
 static int
-dl_rsync(char const *caRepository, struct cache_node *mft)
+dl_rsync(struct cache_node *rpp)
 {
        struct cache_node *module, *node;
        char *path;
@@ -561,14 +562,9 @@ dl_rsync(char const *caRepository, struct cache_node *mft)
                return 1;
        }
 
-       module = get_rsync_module(mft);
-       if (module == NULL) {
+       module = get_rsync_module(rpp);
+       if (module == NULL)
                return -EINVAL; // XXX
-       }
-       mft->rpp = get_rsync_rpp(caRepository, mft);
-       if (!mft->rpp)
-               return pr_val_err("Manifest '%s' does not seem to be inside its publication point '%s'.",
-                   mft->url, caRepository);
 
        error = cache_tmpfile(&path);
        if (error)
@@ -585,19 +581,15 @@ dl_rsync(char const *caRepository, struct cache_node *mft)
        module->mtim = time(NULL); // XXX catch -1
        module->tmpdir = path;
 
-       for (node = mft; node != module; node = node->parent) {
+       for (node = rpp; node != module; node = node->parent) {
                node->flags |= RSYNC_INHERIT;
                node->mtim = module->mtim;
-               if (mft) {
-                       node->rpp = mft->rpp;
-                       if (node == mft->rpp)
-                               mft = NULL;
-               }
        }
 
        return 0;
 }
 
+/*
 static int
 dl_http(struct cache_node *node)
 {
@@ -608,73 +600,51 @@ dl_http(struct cache_node *node)
 
        return http_download_cache_node(node);
 }
+*/
 
+/* @uri is either a caRepository or a rpkiNotify */
 static int
-dl_rrdp(char const *notif_url, struct cache_node *mft)
-{
-       if (!config_get_http_enabled()) {
-               pr_val_debug("HTTP is disabled.");
-               return 1;
-       }
-
-       // XXX needs to add all files to node. Probably also update node itself.
-       // XXX maybe pr_crit() on !mft->parent?
-       return rrdp_update(cachent_provide(cache.https, notif_url), mft->parent);
-
-//     node->flags |= CNF_FRESH;
-//     node->mtim = time(NULL); // XXX catch -1
-//     node->tmpdir = path;
-}
-
-static int
-download(char const *uri, enum map_type type, struct cache_node *mft)
+try_uri(char const *uri, int (*download)(struct cache_node *),
+    maps_dl_cb validate, void *arg)
 {
-       switch (type) {
-       case MAP_RSYNC:
-               return dl_rsync(uri, mft);
-       case MAP_HTTP:
-               return dl_http(mft);
-       case MAP_NOTIF:
-               return dl_rrdp(uri, mft);
-       }
+       struct cache_node *rpp;
+       int error;
 
-       pr_crit("Unreachable.");
-       return -EINVAL; /* Warning shutupper */
-}
+       if (!uri)
+               return 1; /* Protocol unavailable; ignore */
 
-/*
- * XXX review result sign
- *
- * uri is a rpkiNotify or a caRepository.
- */
-static int
-try_uri(struct cache_node *mft, char const *uri, enum map_type type,
-    bool online, maps_dl_cb cb, void *arg)
-{
-       int error;
+       pr_val_debug("Trying %s (%s)...", uri, download ? "online" : "offline");
 
-       pr_val_debug("Trying %s...", uri);
+       rpp = cachent_provide(cache.rsync, uri);
+       if (!rpp)
+               return pr_val_err("Malformed URL: %s", uri);
 
-       if (online) {
-               error = download(uri, type, mft);
-               if (error) {
-                       pr_val_debug("RPP refresh failed.");
-                       return error;
+       if (download != NULL) {
+               if (rpp->flags & CNF_FRESH) {
+                       if (rpp->dlerr)
+                               return rpp->dlerr;
+               } else {
+                       rpp->flags |= CNF_FRESH;
+                       error = rpp->dlerr = download(rpp);
+                       if (error)
+                               return error;
                }
        }
 
-       error = cb(mft->rpp, arg);
+       error = validate(rpp, arg);
        if (error) {
                pr_val_debug("RPP validation failed.");
                return error;
        }
 
        /* XXX commit the files (later, during cleanup) */
-       pr_val_debug("RPP downloaded and validated successfully.");
+       pr_val_debug("RPP validated successfully.");
        return 0;
 }
 
 /**
+ * XXX outdated comment
+ *
  * Assumes the URIs represent different ways to access the same content.
  *
  * Sequentially (in the order dictated by their priorities) attempts to update
@@ -688,31 +658,32 @@ try_uri(struct cache_node *mft, char const *uri, enum map_type type,
 int
 cache_download_alt(struct sia_uris *uris, maps_dl_cb cb, void *arg)
 {
-       struct cache_node *mft;
-       int online;
-       int error = 0;
+       int error;
 
-       /* XXX mutex */
-       /* XXX if parent is downloaded, child is downloaded. */
-       mft = cachent_provide(cache.rsync, uris->rpkiManifest);
+       // XXX Make sure somewhere validates rpkiManifest matches caRepository.
 
-       if (mft->flags & CNF_FRESH)
-               return cb(mft->rpp, arg); // XXX can rpp be NULL?
+       /* 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?
 
-       for (online = 1; online >= 0; online--) {
-               if (uris->rpkiNotify) {
-                       error = try_uri(mft, uris->rpkiNotify, MAP_NOTIF,
-                           online, cb, arg);
-                       if (error <= 0)
-                               return error;
-               }
-               error = try_uri(mft, uris->caRepository, MAP_RSYNC,
-                   online, cb, arg);
-               if (error <= 0)
-                       return error;
-       }
+       /* Online attempts */
+       // XXX review result signs
+       // XXX normalize rpkiNotify & caRepository?
+       error = try_uri(uris->rpkiNotify, dl_rrdp, cb, arg);
+       if (error <= 0)
+               return error;
+       error = try_uri(uris->caRepository, dl_rsync, cb, arg);
+       if (error <= 0)
+               return error;
 
-       return error;
+       /* Offline attempts */
+       error = try_uri(uris->rpkiNotify, NULL, cb, arg);
+       if (error <= 0)
+               return error;
+       return try_uri(uris->caRepository, NULL, cb, arg);
 }
 
 void
@@ -729,6 +700,8 @@ cache_print(void)
 static bool
 commit_rpp_delta(struct cache_node *node, char const *path)
 {
+       PR_DEBUG_MSG("Commiting %s", node->url);
+
        if (node->tmpdir == NULL)
                return true; /* Not updated */
 
@@ -775,30 +748,30 @@ commit_rpp_delta(struct cache_node *node, char const *path)
 //
 //     delete_node(cache, node);
 //}
-//
-//static time_t
-//get_days_ago(int days)
-//{
-//     time_t tt_now, last_week;
-//     struct tm tm;
-//     int error;
-//
-//     tt_now = time(NULL);
-//     if (tt_now == (time_t) -1)
-//             pr_crit("time(NULL) returned (time_t) -1.");
-//     if (localtime_r(&tt_now, &tm) == NULL) {
-//             error = errno;
-//             pr_crit("localtime_r(tt, &tm) returned error: %s",
-//                 strerror(error));
-//     }
-//     tm.tm_mday -= days;
-//     last_week = mktime(&tm);
-//     if (last_week == (time_t) -1)
-//             pr_crit("mktime(tm) returned (time_t) -1.");
-//
-//     return last_week;
-//}
-//
+
+static time_t
+get_days_ago(int days)
+{
+       time_t tt_now, last_week;
+       struct tm tm;
+       int error;
+
+       tt_now = time(NULL);
+       if (tt_now == (time_t) -1)
+               pr_crit("time(NULL) returned (time_t) -1.");
+       if (localtime_r(&tt_now, &tm) == NULL) {
+               error = errno;
+               pr_crit("localtime_r(tt, &tm) returned error: %s",
+                   strerror(error));
+       }
+       tm.tm_mday -= days;
+       last_week = mktime(&tm);
+       if (last_week == (time_t) -1)
+               pr_crit("mktime(tm) returned (time_t) -1.");
+
+       return last_week;
+}
+
 //static void
 //cleanup_tmp(struct rpki_cache *cache, struct cache_node *node)
 //{
@@ -898,6 +871,8 @@ nftw_remove_abandoned(const char *path, const struct stat *st,
        struct cache_node *msm; /* Most Specific Match */
        struct timespec now;
 
+       PR_DEBUG_MSG("Removing potentially abandoned %s", path);
+
        /* XXX node->parent has to be set */
        pm = find_msm(nftw_root, pstrdup(path), &msm);
        if (!pm && !(msm->flags & CNF_RSYNC))
index daaaa7af98a53b5712b3a4758267a4b6c7adcd3e..4db2093b003bbc0115798d1f04b3b0e3b914f0d9 100644 (file)
@@ -238,6 +238,91 @@ 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)
+{
+       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;
+}
+
+static int
+ensure_dir(char const *path)
+{
+       int error;
+
+       if (mkdir(path, 0777) != 0) {
+               error = errno;
+               if (error != EEXIST) {
+                       pr_op_err_st("Error while making directory '%s': %s",
+                           path, strerror(error));
+                       return error;
+               }
+       }
+
+       return 0;
+}
+
+/* mkdir -p $_path */
+/* XXX Maybe also short-circuit by parent? */
+int
+mkdir_p(char const *_path, bool include_basename)
+{
+       char *path, *last_slash;
+       int i, result = 0;
+
+       path = pstrdup(_path); /* Remove const */
+
+       if (!include_basename) {
+               last_slash = strrchr(path, '/');
+               if (last_slash == NULL)
+                       goto end;
+               *last_slash = '\0';
+       }
+
+       result = dir_exists(path); /* short circuit */
+       if (result > 0) {
+               result = 0;
+               goto end;
+       } else if (result < 0) {
+               goto end;
+       }
+
+       for (i = 1; path[i] != '\0'; i++) {
+               if (path[i] == '/') {
+                       path[i] = '\0';
+                       result = ensure_dir(path);
+                       path[i] = '/';
+                       if (result != 0)
+                               goto end; /* error msg already printed */
+               }
+       }
+       result = ensure_dir(path);
+
+end:
+       free(path);
+       return result;
+}
+
 /*
  * Delete @path.
  * If path's parent is now empty, delete parent as well.
index 6a3989e94da866ad357bd9a47b43ba359fbefd2f..34333dcf3d52736aec4a963802f1dc1065cd92a2 100644 (file)
@@ -50,6 +50,8 @@ int foreach_file(char const *, char const *, bool, foreach_file_cb, void *);
 
 // XXX
 bool valid_file_or_dir(char const *, bool);
+
+int mkdir_p(char const *, bool);
 int delete_dir_recursive_bottom_up(char const *);
 
 int get_current_time(time_t *);
index 81a5057201c9137836c220ce74832752fc0d31a1..0f83e457b9429ed57547f96d7e6b4429c1d2cebf 100644 (file)
@@ -169,88 +169,3 @@ file_rm_rf(char const *path)
        /* TODO (performance) optimize that 32 */
        return nftw(path, rm, 32, FTW_DEPTH | FTW_PHYS);
 }
-
-/*
- * > 0: exists
- * = 0: !exists
- * < 0: error
- */
-static int
-dir_exists(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;
-}
-
-static int
-ensure_dir(char const *path)
-{
-       int error;
-
-       if (mkdir(path, 0777) != 0) {
-               error = errno;
-               if (error != EEXIST) {
-                       pr_op_err_st("Error while making directory '%s': %s",
-                           path, strerror(error));
-                       return error;
-               }
-       }
-
-       return 0;
-}
-
-/* mkdir -p $_path */
-/* XXX Maybe also short-circuit by parent? */
-int
-mkdir_p(char const *_path, bool include_basename)
-{
-       char *path, *last_slash;
-       int i, result = 0;
-
-       path = pstrdup(_path); /* Remove const */
-
-       if (!include_basename) {
-               last_slash = strrchr(path, '/');
-               if (last_slash == NULL)
-                       goto end;
-               *last_slash = '\0';
-       }
-
-       result = dir_exists(path); /* short circuit */
-       if (result > 0) {
-               result = 0;
-               goto end;
-       } else if (result < 0) {
-               goto end;
-       }
-
-       for (i = 1; path[i] != '\0'; i++) {
-               if (path[i] == '/') {
-                       path[i] = '\0';
-                       result = ensure_dir(path);
-                       path[i] = '/';
-                       if (result != 0)
-                               goto end; /* error msg already printed */
-               }
-       }
-       result = ensure_dir(path);
-
-end:
-       free(path);
-       return result;
-}
index 0d1fd8c7e5d6f0f46296c14c5ef20f4837f05c23..1de125ae8e166fdce736a21c8d81f61a55370149 100644 (file)
@@ -36,8 +36,6 @@ int file_merge_into(char const *, char const *);
 int file_rm_f(char const *);
 int file_rm_rf(char const *);
 
-int mkdir_p(char const *, bool);
-
 /*
  * Remember that this API is awkward:
  *
index d616d76d3ed9f488dcfac66624bba9b2f3853546..6bee4e32b5e7152807889d062d4ef8fffc37cbc4 100644 (file)
@@ -1093,7 +1093,7 @@ update_notif(struct cachefile_notification *old, struct update_notification *new
  * snapshot, and explodes them into @rpp's tmp directory.
  */
 int
-rrdp_update(struct cache_node *notif, struct cache_node *rpp)
+rrdp_update(struct cache_node *notif)
 {
        char *path = NULL;
        struct cachefile_notification *old;
index 899500102137ec9bc7d02fb40a42bd479ec0931f..3800c9f97fe3ec540cde7a1d575190287fc06ea4 100644 (file)
@@ -6,7 +6,7 @@
 struct cachefile_notification;
 struct cache_node;
 
-int rrdp_update(struct cache_node *, struct cache_node *);
+int rrdp_update(struct cache_node *);
 
 json_t *rrdp_notif2json(struct cachefile_notification *);
 int rrdp_json2notif(json_t *, struct cachefile_notification **);
index a0ff28aa5e9a32f6483a615fef60ac4030a0b276..a2805cbb5f62e78f064a346b552fbcd6a762368d 100644 (file)
@@ -23,7 +23,7 @@ AM_CFLAGS += -I../src -DUNIT_TESTING ${CHECK_CFLAGS} ${XML2_CFLAGS} ${JANSSON_CF
 MY_LDADD = ${CHECK_LIBS} ${JANSSON_LIBS}
 
 check_PROGRAMS  = url.test
-#check_PROGRAMS += cachent.test
+check_PROGRAMS += cachent.test
 check_PROGRAMS += cache.test
 TESTS = ${check_PROGRAMS}
 
index 17df8b42244e33fcda7bb7f95a1121992be6f428..8bbe63883be730c5921771951fa147f69dd5f6e4 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "alloc.c"
 #include "cache/cachent.c"
-#include "cache/common.c"
+#include "cache/util.c"
 #include "data_structure/path_builder.c"
 #include "mock.c"
 #include "types/url.c"
@@ -20,14 +20,14 @@ START_TEST(test_delete)
 {
        struct cache_node *root, *a, *b;
 
-       a = node("a", 0, NULL);
+       a = unode("a", NULL);
        dn = 0;
        cachent_delete(a);
        ck_assert_uint_eq(1, dn);
        ck_assert_str_eq("a", deleted[0]);
 
-       a = node("a", 0, NULL);
-       root = node("root", 0, a, NULL);
+       a = unode("a", NULL);
+       root = unode("root", 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("root", deleted[0]);
 
-       b = node("b", 0,
-                       node("c", 0, NULL),
-                       node("d", 0, NULL),
-                       node("e", 0, NULL),
-                       node("f", 0, NULL), NULL);
-       a = node("a", 0,
+       b = unode("b",
+                       unode("c", NULL),
+                       unode("d", NULL),
+                       unode("e", NULL),
+                       unode("f", NULL), NULL);
+       a = unode("a",
                b,
-               node("g", 0,
-                       node("h", 0,
-                               node("i", 0, NULL), NULL),
-                       node("j", 0,
-                               node("k", 0, NULL), NULL),
-                       node("l", 0,
-                               node("m", 0, NULL), NULL),
-                       node("n", 0,
-                               node("o", 0, NULL), NULL), NULL), NULL);
-       root = node("root", 0, a, NULL);
+               unode("g",
+                       unode("h",
+                               unode("i", NULL), NULL),
+                       unode("j",
+                               unode("k", NULL), NULL),
+                       unode("l",
+                               unode("m", NULL), NULL),
+                       unode("n",
+                               unode("o", NULL), NULL), NULL), NULL);
+       root = unode("root", a, NULL);
 
        dn = 0;
        cachent_delete(b);
@@ -124,36 +124,36 @@ START_TEST(test_traverse)
        root = NULL;
        ck_traverse(root, NULL);
 
-       root =  node("a", 0, NULL);
+       root =  unode("a", NULL);
        ck_traverse(root, "tmp/a", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0, NULL), NULL);
+       root =  unode("a",
+                       unode("b", NULL), NULL);
        ck_traverse(root, "tmp/a", "tmp/a/b", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0,
-                               node("c", 0, NULL), NULL), NULL);
+       root =  unode("a",
+                       unode("b",
+                               unode("c", NULL), NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
                "tmp/a/b/c", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0,
-                               node("c", 0, NULL),
-                               node("d", 0, NULL), NULL), NULL);
+       root =  unode("a",
+                       unode("b",
+                               unode("c", NULL),
+                               unode("d", NULL), NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
                "tmp/a/b/c",
                "tmp/a/b/d", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0,
-                               node("c", 0, NULL),
-                               node("d", 0, NULL), NULL),
-                       node("e", 0, NULL), NULL);
+       root =  unode("a",
+                       unode("b",
+                               unode("c", NULL),
+                               unode("d", NULL), NULL),
+                       unode("e", NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
@@ -161,11 +161,11 @@ START_TEST(test_traverse)
                "tmp/a/b/d",
                "tmp/a/e", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0, NULL),
-                       node("c", 0,
-                               node("d", 0, NULL),
-                               node("e", 0, NULL), NULL), NULL);
+       root =  unode("a",
+                       unode("b", NULL),
+                       unode("c",
+                               unode("d", NULL),
+                               unode("e", NULL), NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
@@ -173,13 +173,13 @@ START_TEST(test_traverse)
                "tmp/a/c/d",
                "tmp/a/c/e", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0,
-                               node("c", 0, NULL),
-                               node("d", 0, NULL), NULL),
-                       node("e", 0,
-                               node("f", 0, NULL),
-                               node("g", 0, NULL), NULL), NULL);
+       root =  unode("a",
+                       unode("b",
+                               unode("c", NULL),
+                               unode("d", NULL), NULL),
+                       unode("e",
+                               unode("f", NULL),
+                               unode("g", NULL), NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
@@ -189,21 +189,21 @@ START_TEST(test_traverse)
                "tmp/a/e/f",
                "tmp/a/e/g", NULL);
 
-       root =  node("a", 0,
-                       node("b", 0,
-                               node("c", 0, NULL),
-                               node("d", 0, NULL),
-                               node("e", 0, NULL),
-                               node("f", 0, NULL), NULL),
-                       node("g", 0,
-                               node("h", 0,
-                                       node("i", 0, NULL), NULL),
-                               node("j", 0,
-                                       node("k", 0, NULL), NULL),
-                               node("l", 0,
-                                       node("m", 0, NULL), NULL),
-                               node("n", 0,
-                                       node("o", 0, NULL), NULL), NULL), NULL);
+       root =  unode("a",
+                       unode("b",
+                               unode("c", NULL),
+                               unode("d", NULL),
+                               unode("e", NULL),
+                               unode("f", NULL), NULL),
+                       unode("g",
+                               unode("h",
+                                       unode("i", NULL), NULL),
+                               unode("j",
+                                       unode("k", NULL), NULL),
+                               unode("l",
+                                       unode("m", NULL), NULL),
+                               unode("n",
+                                       unode("o", NULL), NULL), NULL), NULL);
        ck_traverse(root,
                "tmp/a",
                "tmp/a/b",
diff --git a/test/cache/common.c b/test/cache/common.c
deleted file mode 100644 (file)
index ebb67dc..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "cache/common.h"
-
-#include <stdarg.h>
-#include <string.h>
-#include "data_structure/uthash.h"
-
-struct cache_node *
-node(char const *url, int flags, char const *tmpdir, ...)
-{
-       struct cache_node *result;
-       struct cache_node *child;
-       char const *slash;
-       va_list args;
-
-       result = pzalloc(sizeof(struct cache_node));
-       result->url = pstrdup(url);
-       slash = strrchr(url, '/');
-       result->name = slash ? (slash + 1) : result->url;
-       result->flags = flags;
-       result->tmpdir = tmpdir ? pstrdup(tmpdir) : NULL;
-
-       va_start(args, tmpdir);
-       while ((child = va_arg(args, struct cache_node *)) != NULL) {
-               HASH_ADD_KEYPTR(hh, result->children, child->name,
-                   strlen(child->name), child);
-               child->parent = result;
-       }
-       va_end(args);
-
-       return result;
-}
diff --git a/test/cache/common.h b/test/cache/common.h
deleted file mode 100644 (file)
index d8b2ec3..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef TEST_CACHE_COMMON_H_
-#define TEST_CACHE_COMMON_H_
-
-#include "cache/cachent.h"
-
-struct cache_node *node(char const *, int , char const *, ...);
-
-#endif /* TEST_CACHE_COMMON_H_ */
index 5b99e27ad106d30ed018cd9b762ec4d355dbf339..03571a3beac455b98df4ec8974c79eb700e47402 100644 (file)
@@ -8,18 +8,20 @@
 #include <sys/queue.h>
 
 #include "alloc.c"
+#include "common.c"
 //#include "json_util.c"
 #include "mock.c"
 #include "cache/cachent.c"
-#include "cache/common.c"
 #include "cache/local_cache.c"
+#include "cache/util.c"
 #include "data_structure/path_builder.c"
 #include "types/str.c"
 #include "types/url.c"
 
 /* Mocks */
 
-static bool dl_error; /* Download should return error? */
+static unsigned int rsync_counter; /* Times the rsync function was called */
+static unsigned int https_counter; /* Times the https function was called */
 
 struct downloaded_path {
        char *path;
@@ -27,18 +29,24 @@ struct downloaded_path {
        SLIST_ENTRY(downloaded_path) hook;
 };
 
+
+static bool dl_mock_type; /* false = list. true = list + actual files */
+static int dl_error;
+
 /* Paths downloaded during the test */
 static SLIST_HEAD(downloaded_paths, downloaded_path) downloaded;
 
-static unsigned int rsync_counter; /* Times the rsync function was called */
-static unsigned int https_counter; /* Times the https function was called */
-
 int
-file_exists(char const *file)
+file_exists(char const *path)
 {
-       struct downloaded_path *path;
-       SLIST_FOREACH(path, &downloaded, hook)
-               if (strcmp(file, path->path) == 0)
+       struct stat meta;
+       struct downloaded_path *dp;
+
+       if (dl_mock_type)
+               return (stat(path, &meta) == 0) ? 0 : errno;
+
+       SLIST_FOREACH(dp, &downloaded, hook)
+               if (strcmp(path, dp->path) == 0)
                        return 0;
        return ENOENT;
 }
@@ -47,13 +55,17 @@ int
 file_rm_rf(char const *file)
 {
        struct downloaded_path *path;
+
        SLIST_FOREACH(path, &downloaded, hook)
                if (strcmp(file, path->path) == 0) {
                        SLIST_REMOVE(&downloaded, path, downloaded_path, hook);
                        free(path->path);
                        free(path);
+                       if (dl_mock_type)
+                               ck_assert_int_eq(0, remove(file));
                        return 0;
                }
+
        return ENOENT;
 }
 
@@ -78,7 +90,7 @@ pretend_download(char const *local)
        struct downloaded_path *dl;
 
        if (dl_error)
-               return -EINVAL;
+               return dl_error;
        if (file_exists(local) == 0)
                return 0;
 
@@ -86,6 +98,10 @@ pretend_download(char const *local)
        dl->path = pstrdup(local);
        dl->visited = false;
        SLIST_INSERT_HEAD(&downloaded, dl, hook);
+
+       if (dl_mock_type)
+               ck_assert_int_eq(0, mkdir_p(local, true));
+
        return 0;
 }
 
@@ -107,17 +123,19 @@ http_download(char const *url, char const *path, curl_off_t ims, bool *changed)
        return error;
 }
 
-MOCK_ABORT_INT(rrdp_update, struct cache_node *notif, struct cache_node *rpp)
+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, get_days_ago(7), void)
 
 /* Helpers */
 
 static void
-setup_test(void)
+setup_test(bool dl_type)
 {
-       dl_error = false;
+       dl_error = 0;
+       dl_mock_type = dl_type;
        SLIST_INIT(&downloaded);
 
        ck_assert_int_eq(0, system("rm -rf tmp/"));
@@ -133,14 +151,14 @@ okay(struct cache_node *node, void *arg)
 }
 
 static void
-run_dl_rsync(char const *caRepository, char const *rpkiManifest,
-    int expected_error, unsigned int expected_calls)
+run_dl_rsync(char const *caRepository, int expected_error,
+    unsigned int expected_calls)
 {
        static struct sia_uris sias;
 
        sias.caRepository = pstrdup(caRepository);
        sias.rpkiNotify = NULL;
-       sias.rpkiManifest = pstrdup(rpkiManifest);
+       sias.rpkiManifest = NULL;
 
        rsync_counter = 0;
        https_counter = 0;
@@ -167,6 +185,9 @@ find_downloaded_path(struct cache_node *node)
        if (!node->tmpdir)
                return NULL;
 
+       if (dl_mock_type && !file_exists(node->tmpdir))
+               return NULL;
+
        SLIST_FOREACH(path, &downloaded, hook) {
                if (strcmp(node->tmpdir, path->path) == 0) {
                        if (path->visited)
@@ -184,6 +205,8 @@ check_path(struct cache_node *node, char const *_)
 {
        struct downloaded_path *path;
 
+       PR_DEBUG_MSG("Checking %s", node->url);
+
        path = find_downloaded_path(node);
        if (node->tmpdir) {
                if (path == NULL)
@@ -244,6 +267,8 @@ ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual)
 {
        struct cache_node *echild, *achild, *tmp;
 
+       PR_DEBUG_MSG("Comparing %s", expected->url);
+
        ck_assert_str_eq(expected->url, actual->url);
        ck_assert_str_eq(expected->name, actual->name);
        ck_assert_int_eq(expected->flags, actual->flags);
@@ -299,17 +324,29 @@ ck_cache(struct cache_node *rsync, struct cache_node *https)
        cachent_delete(https);
 }
 
-//static void
-//new_iteration(bool outdate)
-//{
-//     struct cache_node *node, *tmp;
-//     time_t epoch;
-//
-//     epoch = outdate ? get_days_ago(30) : get_days_ago(1);
-//     HASH_ITER(hh, cache->ht, node, tmp)
-//             node->attempt.ts = epoch;
-//}
-//
+static void
+ck_cache_rsync(struct cache_node *rsync)
+{
+       ck_cache(rsync, unode("https:", NULL));
+}
+
+static time_t epoch;
+
+static bool
+unfreshen(struct cache_node *node, char const *path)
+{
+       node->flags &= ~CNF_FRESH;
+       node->mtim = epoch;
+       return true;
+}
+
+static void
+new_iteration(bool outdate)
+{
+       epoch = outdate ? get_days_ago(30) : get_days_ago(1);
+       cachent_traverse(cache.rsync, unfreshen);
+}
+
 //static void
 //cache_reset(struct rpki_cache *cache)
 //{
@@ -323,7 +360,7 @@ cleanup_test(void)
 {
        struct downloaded_path *path;
 
-       dl_error = false;
+       dl_error = 0;
        cache_commit();
 
        while (!SLIST_EMPTY(&downloaded)) {
@@ -336,235 +373,228 @@ cleanup_test(void)
 
 /* Tests */
 
-START_TEST(test_cache_download_rsync)
-{
-       static const int SUCCESS = CNF_RSYNC | CNF_CACHED | CNF_FRESH | CNF_VALID;
-
-       setup_test();
-
-       run_dl_rsync("rsync://a.b.c/d", "rsync://a.b.c/d/mft", 0, 1);
-       ck_cache(
-               node("rsync:", 0, NULL,
-                       node("rsync://a.b.c", 0, NULL,
-                               node("rsync://a.b.c/d", SUCCESS, "tmp/tmp/0",
-                                       node("rsync://a.b.c/d/mft", RSYNC_INHERIT, NULL, NULL),
-                                       NULL),
-                               NULL),
-                       NULL),
-               node("https:", 0, NULL, NULL));
-
-       /* Redownload same file, nothing should happen */
-       run_dl_rsync("rsync://a.b.c/d", "rsync://a.b.c/d/mft", 0, 0);
-       ck_cache(
-               node("rsync:", 0, NULL,
-                       node("rsync://a.b.c", 0, NULL,
-                               node("rsync://a.b.c/d", SUCCESS, "tmp/tmp/0",
-                                       node("rsync://a.b.c/d/mft", RSYNC_INHERIT, NULL, NULL),
-                                       NULL),
-                               NULL),
-                       NULL),
-               node("https:", 0, NULL, NULL));
-
-       /*
-        * rsyncs are recursive, which means if we've been recently asked to
-        * download d, we needn't bother redownloading d/e.
-        */
-       run_dl_rsync("rsync://a.b.c/d/e", "rsync://a.b.c/d/e/mft", 0, 0);
-       ck_cache(
-               node("rsync:", 0, NULL,
-                       node("rsync://a.b.c", 0, NULL,
-                               node("rsync://a.b.c/d", SUCCESS, "tmp/tmp/0",
-                                       node("rsync://a.b.c/d/e", RSYNC_INHERIT, NULL,
-                                               node("rsync://a.b.c/d/e/mft", RSYNC_INHERIT, NULL, NULL),
-                                               NULL),
-                                       node("rsync://a.b.c/d/mft", RSYNC_INHERIT, NULL, NULL),
-                                       NULL),
-                               NULL),
-                       NULL),
-               node("https:", 0, NULL, NULL));
-
-       /*
-        * rsyncs get truncated, because it results in much faster
-        * synchronization in practice.
-        * This is not defined in any RFCs; it's an effective standard,
-        * and there would be consequences for violating it.
-        */
-       run_dl_rsync("rsync://x.y.z/m/n/o", "rsync://x.y.z/m/n/o/mft", 0, 1);
-       ck_cache(
-               node("rsync:", 0, NULL,
-                       node("rsync://a.b.c", 0, NULL,
-                               node("rsync://a.b.c/d", SUCCESS, "tmp/tmp/0",
-                                       node("rsync://a.b.c/d/e", RSYNC_INHERIT, NULL,
-                                               node("rsync://a.b.c/d/e/mft", RSYNC_INHERIT, NULL, NULL),
-                                               NULL),
-                                       node("rsync://a.b.c/d/mft", RSYNC_INHERIT, NULL, NULL),
-                                       NULL),
-                               NULL),
-                       node("rsync://x.y.z", 0, NULL,
-                               node("rsync://x.y.z/m", SUCCESS, "tmp/tmp/1",
-                                       node("rsync://x.y.z/m/n", RSYNC_INHERIT, NULL,
-                                               node("rsync://x.y.z/m/n/o", RSYNC_INHERIT, NULL,
-                                                       node("rsync://x.y.z/m/n/o/mft", RSYNC_INHERIT, NULL, NULL),
-                                                       NULL),
-                                               NULL),
-                                       NULL),
-                               NULL),
-                       NULL),
-               node("https:", 0, NULL, NULL));
-
-//     /* Sibling */
-//     run_dl_rsync("rsync://a.b.c/e/f", "rsync://a.b.c/e/f/mft", 0, 1);
-//     ck_cache(
-//         NODE("rsync://a.b.c/d/", 0, 1, true),
-//         NODE("rsync://a.b.c/e/", 0, 1, true),
-//         NODE("rsync://x.y.z/m/", 0, 1, true),
-//         NULL);
-
-       cleanup_test();
-}
-END_TEST
-
-//START_TEST(test_cache_download_rsync_error)
+static const int DOWNLOADED = CNF_RSYNC | CNF_CACHED | CNF_FRESH;
+static const int VALIDATED = RSYNC_INHERIT | CNF_VALID;
+static const int FULL = DOWNLOADED | VALIDATED;
+static const int STALE = CNF_RSYNC | CNF_CACHED | CNF_VALID;
+/* Intermediary between a downloaded and a validated node */
+//static const int BRANCH = RSYNC_INHERIT;
+//static const int FAILED = CNF_FRESH;
+//
+//START_TEST(test_cache_download_rsync)
 //{
-//     setup_test();
+//     setup_test(false);
 //
-//     dl_error = false;
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
-//     dl_error = true;
-//     run_cache_download("rsync://a.b.c/e", -EINVAL, 1, 0);
-//     ck_cache(
-//         NODE("rsync://a.b.c/d/", 0, 1, true),
-//         NODE("rsync://a.b.c/e/", -EINVAL, 0, false),
-//         NULL);
+//     run_dl_rsync("rsync://a.b.c/d", 0, 1);
+//     ck_cache_rsync(
+//             unode("rsync:",
+//                     unode("rsync://a.b.c",
+//                             uftnode("rsync://a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
 //
-//     /* Regardless of error, not reattempted because same iteration */
-//     dl_error = true;
-//     run_cache_download("rsync://a.b.c/e", -EINVAL, 0, 0);
-//     ck_cache(
-//         NODE("rsync://a.b.c/d/", 0, 1, true),
-//         NODE("rsync://a.b.c/e/", -EINVAL, 0, false),
-//         NULL);
+//     /* Redownload same file, nothing should happen */
+//     run_dl_rsync("rsync://a.b.c/d", 0, 0);
+//     ck_cache_rsync(
+//             unode("rsync:",
+//                     unode("rsync://a.b.c",
+//                             uftnode("rsync://a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
 //
-//     dl_error = false;
-//     run_cache_download("rsync://a.b.c/e", -EINVAL, 0, 0);
-//     ck_cache(
-//         NODE("rsync://a.b.c/d/", 0, 1, true),
-//         NODE("rsync://a.b.c/e/", -EINVAL, 0, false),
-//         NULL);
-//
-//     cleanup_test();
-//}
-//END_TEST
-//
-//START_TEST(test_cache_cleanup_rsync)
-//{
-//     setup_test();
+//     /*
+//      * rsyncs are recursive, which means if we've been recently asked to
+//      * download d, we needn't bother redownloading d/e.
+//      */
+//     run_dl_rsync("rsync://a.b.c/d/e", 0, 0);
+//     ck_cache_rsync(
+//             unode("rsync:",
+//                     unode("rsync://a.b.c",
+//                             uftnode("rsync://a.b.c/d", FULL, "tmp/tmp/0",
+//                                     ufnode("rsync://a.b.c/d/e", VALIDATED, NULL), NULL), NULL), NULL));
 //
 //     /*
-//      * First iteration: Tree is created. No prunes, because nothing's
-//      * outdated.
+//      * rsyncs get truncated, because it results in much faster
+//      * synchronization in practice.
+//      * This is not defined in any RFCs; it's an effective standard,
+//      * and there would be consequences for violating it.
 //      */
-//     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     cache_cleanup(cache);
-//     ck_cache(
-//         NODE("rsync://a.b.c/d/", 0, 1, true),
-//         NODE("rsync://a.b.c/e/", 0, 1, true),
-//         NULL);
+//     run_dl_rsync("rsync://x.y.z/m/n/o", 0, 1);
+//     ck_cache_rsync(
+//             unode("rsync:",
+//                     unode("rsync://a.b.c",
+//                             uftnode("rsync://a.b.c/d", FULL, "tmp/tmp/0",
+//                                     ufnode("rsync://a.b.c/d/e", VALIDATED, NULL), NULL), NULL),
+//                     unode("rsync://x.y.z",
+//                             uftnode("rsync://x.y.z/m", DOWNLOADED, "tmp/tmp/1",
+//                                     ufnode("rsync://x.y.z/m/n", BRANCH,
+//                                             ufnode("rsync://x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
 //
-//     /* One iteration with no changes, for paranoia */
-//     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     cache_cleanup(cache);
-//     ck_cache(
-//             NODE("rsync://a.b.c/d/", 0, 1, true),
-//             NODE("rsync://a.b.c/e/", 0, 1, true),
-//             NULL);
+//     /* Sibling */
+//     run_dl_rsync("rsync://a.b.c/e/f", 0, 1);
+//     ck_cache_rsync(
+//             unode("rsync:",
+//                     unode("rsync://a.b.c",
+//                             uftnode("rsync://a.b.c/d", FULL, "tmp/tmp/0",
+//                                     ufnode("rsync://a.b.c/d/e", VALIDATED, NULL), NULL),
+//                             uftnode("rsync://a.b.c/e", DOWNLOADED, "tmp/tmp/2",
+//                                     ufnode("rsync://a.b.c/e/f", VALIDATED, NULL), NULL), NULL),
+//                     unode("rsync://x.y.z",
+//                             uftnode("rsync://x.y.z/m", DOWNLOADED, "tmp/tmp/1",
+//                                     ufnode("rsync://x.y.z/m/n", BRANCH,
+//                                             ufnode("rsync://x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
 //
-//     /* Add one sibling */
-//     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     run_cache_download("rsync://a.b.c/f", 0, 1, 0);
-//     cache_cleanup(cache);
-//     ck_cache(
-//             NODE("rsync://a.b.c/d/", 0, 1, true),
-//             NODE("rsync://a.b.c/e/", 0, 1, true),
-//             NODE("rsync://a.b.c/f/", 0, 1, true),
-//             NULL);
+//     cleanup_test();
+//}
+//END_TEST
 //
-//     /* Nodes don't get updated, but they're still too young. */
-//     new_iteration(false);
-//     cache_cleanup(cache);
-//     ck_cache(
-//             NODE("rsync://a.b.c/d/", 0, 1, true),
-//             NODE("rsync://a.b.c/e/", 0, 1, true),
-//             NODE("rsync://a.b.c/f/", 0, 1, true),
-//             NULL);
+//START_TEST(test_cache_download_rsync_error)
+//{
+//     setup_test(false);
+//
+//     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));
 //
-//     /* Remove some branches */
-//     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
-//     cache_cleanup(cache);
-//     ck_cache(NODE("rsync://a.b.c/d/", 0, 1, true), NULL);
+//     /* Regardless of error, not reattempted because same iteration */
+//     dl_error = EINVAL;
+//     run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0);
+//     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));
+//
+//     dl_error = 0;
+//     run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0);
+//     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));
 //
+//     cleanup_test();
+//}
+//END_TEST
+
+START_TEST(test_cache_cleanup_rsync)
+{
+       setup_test(true);
+
+       /*
+        * First iteration: Tree is created. No prunes, because nothing's
+        * outdated.
+        */
+       new_iteration(true);
+       run_dl_rsync("rsync://a.b.c/d", 0, 1);
+       run_dl_rsync("rsync://a.b.c/e", 0, 1);
+       cleanup_cache();
+       ck_cache_rsync(
+               unode("rsync:",
+                       unode("rsync://a.b.c",
+                               ufnode("rsync://a.b.c/d", FULL, NULL),
+                               ufnode("rsync://a.b.c/e", FULL, NULL), NULL), NULL));
+
+       /* One iteration with no changes, for paranoia */
+       new_iteration(true);
+       run_dl_rsync("rsync://a.b.c/d", 0, 1);
+       run_dl_rsync("rsync://a.b.c/e", 0, 1);
+       cleanup_cache();
+       ck_cache_rsync(
+               unode("rsync:",
+                       unode("rsync://a.b.c",
+                               ufnode("rsync://a.b.c/d", FULL, NULL),
+                               ufnode("rsync://a.b.c/e", FULL, NULL), NULL), NULL));
+
+       /* Add one sibling */
+       new_iteration(true);
+       run_dl_rsync("rsync://a.b.c/d", 0, 1);
+       run_dl_rsync("rsync://a.b.c/e", 0, 1);
+       run_dl_rsync("rsync://a.b.c/f", 0, 1);
+       cleanup_cache();
+       ck_cache_rsync(
+               unode("rsync:",
+                       unode("rsync://a.b.c",
+                               ufnode("rsync://a.b.c/d", FULL, NULL),
+                               ufnode("rsync://a.b.c/e", FULL, NULL),
+                               ufnode("rsync://a.b.c/f", FULL, NULL), NULL), NULL));
+
+       /* Nodes don't get updated, but they're still too young. */
+       new_iteration(false);
+       cleanup_cache();
+       ck_cache_rsync(
+               unode("rsync:",
+                       unode("rsync://a.b.c",
+                               ufnode("rsync://a.b.c/d", STALE, NULL),
+                               ufnode("rsync://a.b.c/e", STALE, NULL),
+                               ufnode("rsync://a.b.c/f", STALE, NULL), NULL), NULL));
+
+       /* Remove some branches */
+       new_iteration(true);
+       run_dl_rsync("rsync://a.b.c/d", 0, 1);
+       cleanup_cache();
+       ck_cache_rsync(
+               unode("rsync:",
+                       unode("rsync://a.b.c",
+                               ufnode("rsync://a.b.c/d", FULL, NULL), NULL), NULL));
+
 //     /* Remove old branch and add sibling at the same time */
 //     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     cache_cleanup(cache);
+//     run_dl_rsync("rsync://a.b.c/e", 0, 1);
+//     cleanup_cache();
 //     ck_cache(NODE("rsync://a.b.c/e/", 0, 1, true), NULL);
 //
 //     /* Try child */
 //     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/e/f/g", 0, 1, 0);
-//     cache_cleanup(cache);
+//     run_dl_rsync("rsync://a.b.c/e/f/g", 0, 1);
+//     cleanup_cache();
 //     ck_cache(NODE("rsync://a.b.c/e/", 0, 1, true), NULL);
 //
 //     /* Parent again */
 //     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     cache_cleanup(cache);
+//     run_dl_rsync("rsync://a.b.c/e", 0, 1);
+//     cleanup_cache();
 //     ck_cache(NODE("rsync://a.b.c/e/", 0, 1, true), NULL);
 //
 //     /* Empty the tree */
 //     new_iteration(true);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NULL);
 //
 //     /* Node exists, but file doesn't */
 //     new_iteration(true);
-//     run_cache_download("rsync://a.b.c/e", 0, 1, 0);
-//     run_cache_download("rsync://a.b.c/f", 0, 1, 0);
+//     run_dl_rsync("rsync://a.b.c/e", 0, 1);
+//     run_dl_rsync("rsync://a.b.c/f", 0, 1);
 //     ck_cache(
 //             NODE("rsync://a.b.c/e/", 0, 1, true),
 //             NODE("rsync://a.b.c/f/", 0, 1, true),
 //             NULL);
 //     ck_assert_int_eq(0, file_rm_rf("tmp/rsync/a.b.c/f"));
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NODE("rsync://a.b.c/e/", 0, 1, true), NULL);
-//
-//     cleanup_test();
-//}
-//END_TEST
-//
+
+       cleanup_test();
+}
+END_TEST
+
 //START_TEST(test_cache_cleanup_rsync_error)
 //{
 //     setup_test();
 //
 //     /* Set up */
 //     dl_error = false;
-//     run_cache_download("rsync://a.b.c/d", 0, 1, 0);
+//     run_dl_rsync("rsync://a.b.c/d", 0, 1);
 //     dl_error = true;
-//     run_cache_download("rsync://a.b.c/e", -EINVAL, 1, 0);
+//     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 */
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NODE("rsync://a.b.c/d/", 0, 1, true), NULL);
 //
 //     /*
@@ -574,12 +604,12 @@ END_TEST
 //      */
 //     new_iteration(false);
 //     dl_error = true;
-//     run_cache_download("rsync://a.b.c/d", -EINVAL, 1, 0);
+//     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);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NULL);
 //
 //     cleanup_test();
@@ -648,7 +678,7 @@ END_TEST
 //     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);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(
 //             NODE("https://a.b.c/d", 0, 1, 1),
 //             NODE("https://a.b.c/e", 0, 1, 1),
@@ -657,19 +687,19 @@ END_TEST
 //     /* Remove one branch */
 //     new_iteration(true);
 //     run_cache_download("https://a.b.c/d", 0, 0, 1);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     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);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     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);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(
 //             NODE("https://a.b.c/e/f/g", 0, 1, 1), NULL);
 //
@@ -679,18 +709,18 @@ END_TEST
 //      */
 //     new_iteration(true);
 //     run_cache_download("https://a.b.c/e/f", 0, 0, 1);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     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);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NODE("https://a.b.c/e", 0, 1, 1), NULL);
 //
 //     /* Empty the tree */
 //     new_iteration(true);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NULL);
 //
 //     /* Node exists, but file doesn't */
@@ -702,7 +732,7 @@ END_TEST
 //         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"));
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NODE("https://a.b.c/e", 0, 1, 1), NULL);
 //
 //     cleanup_test();
@@ -724,7 +754,7 @@ END_TEST
 //         NULL);
 //
 //     /* Deleted because file ENOENT. */
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(
 //         NODE("https://a.b.c/d", 0, 1, 1),
 //         NULL);
@@ -737,20 +767,20 @@ END_TEST
 //
 //     /* Not deleted, because not old */
 //     new_iteration(false);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL);
 //
 //     /* Become old */
 //     new_iteration(true);
-//     cache_cleanup(cache);
+//     cleanup_cache();
 //     ck_cache(NULL);
 //
 //     cleanup_test();
 //}
 //END_TEST
-
-START_TEST(test_dots)
-{
+//
+//START_TEST(test_dots)
+//{
 //     setup_test();
 //
 //     run_cache_download("https://a.b.c/d", 0, 0, 1);
@@ -769,9 +799,9 @@ START_TEST(test_dots)
 //         NULL);
 //
 //     cleanup_test();
-}
-END_TEST
-
+//}
+//END_TEST
+//
 //START_TEST(test_tal_json)
 //{
 //     json_t *json;
@@ -968,9 +998,9 @@ 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);
 //     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);
 //     tcase_add_test(rsync, test_cache_cleanup_rsync_error);
 
        https = tcase_create("https");
@@ -980,7 +1010,7 @@ static Suite *thread_pool_suite(void)
 //     tcase_add_test(https, test_cache_cleanup_https_error);
 
        dot = tcase_create("dot");
-       tcase_add_test(dot, test_dots);
+//     tcase_add_test(dot, test_dots);
 
        meta = tcase_create(TAL_METAFILE);
 //     tcase_add_test(meta, test_tal_json);
diff --git a/test/cache/util.c b/test/cache/util.c
new file mode 100644 (file)
index 0000000..682383a
--- /dev/null
@@ -0,0 +1,66 @@
+#include "cache/util.h"
+
+#include <string.h>
+#include "data_structure/uthash.h"
+
+struct cache_node *
+vnode(char const *url, int flags, char const *tmpdir, va_list children)
+{
+       struct cache_node *result;
+       struct cache_node *child;
+       char const *slash;
+
+       result = pzalloc(sizeof(struct cache_node));
+       result->url = pstrdup(url);
+       slash = strrchr(url, '/');
+       result->name = slash ? (slash + 1) : result->url;
+       result->flags = flags;
+       result->tmpdir = tmpdir ? pstrdup(tmpdir) : NULL;
+
+       while ((child = va_arg(children, struct cache_node *)) != NULL) {
+               HASH_ADD_KEYPTR(hh, result->children, child->name,
+                   strlen(child->name), child);
+               child->parent = result;
+       }
+
+       return result;
+}
+
+struct cache_node *
+uftnode(char const *url, int flags, char const *tmpdir, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, tmpdir);
+       result = vnode(url, flags, tmpdir, children);
+       va_end(children);
+
+       return result;
+}
+
+struct cache_node *
+ufnode(char const *url, int flags, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, flags);
+       result = vnode(url, flags, NULL, children);
+       va_end(children);
+
+       return result;
+}
+
+struct cache_node *
+unode(char const *url, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, url);
+       result = vnode(url, 0, NULL, children);
+       va_end(children);
+
+       return result;
+}
diff --git a/test/cache/util.h b/test/cache/util.h
new file mode 100644 (file)
index 0000000..4ff43ef
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef TEST_CACHE_UTIL_H_
+#define TEST_CACHE_UTIL_H_
+
+#include <stdarg.h>
+#include "cache/cachent.h"
+
+struct cache_node *vnode(char const *, int, char const *, va_list);
+struct cache_node *uftnode(char const *, int , char const *, ...);
+struct cache_node *ufnode(char const *, int , ...);
+struct cache_node *unode(char const *, ...);
+
+#endif /* TEST_CACHE_UTIL_H_ */
index 5717f797f55ae2112e6c78d601bc78f565c5ac63..b0bb560df20c64bb9909575d04372c28603af268 100644 (file)
@@ -113,7 +113,6 @@ 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, 0, void)
 MOCK(config_get_mode, enum mode, STANDALONE, void)
 MOCK_TRUE(config_get_rsync_enabled, void)
 MOCK_UINT(config_get_rsync_priority, 50, void)