#include "types/url.h"
struct cache_node *
-cachent_create_root(char const *schema)
+cachent_create_root(bool https)
{
struct cache_node *root;
root = pzalloc(sizeof(struct cache_node));
- root->url = pstrdup(schema);
- root->name = root->url;
+ root->url = pstrdup(https ? "https://" : "rsync://");
+ root->path = join_paths(config_get_local_repository(),
+ https ? "https" : "rsync");
+ root->name = strrchr(root->path, '/') + 1;
return root;
}
/* Preorder. @cb returns whether the children should be traversed. */
int
-cachent_traverse(struct cache_node *root,
- bool (*cb)(struct cache_node *, char const *))
+cachent_traverse(struct cache_node *root, bool (*cb)(struct cache_node *))
{
struct cache_node *iter_start;
struct cache_node *parent, *child;
struct cache_node *tmp;
- struct path_builder pb;
int error;
if (!root)
return 0;
- pb_init(&pb);
-
- error = pb_append(&pb, config_get_local_repository());
- if (error)
- goto end;
-
- error = pb_append(&pb, root->name);
- if (error)
- goto end;
- if (!cb(root, pb.string))
- goto end;
+ if (!cb(root))
+ return error;
parent = root;
iter_start = parent->children;
if (iter_start == NULL)
- goto end;
+ return error;
reloop: /* iter_start must not be NULL */
HASH_ITER(hh, iter_start, child, tmp) {
- error = pb_append(&pb, child->name);
- if (error)
- goto end;
-
- if (cb(child, pb.string) && (child->children != NULL)) {
+ if (cb(child) && (child->children != NULL)) {
parent = child;
iter_start = parent->children;
goto reloop;
}
-
- pb_pop(&pb, true);
}
parent = iter_start->parent;
do {
if (parent == NULL)
- goto end;
- pb_pop(&pb, true);
+ return error;
iter_start = parent->hh.next;
parent = parent->parent;
} while (iter_start == NULL);
goto reloop;
-
-end: pb_cleanup(&pb);
- return error;
}
static struct cache_node *
char const *name, size_t namelen)
{
struct cache_node *child;
+ size_t pathlen;
child = find_child(parent, name, namelen);
if (child != NULL)
child = pzalloc(sizeof(struct cache_node));
child->url = pstrndup(url, name - url + namelen);
+
+ pathlen = strlen(parent->path) + namelen + 2;
+ child->path = pmalloc(pathlen);
+ if (snprintf(child->path, pathlen, "%s/%.*s", parent->path, (int)namelen, name) >= pathlen)
+ pr_crit("aaaaaa"); // XXX
+
child->name = child->url + (name - url);
if ((parent->flags & RSYNC_INHERIT) == RSYNC_INHERIT)
child->flags = RSYNC_INHERIT;
for (i = 0; ancestor->url[i] != 0; i++)
if (ancestor->url[i] != normal[i])
goto fail;
- if (normal[i] != '/' && normal[i] != '\0')
+ if (i != RPKI_SCHEMA_LEN && normal[i] != '/' && normal[i] != '\0')
goto fail;
token_init(&tkn, normal + i);
static void __delete_node_cb(struct cache_node const *);
#endif
-static void
+static int
__delete_node(struct cache_node *node)
{
+ int valid = node->flags & CNF_VALID;
+
#ifdef UNIT_TESTING
__delete_node_cb(node);
#endif
if (node->parent != NULL)
HASH_DEL(node->parent->children, node);
free(node->url);
- free(node->tmpdir);
+ free(node->path);
+ free(node->tmppath);
free(node);
+
+ return valid;
}
-void
+int
cachent_delete(struct cache_node *node)
{
struct cache_node *parent;
+ int valid;
if (!node)
- return;
+ return 0;
+
+ valid = node->flags & CNF_VALID;
parent = node->parent;
if (parent != NULL) {
node = node->children;
parent = node->parent;
- __delete_node(node);
+ valid |= __delete_node(node);
node = parent;
} while (node != NULL);
+
+ return valid;
}
static void
printf("%s", (node->flags & CNF_VALID) ? "valid " : "");
printf("%s", (node->flags & CNF_NOTIFICATION) ? "notification " : "");
printf("%s", (node->flags & CNF_WITHDRAWN) ? "withdrawn " : "");
- printf(" -- %s", node->tmpdir);
+ printf(" -- %s", node->tmppath);
printf("\n");
HASH_ITER(hh, node->children, child, tmp)
* Did it validate successfully (at least once) during the current cycle?
* (It's technically possible for two different repositories to map to the same
* cache node. One of them is likely going to fail validation.)
+ * This only refers to the tmp path; The final path, if it exists, always
+ * contains valid objects (until expiration).
*/
#define CNF_VALID (1 << 5)
/* Is the node an RRDP Update Notification? */
// XXX rename to cache_entity or cachent
struct cache_node {
- char const *name; /* Points to the last component of @url XXX redundant */
- char *url; /* Normalized */
- int flags;
+ char *url; /* rsync://a.b.c/d/e (normalized) */
+ char *path; /* path/to/cache/rsync/a.b.c/d/e */
+ char const *name; /* Points to the last component of @url or @path XXX redundant */
+ int flags; /* CNF_* */
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.
+ * If download attempted, path to the temporal directory where the
+ * refresh was dumped.
* (See --compare-dest at rsync(1). RRDP is basically the same.)
- * Otherwise undefined.
- *
- * XXX this is not always a directory; rename to "tmppath"
+ * Otherwise NULL.
*/
- char *tmpdir;
+ char *tmppath; /* path/to/cache/tmp/1234 */
- /* Only if flags & CNF_NOTIFICATION */
+// /* Only if flags & CNF_NOTIFICATION */
// struct cachefile_notification notif;
struct cache_node *parent; /* Tree parent */
UT_hash_handle hh; /* Hash table hook */
};
-struct cache_node *cachent_create_root(char const *);
+struct cache_node *cachent_create_root(bool);
-int cachent_traverse(struct cache_node *,
- bool (*cb)(struct cache_node *, char const *));
+int cachent_traverse(struct cache_node *, bool (*cb)(struct cache_node *));
struct cache_node *cachent_find(struct cache_node *, char const *,
struct cache_node **);
struct cache_node *cachent_provide(struct cache_node *, char const *);
-void cachent_delete(struct cache_node *);
+int cachent_delete(struct cache_node *);
/* Recursive; tests only. */
void cachent_print(struct cache_node *);
static void
load_tal_json(void)
{
- cache.rsync = cachent_create_root("rsync");
- cache.https = cachent_create_root("https");
+ cache.rsync = cachent_create_root(false);
+ cache.https = cachent_create_root(true);
// char *filename;
// json_t *root;
dl_rsync(struct cache_node *rpp)
{
struct cache_node *module, *node;
- char *path;
+ char *tmppath;
int error;
if (!config_get_rsync_enabled()) {
if (module == NULL)
return -EINVAL; // XXX
- error = cache_tmpfile(&path);
+ error = cache_tmpfile(&tmppath);
if (error)
return error;
- // XXX looks like the third argument is redundant now.
- error = rsync_download(module->url, path, true);
+ error = rsync_download(module->url, tmppath,
+ (module->flags & CNF_CACHED) ? module->path : NULL);
if (error) {
- free(path);
+ free(tmppath);
return error;
}
module->flags |= CNF_RSYNC | CNF_CACHED | CNF_FRESH;
module->mtim = time(NULL); // XXX catch -1
- module->tmpdir = path;
+ module->tmppath = tmppath;
for (node = rpp; node != module; node = node->parent) {
node->flags |= RSYNC_INHERIT;
static int
dl_http(struct cache_node *node)
{
- char *path;
+ char *tmppath;
bool changed;
int error;
return 1;
}
- error = cache_tmpfile(&path);
+ error = cache_tmpfile(&tmppath);
if (error)
return error;
- error = http_download(node->url, path, node->mtim, &changed);
+ error = http_download(node->url, tmppath, node->mtim, &changed);
if (error) {
- free(path);
+ free(tmppath);
return error;
}
node->flags |= CNF_CHANGED;
node->mtim = time(NULL); // XXX catch -1
}
- node->tmpdir = path;
+ node->tmppath = tmppath;
return 0;
}
HASH_ITER(hh, domain->children, module, tmp2)
HASH_ITER(hh, module->children, child, tmp3) {
pr_op_debug("Removing leftover: %s", child->url);
- cachent_delete(child);
+ module->flags |= cachent_delete(child);
}
}
* XXX result is redundant
*/
static bool
-commit_rpp_delta(struct cache_node *node, char const *path)
+commit_rpp_delta(struct cache_node *node)
{
struct cache_node *child, *tmp;
int error;
goto branch;
}
- if (node->tmpdir == NULL) {
+ if (node->tmppath == NULL) {
if (node->children) {
pr_op_debug("Branch.");
goto branch;
if (node->flags & CNF_VALID) {
pr_op_debug("Validation successful; committing.");
- error = file_merge_into(node->tmpdir, path);
+ error = file_merge_into(node->tmppath, node->path);
if (error)
printf("rename errno: %d\n", error); // XXX
/* XXX Think more about the implications of this. */
} else {
pr_op_debug("Validation unsuccessful; rollbacking.");
/* XXX just do remove()? */
- file_rm_f(node->tmpdir);
+ file_rm_f(node->tmppath);
}
- free(node->tmpdir);
- node->tmpdir = NULL;
+ free(node->tmppath);
+ node->tmppath = NULL;
return true;
branch: node->flags = 0;
- if (node->tmpdir) {
- free(node->tmpdir);
- node->tmpdir = NULL;
+ if (node->tmppath) {
+ free(node->tmppath);
+ node->tmppath = NULL;
}
return true;
}
}
static bool
-remove_orphaned(struct cache_node *node, char const *path)
+remove_orphaned(struct cache_node *node)
{
- if (file_exists(path) == ENOENT) {
- pr_op_debug("Missing file; deleting node: %s", path);
+ if (file_exists(node->path) == ENOENT) {
+ pr_op_debug("Missing file; deleting node: %s", node->path);
cachent_delete(node);
return false;
}
unsigned int interval;
} retry;
char *program;
- struct {
- struct string_array flat; /* Deprecated */
- struct string_array recursive;
- } args;
+ struct string_array args;
} rsync;
struct {
.id = 3006,
.name = "rsync.arguments-recursive",
.type = >_string_array,
- .offset = offsetof(struct rpki_config, rsync.args.recursive),
- .doc = "RSYNC program arguments",
+ .offset = offsetof(struct rpki_config, rsync.args),
+ .doc = "Deprecated; does nothing.",
.availability = AVAILABILITY_JSON,
- /* Unlimited */
- .max = 0,
+ .deprecated = true,
}, {
.id = 3007,
.name = "rsync.arguments-flat",
.type = >_string_array,
- .offset = offsetof(struct rpki_config, rsync.args.flat),
+ .offset = offsetof(struct rpki_config, rsync.args),
.doc = "Deprecated; does nothing.",
.availability = AVAILABILITY_JSON,
- /* Unlimited */
- .max = 0,
.deprecated = true,
},
static void
set_default_values(void)
{
- static char const *recursive_rsync_args[] = {
- "-rtz", "--delete", "--omit-dir-times",
-
- "--contimeout=20", "--max-size=20MB", "--timeout=15",
-
- "--include=*/", "--include=*.cer", "--include=*.crl",
- "--include=*.gbr", "--include=*.mft", "--include=*.roa",
- "--exclude=*",
-
- "$REMOTE", "$LOCAL",
- };
- static char const *flat_rsync_args[] = { "<deprecated>" };
+ static char const *trash[] = { "<deprecated>" };
static char const *addrs[] = {
#ifdef __linux__
"::"
rpki_config.rsync.retry.count = 1;
rpki_config.rsync.retry.interval = 4;
rpki_config.rsync.program = pstrdup("rsync");
- string_array_init(&rpki_config.rsync.args.flat,
- flat_rsync_args, ARRAY_LEN(flat_rsync_args));
- string_array_init(&rpki_config.rsync.args.recursive,
- recursive_rsync_args, ARRAY_LEN(recursive_rsync_args));
+ string_array_init(&rpki_config.rsync.args, trash, ARRAY_LEN(trash));
rpki_config.http.enabled = true;
/* Higher priority than rsync by default */
return rpki_config.rsync.program;
}
-struct string_array const *
-config_get_rsync_args(void)
-{
- return &rpki_config.rsync.args.recursive;
-}
-
bool
config_get_http_enabled(void)
{
unsigned int config_get_rsync_retry_count(void);
unsigned int config_get_rsync_retry_interval(void);
char *config_get_rsync_program(void);
-struct string_array const *config_get_rsync_args(void);
bool config_get_http_enabled(void);
unsigned int config_get_http_priority(void);
unsigned int config_get_http_retry_count(void);
{
int error;
- error = rsync_download(src, dst, false);
+ // XXX use the cache
+ error = rsync_download(src, dst, NULL);
if (error) {
pr_op_err("rysnc download failed: %s", strerror(abs(error)));
return NULL;
#include "log.h"
#include "thread_var.h"
#include "http/http.h"
-#include "cache/cache_entity.h"
+#include "cache/cachent.h"
#include "crypto/base64.h"
#include "crypto/hash.h"
#include "xml/relax_ng.h"
}
static int
-parse_notification(struct cache_node *node, struct update_notification *result)
+parse_notification(struct cache_node *notif, struct update_notification *result)
{
int error;
- update_notification_init(result, node->url);
+ update_notification_init(result, notif->url);
- error = relax_ng_parse(node->tmpdir, xml_read_notif, result);
+ error = relax_ng_parse(notif->tmppath, xml_read_notif, result);
if (error)
update_notification_cleanup(result);
return 0;
}
+static int
+dl_notif(struct cache_node *notif)
+{
+ char *tmppath;
+ bool changed;
+ int error;
+
+ error = cache_tmpfile(&tmppath);
+ if (error)
+ return error;
+
+ error = http_download(notif->url, tmppath, notif->mtim, &changed);
+ if (error) {
+ free(tmppath);
+ return error;
+ }
+
+ // XXX notif->flags |= CNF_CACHED | CNF_FRESH;
+ if (changed) {
+ notif->mtim = time(NULL); // XXX
+ notif->tmppath = tmppath;
+ } else {
+ free(tmppath);
+ }
+
+ return 0;
+}
+
/*
* Downloads the Update Notification @notif, and updates the cache accordingly.
*
int
rrdp_update(struct cache_node *notif)
{
- char *path = NULL;
struct cachefile_notification *old;
struct update_notification new;
int serial_cmp;
fnstack_push(notif->url);
pr_val_debug("Processing notification.");
- error = http_download_cache_node(notif);
+ ///////////////////////////////////////////////////////////////////////
+
+ error = dl_notif(notif);
if (error)
goto end;
- if (!(notif->flags & CNF_CHANGED)) {
+ if (!notif->tmppath) {
pr_val_debug("The Notification has not changed.");
- rpp->flags |= CNF_FRESH; /* Success */
goto end;
}
error = parse_notification(notif, &new);
if (error)
goto end;
+
+ remove(notif->tmppath); // XXX
+ if (mkdir(notif->tmppath) == -1) {
+ error = errno;
+ pr_val_err("Can't create notification's temporal directory: %s",
+ strerror(error));
+ goto clean_notif;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
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, rpp);
+ error = handle_snapshot(&new, notif);
if (error)
goto clean_notif;
update_notification_cleanup(&new);
end:
- free(path);
fnstack_pop();
return error;
}
}
static void
-release_args(char **args, unsigned int size)
+prepare_rsync(char *args, char const *src, char const *dst, char const *cmpdst)
{
- unsigned int i;
-
- /* args[0] wasn't allocated */
- for (i = 1; i < size + 1; i++)
- free(args[i]);
- free(args);
-}
-
-static void
-prepare_rsync(char const *src, char const *dst, char ***args, size_t *args_len)
-{
- struct string_array const *config_args;
- char **copy_args;
- unsigned int i;
-
- config_args = config_get_rsync_args();
- /*
- * We need to work on a copy, because the config args are immutable,
- * and we need to add the program name (for some reason) and NULL
- * elements, and replace $REMOTE and $LOCAL.
- */
- copy_args = pcalloc(config_args->length + 2, sizeof(char *));
-
- copy_args[0] = config_get_rsync_program();
- copy_args[config_args->length + 1] = NULL;
-
- memcpy(copy_args + 1, config_args->array,
- config_args->length * sizeof(char *));
-
- for (i = 0; i < config_args->length; i++) {
- if (strcmp(config_args->array[i], "$REMOTE") == 0)
- copy_args[i + 1] = pstrdup(src);
- else if (strcmp(config_args->array[i], "$LOCAL") == 0)
- copy_args[i + 1] = pstrdup(dst);
- else
- copy_args[i + 1] = pstrdup(config_args->array[i]);
+ size_t i = 0;
+
+ /* XXX review */
+ args[i++] = config_get_rsync_program();
+ args[i++] = "-rtz";
+ args[i++] = "--omit-dir-times";
+ args[i++] = "--contimeout";
+ args[i++] = "20";
+ args[i++] = "--max-size";
+ args[i++] = "20MB";
+ args[i++] = "--timeout";
+ args[i++] = "15";
+ args[i++] = "--include=*/";
+ args[i++] = "--include=*.cer";
+ args[i++] = "--include=*.crl";
+ args[i++] = "--include=*.gbr";
+ args[i++] = "--include=*.mft";
+ args[i++] = "--include=*.roa";
+ args[i++] = "--exclude=*";
+ if (cmpdst) {
+ args[i++] = "--compare-dest";
+ args[i++] = cmpdst;
}
-
- *args = copy_args;
- *args_len = config_args->length;
+ args[i++] = src;
+ args[i++] = dst;
+ args[i++] = NULL;
}
__dead static void
return read_pipe(fds, 1);
}
-/*
- * Downloads @src @dst. @src is supposed to be an rsync URL, and @dst is
- * supposed to be a filesystem path.
- */
+/* rsync [--compare-dest @cmpdst] @src @dst */
int
-rsync_download(char const *src, char const *dst, bool is_directory)
+rsync_download(char const *src, char const *dst, char const *cmpdst)
{
- char **args;
- size_t args_len;
+ char *args[32];
/* Descriptors to pipe stderr (first element) and stdout (second) */
int fork_fds[2][2];
pid_t child_pid;
int error;
/* Prepare everything for the child exec */
- args = NULL;
- args_len = 0;
- prepare_rsync(src, dst, &args, &args_len);
+ prepare_rsync(&args, src, dst, cmpdst);
pr_val_info("rsync: %s", src);
if (log_val_enabled(LOG_DEBUG)) {
pr_val_debug("Executing rsync:");
- for (i = 0; i < args_len + 1; i++)
+ for (i = 0; args[i] != NULL; i++)
pr_val_debug(" %s", args[i]);
}
- error = mkdir_p(dst, is_directory, 0777);
+ error = mkdir_p(dst, true, 0777);
if (error)
- goto release_args;
+ return error;
retries = 0;
do {
error = create_pipes(fork_fds);
if (error)
- goto release_args;
+ return error;
/* Flush output (avoid locks between father and child) */
log_flush();
close(fork_fds[1][0]);
close(fork_fds[0][1]);
close(fork_fds[1][1]);
- goto release_args;
+ return error;
}
/* This code is run by us. */
error, strerror(error));
if (child_status > 0)
break;
- goto release_args;
+ return error;
}
} while (0);
pr_val_debug("The rsync sub-process terminated with error code %d.",
error);
if (!error)
- goto release_args;
+ return 0;
if (retries == config_get_rsync_retry_count()) {
if (retries > 0)
pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
retries, src);
- error = EIO;
- goto release_args;
+ return EIO;
}
pr_val_warn("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.",
src,
break;
} while (true);
- release_args(args, args_len);
-
if (WIFSIGNALED(child_status)) {
switch (WTERMSIG(child_status)) {
case SIGINT:
pr_op_err_st("The RSYNC command died in a way I don't have a handler for. Dunno; guess I'll die as well.");
return -EINVAL;
-release_args:
- /* The happy path also falls here */
- release_args(args, args_len);
- return error;
}
#ifndef SRC_RSYNC_RSYNC_H_
#define SRC_RSYNC_RSYNC_H_
-#include <stdbool.h>
-
-int rsync_download(char const *, char const *, bool);
+int rsync_download(char const *, char const *, char const *);
#endif /* SRC_RSYNC_RSYNC_H_ */
}
/*
- * Collapses '//', '.' and '..'. Also removes the colon from the schema.
+ * Collapses '//' (except from the schema), '.' and '..'.
*
- * "rsync://a.b/./c//.././/d/." -> "rsync/a.b/d"
+ * "rsync://a.b/./c//.././/d/." -> "rsync://a.b/d"
*/
char *
url_normalize(char const *url)
{
- char *normal, *dst, *root;
+ char *normal, *dst;
struct tokenizer tkn;
if (strncmp(url, "rsync://", RPKI_SCHEMA_LEN) &&
return NULL;
normal = pstrdup(url);
- root = normal + 5;
- *root = '/';
- dst = root + 1;
+ dst = normal + RPKI_SCHEMA_LEN;
token_init(&tkn, url + RPKI_SCHEMA_LEN);
while (token_next(&tkn)) {
if (tkn.len == 1 && tkn.str[0] == '.')
continue;
if (tkn.len == 2 && tkn.str[0] == '.' && tkn.str[1] == '.') {
- dst = path_rewind(root, dst);
+ dst = path_rewind(normal + RPKI_SCHEMA_LEN, dst);
if (!dst)
goto fail;
continue;
}
/* Reject URL if there's nothing after the schema. Maybe unnecessary. */
- if (dst == root + 1)
+ if (dst == normal + RPKI_SCHEMA_LEN)
goto fail;
dst[-1] = '\0';
#include "mock.c"
#include "types/url.c"
-static char deleted[16][5];
+static char deleted[16][6];
static unsigned int dn;
static void
{
struct cache_node *root, *a, *b;
- a = unode("a", NULL);
+ a = runode("a", NULL);
dn = 0;
cachent_delete(a);
ck_assert_uint_eq(1, dn);
ck_assert_str_eq("a", deleted[0]);
- a = unode("a", NULL);
- root = unode("root", a, NULL);
+ a = runode("a", NULL);
+ root = runode("", a, NULL);
dn = 0;
cachent_delete(a);
ck_assert_ptr_eq(NULL, root->children);
dn = 0;
cachent_delete(root);
ck_assert_uint_eq(1, dn);
- ck_assert_str_eq("root", deleted[0]);
-
- b = unode("b",
- unode("c", NULL),
- unode("d", NULL),
- unode("e", NULL),
- unode("f", NULL), NULL);
- a = unode("a",
+ 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,
- 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);
+ 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);
dn = 0;
cachent_delete(b);
dn = 0;
cachent_delete(root);
ck_assert_uint_eq(1, dn);
- ck_assert_str_eq("root", deleted[0]);
+ ck_assert_str_eq("rsync", deleted[0]);
}
END_TEST
static unsigned int e;
static bool
-ck_traverse_cb(struct cache_node *node, char const *path)
+ck_traverse_cb(struct cache_node *node)
{
- ck_assert_str_eq(expected[e++], path);
+ ck_assert_str_eq(expected[e++], node->path);
return true;
}
root = NULL;
ck_traverse(root, NULL);
- root = unode("a", NULL);
- ck_traverse(root, "tmp/a", NULL);
+ root = runode("a", NULL);
+ ck_traverse(root, "tmp/rsync/a", NULL);
- root = unode("a",
- unode("b", NULL), NULL);
- ck_traverse(root, "tmp/a", "tmp/a/b", NULL);
+ root = runode("a",
+ runode("a/b", NULL), NULL);
+ ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", NULL);
- root = unode("a",
- unode("b",
- unode("c", NULL), NULL), NULL);
+ root = runode("a",
+ runode("a/b",
+ runode("a/b/c", NULL), NULL), NULL);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/b/c", NULL);
-
- root = unode("a",
- unode("b",
- unode("c", NULL),
- unode("d", NULL), NULL), NULL);
+ "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);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/b/c",
- "tmp/a/b/d", NULL);
-
- root = unode("a",
- unode("b",
- unode("c", NULL),
- unode("d", NULL), NULL),
- unode("e", NULL), NULL);
+ "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);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/b/c",
- "tmp/a/b/d",
- "tmp/a/e", NULL);
-
- root = unode("a",
- unode("b", NULL),
- unode("c",
- unode("d", NULL),
- unode("e", NULL), NULL), NULL);
+ "tmp/rsync/a",
+ "tmp/rsync/a/b",
+ "tmp/rsync/a/b/c",
+ "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);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/c",
- "tmp/a/c/d",
- "tmp/a/c/e", NULL);
-
- root = unode("a",
- unode("b",
- unode("c", NULL),
- unode("d", NULL), NULL),
- unode("e",
- unode("f", NULL),
- unode("g", NULL), NULL), NULL);
+ "tmp/rsync/a",
+ "tmp/rsync/a/b",
+ "tmp/rsync/a/c",
+ "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);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/b/c",
- "tmp/a/b/d",
- "tmp/a/e",
- "tmp/a/e/f",
- "tmp/a/e/g", 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);
+ "tmp/rsync/a",
+ "tmp/rsync/a/b",
+ "tmp/rsync/a/b/c",
+ "tmp/rsync/a/b/d",
+ "tmp/rsync/a/e",
+ "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);
ck_traverse(root,
- "tmp/a",
- "tmp/a/b",
- "tmp/a/b/c",
- "tmp/a/b/d",
- "tmp/a/b/e",
- "tmp/a/b/f",
- "tmp/a/g",
- "tmp/a/g/h",
- "tmp/a/g/h/i",
- "tmp/a/g/j",
- "tmp/a/g/j/k",
- "tmp/a/g/l",
- "tmp/a/g/l/m",
- "tmp/a/g/n",
- "tmp/a/g/n/o", NULL);
+ "tmp/rsync/a",
+ "tmp/rsync/a/b",
+ "tmp/rsync/a/b/c",
+ "tmp/rsync/a/b/d",
+ "tmp/rsync/a/b/e",
+ "tmp/rsync/a/b/f",
+ "tmp/rsync/a/g",
+ "tmp/rsync/a/g/h",
+ "tmp/rsync/a/g/h/i",
+ "tmp/rsync/a/g/j",
+ "tmp/rsync/a/g/j/k",
+ "tmp/rsync/a/g/l",
+ "tmp/rsync/a/g/l/m",
+ "tmp/rsync/a/g/n",
+ "tmp/rsync/a/g/n/o", NULL);
}
END_TEST
{
struct cache_node *rsync, *abc, *d, *e, *f, *g, *h, *ee;
- rsync = cachent_create_root("rsync");
+ rsync = cachent_create_root(false);
ck_assert_ptr_ne(NULL, rsync);
ck_assert_ptr_eq(NULL, rsync->parent);
- ck_assert_str_eq("rsync", rsync->url);
+ ck_assert_str_eq("rsync://", rsync->url);
+ ck_assert_str_eq("tmp/rsync", rsync->path);
ck_assert_str_eq("rsync", rsync->name);
/* Create branch chain from root */
e = cachent_provide(rsync, "rsync://a.b.c/d/e");
ck_assert_ptr_ne(NULL, e);
- ck_assert_str_eq("rsync/a.b.c/d/e", e->url);
+ ck_assert_str_eq("rsync://a.b.c/d/e", e->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/d/e", e->path);
ck_assert_str_eq("e", e->name);
d = e->parent;
ck_assert_ptr_ne(NULL, d);
- ck_assert_str_eq("rsync/a.b.c/d", d->url);
+ ck_assert_str_eq("rsync://a.b.c/d", d->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/d", d->path);
ck_assert_str_eq("d", d->name);
abc = d->parent;
ck_assert_ptr_ne(NULL, abc);
- ck_assert_str_eq("rsync/a.b.c", abc->url);
+ ck_assert_str_eq("rsync://a.b.c", abc->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c", abc->path);
ck_assert_str_eq("a.b.c", abc->name);
ck_assert_ptr_eq(rsync, abc->parent);
/* Some not normalized noise */
ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c/d/e////"));
ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c///d/./e//"));
- ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a/../z/../a.b.c/d/e/"));
+ ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c/d/f/../e/"));
/* Create sibling from root */
f = cachent_provide(rsync, "rsync://a.b.c/f");
ck_assert_ptr_ne(NULL, f);
ck_assert_ptr_eq(abc, f->parent);
- ck_assert_str_eq("rsync/a.b.c/f", f->url);
+ ck_assert_str_eq("rsync://a.b.c/f", f->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/f", f->path);
ck_assert_str_eq("f", f->name);
/* Create more than one descendant from root */
h = cachent_provide(rsync, "rsync://a.b.c/f/g/h");
ck_assert_ptr_ne(NULL, h);
- ck_assert_str_eq("rsync/a.b.c/f/g/h", h->url);
+ ck_assert_str_eq("rsync://a.b.c/f/g/h", h->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/f/g/h", h->path);
ck_assert_str_eq("h", h->name);
g = h->parent;
ck_assert_ptr_ne(NULL, g);
ck_assert_ptr_eq(f, g->parent);
- ck_assert_str_eq("rsync/a.b.c/f/g", g->url);
+ ck_assert_str_eq("rsync://a.b.c/f/g", g->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/f/g", g->path);
ck_assert_str_eq("g", g->name);
/* Try to create a conflict by prefix */
ee = cachent_provide(rsync, "rsync://a.b.c/d/ee");
ck_assert_ptr_ne(e, ee);
ck_assert_ptr_eq(d, ee->parent);
- ck_assert_str_eq("rsync/a.b.c/d/ee", ee->url);
+ ck_assert_str_eq("rsync://a.b.c/d/ee", ee->url);
+ ck_assert_str_eq("tmp/rsync/a.b.c/d/ee", ee->path);
ck_assert_str_eq("ee", ee->name);
ck_assert_ptr_eq(e, cachent_provide(abc, "rsync://a.b.c/d/e"));
ck_assert_ptr_eq(ee, cachent_provide(abc, "rsync://a.b.c/d/ee"));
-/*
- * This test will create some temporal directories on "/tmp".
- * Needs permissions.
- */
+/* This will create some test files in "tmp/". Needs permissions. */
#include <check.h>
//#include <stdarg.h>
}
int
-rsync_download(char const *src, char const *dst, bool is_directory)
+rsync_download(char const *src, char const *dst, char const *cmpdir)
{
char cmd[64];
}
static bool
-ck_path(struct cache_node *node, char const *_)
+ck_path(struct cache_node *node)
{
int error;
- if (!node->tmpdir)
+ if (!node->tmppath)
return true;
- error = file_exists(node->tmpdir);
+ error = file_exists(node->tmppath);
if (error)
- ck_abort_msg("Missing file in cache: %s (%s)", node->tmpdir, strerror(error));
+ ck_abort_msg("Missing file in cache: %s (%s)", node->tmppath,
+ strerror(error));
return true;
}
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->tmpdir)
- ck_assert_str_eq(expected->tmpdir, actual->tmpdir);
+ if (expected->tmppath)
+ ck_assert_str_eq(expected->tmppath, actual->tmppath);
else
- ck_assert_ptr_eq(NULL, actual->tmpdir);
+ ck_assert_ptr_eq(NULL, actual->tmppath);
HASH_ITER(hh, expected->children, echild, tmp) {
HASH_FIND(hh, actual->children, echild->name,
static void
ck_cache_rsync(struct cache_node *rsync)
{
- ck_cache(rsync, unode("https", NULL));
+ ck_cache(rsync, hunode("", NULL));
}
static void
ck_cache_https(struct cache_node *https)
{
- ck_cache(unode("rsync", NULL), https);
+ ck_cache(runode("", NULL), https);
}
static time_t epoch;
static bool
-unfreshen(struct cache_node *node, char const *path)
+unfreshen(struct cache_node *node)
{
PR_DEBUG_MSG("Unfreshening %s.", node->url);
- node->flags &= ~CNF_FRESH;
+ node->flags &= ~(CNF_FRESH | CNF_CHANGED | CNF_VALID);
node->mtim = epoch;
return true;
}
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;
+static const int STALE = CNF_RSYNC | CNF_CACHED;
/* Intermediary between a downloaded and a validated node */
static const int BRANCH = RSYNC_INHERIT;
static const int FAILED = CNF_FRESH;
{
setup_test();
+ printf("==== Startup ====\n");
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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
/* Redownload same file, nothing should happen */
+ printf("==== Redownload sample file ====\n");
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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
/*
* rsyncs are recursive, which means if we've been recently asked to
* download d, we needn't bother redownloading d/e.
*/
+ printf("==== Don't redownload child ====\n");
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));
+ 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));
/*
* rsyncs get truncated, because it results in much faster
* This is not defined in any RFCs; it's an effective standard,
* and there would be consequences for violating it.
*/
+ printf("==== rsync truncated ====\n");
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));
+ 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 */
+ printf("==== Sibling ====\n");
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));
+ 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));
cleanup_test();
}
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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+ rufnode("a.b.c/e", FAILED, NULL), NULL), 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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+ rufnode("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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+ rufnode("a.b.c/e", FAILED, NULL), NULL), NULL));
cleanup_test();
}
run_dl_rsync("rsync://a.b.c/e", 0, 1);
run_cleanup();
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));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/d", FULL, NULL),
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
/* One iteration with no changes, for paranoia */
printf("==== No changes, for paranoia ====\n");
run_dl_rsync("rsync://a.b.c/e", 0, 1);
run_cleanup();
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));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/d", FULL, NULL),
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
/* Add one sibling */
printf("==== Add one sibling ====\n");
run_dl_rsync("rsync://a.b.c/f", 0, 1);
run_cleanup();
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));
+ 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");
new_iteration(false);
run_cleanup();
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));
+ 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));
/* Remove some branches */
printf("==== Remove some branches ====\n");
run_dl_rsync("rsync://a.b.c/d", 0, 1);
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("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");
run_dl_rsync("rsync://a.b.c/e", 0, 1);
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
/* Try child */
printf("==== Try child ====\n");
run_dl_rsync("rsync://a.b.c/e/f/g", 0, 1);
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
/* Parent again */
printf("==== Parent again ====\n");
run_dl_rsync("rsync://a.b.c/e", 0, 1);
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
/* Empty the tree */
printf("==== Empty the tree ====\n");
new_iteration(true);
run_cleanup();
- ck_cache_rsync(unode("rsync", NULL));
+ ck_cache_rsync(runode("", NULL));
/* Node exists, but file doesn't */
run_dl_rsync("rsync://a.b.c/e", 0, 1);
run_dl_rsync("rsync://a.b.c/f", 0, 1);
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- uftnode("rsync/a.b.c/e", FULL, "tmp/tmp/B", NULL),
- uftnode("rsync/a.b.c/f", FULL, "tmp/tmp/C", NULL), NULL), NULL));
+ 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));
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/e", FULL, NULL),
- ufnode("rsync/a.b.c/f", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/e", FULL, NULL),
+ rufnode("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(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
cleanup_test();
}
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(
- 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));
+ runode("",
+ runode("a.b.c",
+ ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+ rufnode("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");
run_cleanup();
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("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");
new_iteration(false);
dl_error = -EINVAL;
run_dl_rsync("rsync://a.b.c/d", -EINVAL, 1);
ck_cache_rsync(
- unode("rsync",
- unode("rsync/a.b.c",
- ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+ runode("",
+ runode("a.b.c",
+ rufnode("a.b.c/d", DOWNLOADED, NULL), NULL), NULL));
/* Error is old; gets deleted */
+ printf("==== Error deleted because old ====\n");
new_iteration(true);
run_cleanup();
- ck_cache_rsync(unode("rsync", NULL));
+ ck_cache_rsync(runode("", NULL));
cleanup_test();
}
END_TEST
+/* XXX ================================================================ */
+
static const int HDOWNLOADED = CNF_CACHED | CNF_FRESH | CNF_CHANGED;
static const int HVALIDATED = CNF_CACHED | CNF_VALID;
static const int HFULL = HDOWNLOADED | HVALIDATED;
/* Download *file* e. */
run_dl_https("https://a.b.c/d/e", 0, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- unode("https/a.b.c/d",
- uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hunode("a.b.c/d",
+ huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL));
/* Download something else 1 */
run_dl_https("https://a.b.c/e", 0, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- unode("https/a.b.c/d",
- uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL));
+ 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));
/* Download something else 2 */
run_dl_https("https://x.y.z/e", 0, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- unode("https/a.b.c/d",
- uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL),
- unode("https/x.y.z",
- uftnode("https/x.y.z/e", HFULL, "tmp/tmp/2", NULL), NULL), NULL));
+ 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));
cleanup_test();
}
dl_error = -EINVAL;
run_dl_https("https://a.b.c/e", -EINVAL, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL),
- uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
+ 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));
/* Regardless of error, not reattempted because same iteration */
dl_error = -EINVAL;
dl_error = 0;
run_dl_https("https://a.b.c/e", -EINVAL, 0);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL),
- uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
+ 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));
cleanup_test();
}
run_dl_https("https://a.b.c/e", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/d", HFULL, NULL),
- ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/d", HFULL, NULL),
+ hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
/* Remove one branch */
new_iteration(true);
run_dl_https("https://a.b.c/d", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/d", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/d", HFULL, NULL), NULL), NULL));
/* Change the one branch */
new_iteration(true);
run_dl_https("https://a.b.c/e", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
/* Add a child to the same branch, do not update the old one */
new_iteration(true);
run_dl_https("https://a.b.c/e/f/g", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- unode("https/a.b.c/e",
- unode("https/a.b.c/e/f",
- ufnode("https/a.b.c/e/f/g", HFULL, NULL), NULL), NULL), NULL), NULL));
+ 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.
run_dl_https("https://a.b.c/e/f", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- unode("https/a.b.c/e",
- ufnode("https/a.b.c/e/f", HFULL, NULL), NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hunode("a.b.c/e",
+ hufnode("a.b.c/e/f", HFULL, NULL), NULL), NULL), NULL));
/* Do it again. */
new_iteration(true);
run_dl_https("https://a.b.c/e", 0, 1);
run_cleanup();
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
/* Empty the tree */
new_iteration(true);
run_cleanup();
- ck_cache_https(unode("https", NULL));
+ ck_cache_https(hunode("", NULL));
/* Node exists, but file doesn't */
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(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/7", NULL),
- unode("https/a.b.c/f",
- unode("https/a.b.c/f/g",
- uftnode("https/a.b.c/f/g/h", HFULL, "tmp/tmp/8", NULL), NULL), NULL), NULL), NULL));
+ 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));
run_cleanup(); /* Move from tmp/tmp to tmp/https */
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL),
- unode("https/a.b.c/f",
- unode("https/a.b.c/f/g",
- ufnode("https/a.b.c/f/g/h", HFULL, NULL), NULL), NULL), NULL), NULL));
+ 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));
ck_assert_int_eq(0, file_rm_rf("tmp/https/a.b.c/f/g/h"));
run_cleanup(); /* Actual test */
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
/* Temporal version disappears before we get a commit */
new_iteration(true);
run_dl_https("https://a.b.c/e", 0, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/9", NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ huftnode("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(unode("https", NULL));
+ ck_cache_https(hunode("", NULL));
/* Temporal version disappears after we get a commit */
new_iteration(true);
run_dl_https("https://a.b.c/e", 0, 1);
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/A", NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ huftnode("a.b.c/e", HFULL, "tmp/tmp/A", NULL), NULL), NULL));
run_cleanup(); /* Commit */
ck_cache_https(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("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(
- unode("https",
- unode("https/a.b.c",
- uftnode("https/a.b.c/e", HFULL, "tmp/tmp/B", NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ huftnode("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(
- unode("https",
- unode("https/a.b.c",
- ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
cleanup_test();
}
END_TEST
-//START_TEST(test_cache_cleanup_https_error)
-//{
-// setup_test();
-//
-// /* Set up */
-// dl_error = false;
-// run_dl_https("https://a.b.c/d", 0, 1);
-// dl_error = true;
-// run_dl_https("https://a.b.c/e", -EINVAL, 1);
-// ck_cache(
-// NODE("https://a.b.c/d", 0, 1, 1),
-// NODE("https://a.b.c/e", -EINVAL, 0, 0),
-// NULL);
-//
-// /* Deleted because file ENOENT. */
-// run_cleanup();
-// ck_cache(
-// NODE("https://a.b.c/d", 0, 1, 1),
-// NULL);
-//
-// /* Fail d */
-// new_iteration(false);
-// dl_error = true;
-// run_dl_https("https://a.b.c/d", -EINVAL, 1);
-// ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL);
-//
-// /* Not deleted, because not old */
-// new_iteration(false);
-// run_cleanup();
-// ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL);
-//
-// /* Become old */
-// new_iteration(true);
-// run_cleanup();
-// ck_cache(NULL);
-//
-// cleanup_test();
-//}
-//END_TEST
-//
-//START_TEST(test_dots)
-//{
-// setup_test();
-//
-// run_cache_download("https://a.b.c/d", 0, 0, 1);
-// ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-// run_cache_download("https://a.b.c/d/.", 0, 0, 0);
-// ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-// run_cache_download("https://a.b.c/d/e/..", 0, 0, 0);
-// ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-// run_cache_download("https://a.b.c/./d/../e", 0, 0, 1);
-// ck_cache(
-// NODE("https://a.b.c/d", 0, 1, 1),
-// NODE("https://a.b.c/./d/../e", 0, 1, 1),
-// NULL);
-//
-// cleanup_test();
-//}
-//END_TEST
+START_TEST(test_cache_cleanup_https_error)
+{
+ setup_test();
+
+ /* Set up */
+ 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));
+
+ /* Deleted because file ENOENT. */
+ run_cleanup();
+ ck_cache_https(
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/d", HFULL, NULL), NULL), NULL));
+
+ /* Fail d */
+ 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));
+
+ /* Not deleted, because not old */
+ new_iteration(false);
+ run_cleanup();
+ ck_cache_https(
+ hunode("",
+ hunode("a.b.c",
+ hufnode("a.b.c/d", CNF_CACHED, NULL), NULL), NULL));
+
+ /* Become old */
+ new_iteration(true);
+ run_cleanup();
+ ck_cache_https(hunode("", NULL));
+
+ cleanup_test();
+}
+END_TEST
+
+START_TEST(test_dots)
+{
+ setup_test();
+
+ 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));
+
+ 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));
+
+ 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));
+
+ 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));
+
+ cleanup_test();
+}
+END_TEST
//
//START_TEST(test_tal_json)
//{
// }
// va_end(args);
//}
-//
+
//#define PREPARE_MAP_LIST(maps, ...) prepare_map_list(maps, ##__VA_ARGS__, NULL)
//
//START_TEST(test_recover)
TCase *rsync, *https, *dot, *meta, *recover;
rsync = tcase_create("rsync");
-// tcase_add_test(rsync, test_cache_download_rsync);
-// tcase_add_test(rsync, test_cache_download_rsync_error);
-// tcase_add_test(rsync, test_cache_cleanup_rsync);
-// tcase_add_test(rsync, test_cache_cleanup_rsync_error);
+ tcase_add_test(rsync, test_cache_download_rsync);
+ tcase_add_test(rsync, test_cache_download_rsync_error);
+ tcase_add_test(rsync, test_cache_cleanup_rsync);
+ tcase_add_test(rsync, test_cache_cleanup_rsync_error);
https = tcase_create("https");
-// tcase_add_test(https, test_cache_download_https);
-// tcase_add_test(https, test_cache_download_https_error);
+ tcase_add_test(https, test_cache_download_https);
+ tcase_add_test(https, test_cache_download_https_error);
tcase_add_test(https, test_cache_cleanup_https);
-// tcase_add_test(https, test_cache_cleanup_https_error);
+ 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);
#include <string.h>
#include "data_structure/uthash.h"
-struct cache_node *
-vnode(char const *url, int flags, char const *tmpdir, va_list children)
+static struct cache_node *
+node(char const *schema, char const *path, int flags, char const *tmpdir,
+ va_list children)
{
struct cache_node *result;
struct cache_node *child;
+ char buffer[64];
char const *slash;
result = pzalloc(sizeof(struct cache_node));
- result->url = pstrdup(url);
- slash = strrchr(url, '/');
- result->name = slash ? (slash + 1) : result->url;
+
+ 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->name = strrchr(result->path, '/') + 1;
+ ck_assert_ptr_ne(NULL, result->name);
result->flags = flags;
- result->tmpdir = tmpdir ? pstrdup(tmpdir) : NULL;
+ result->tmppath = tmpdir ? pstrdup(tmpdir) : NULL;
while ((child = va_arg(children, struct cache_node *)) != NULL) {
HASH_ADD_KEYPTR(hh, result->children, child->name,
}
struct cache_node *
-uftnode(char const *url, int flags, char const *tmpdir, ...)
+ruftnode(char const *path, int flags, char const *tmpdir, ...)
+{
+ struct cache_node *result;
+ va_list children;
+
+ va_start(children, tmpdir);
+ result = node("rsync", path, flags, tmpdir, children);
+ va_end(children);
+
+ return result;
+}
+
+struct cache_node *
+rufnode(char const *path, int flags, ...)
+{
+ struct cache_node *result;
+ va_list children;
+
+ va_start(children, flags);
+ result = node("rsync", path, flags, NULL, children);
+ va_end(children);
+
+ return result;
+}
+
+struct cache_node *
+runode(char const *path, ...)
+{
+ struct cache_node *result;
+ va_list children;
+
+ va_start(children, path);
+ result = node("rsync", path, 0, NULL, children);
+ va_end(children);
+
+ return result;
+}
+
+struct cache_node *
+huftnode(char const *path, int flags, char const *tmpdir, ...)
{
struct cache_node *result;
va_list children;
va_start(children, tmpdir);
- result = vnode(url, flags, tmpdir, children);
+ result = node("https", path, flags, tmpdir, children);
va_end(children);
return result;
}
struct cache_node *
-ufnode(char const *url, int flags, ...)
+hufnode(char const *path, int flags, ...)
{
struct cache_node *result;
va_list children;
va_start(children, flags);
- result = vnode(url, flags, NULL, children);
+ result = node("https", path, flags, NULL, children);
va_end(children);
return result;
}
struct cache_node *
-unode(char const *url, ...)
+hunode(char const *path, ...)
{
struct cache_node *result;
va_list children;
- va_start(children, url);
- result = vnode(url, 0, NULL, children);
+ va_start(children, path);
+ result = node("https", path, 0, NULL, children);
va_end(children);
return result;
#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 *, ...);
+struct cache_node *ruftnode(char const *, int , char const *, ...);
+struct cache_node *rufnode(char const *, int , ...);
+struct cache_node *runode(char const *, ...);
+
+struct cache_node *huftnode(char const *, int , char const *, ...);
+struct cache_node *hufnode(char const *, int , ...);
+struct cache_node *hunode(char const *, ...);
#endif /* TEST_CACHE_UTIL_H_ */
{
char *normal;
- TEST_NORMALIZE("rsync://a.b.c", "rsync/a.b.c");
- TEST_NORMALIZE("rsync://a.b.c/", "rsync/a.b.c");
- TEST_NORMALIZE("rsync://a.b.c//////", "rsync/a.b.c");
- TEST_NORMALIZE("rsync://a.b.c/d/e", "rsync/a.b.c/d/e");
- TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync/a.b.c/d/e");
- TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync/a.b.c/d/e");
- TEST_NORMALIZE("rsync://a.b.c/d/./e/.", "rsync/a.b.c/d/e");
- TEST_NORMALIZE("rsync://a.b.c/d/../d/../d/e/", "rsync/a.b.c/d/e");
- TEST_NORMALIZE("rsync://a.b.c/../x/y/z", "rsync/x/y/z");
- TEST_NORMALIZE("rsync://x//y/z/../../../m/./n/o", "rsync/m/n/o");
+ TEST_NORMALIZE("rsync://a.b.c", "rsync://a.b.c");
+ TEST_NORMALIZE("rsync://a.b.c/", "rsync://a.b.c");
+ TEST_NORMALIZE("rsync://a.b.c//////", "rsync://a.b.c");
+ TEST_NORMALIZE("rsync://a.b.c/d/e", "rsync://a.b.c/d/e");
+ TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync://a.b.c/d/e");
+ TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync://a.b.c/d/e");
+ TEST_NORMALIZE("rsync://a.b.c/d/./e/.", "rsync://a.b.c/d/e");
+ TEST_NORMALIZE("rsync://a.b.c/x/../x/y/z", "rsync://a.b.c/x/y/z");
+ TEST_NORMALIZE("rsync://a.b.c/d/../d/../d/e/", "rsync://a.b.c/d/e");
+ TEST_NORMALIZE("rsync://x//y/z/../../m/./n/o", "rsync://x/m/n/o");
ck_assert_ptr_eq(NULL, url_normalize("rsync://"));
+ ck_assert_ptr_eq(NULL, url_normalize("rsync://."));
ck_assert_ptr_eq(NULL, url_normalize("rsync://.."));
ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/.."));
+ ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/../x"));
+ ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/../x/y/z"));
ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/d/e/../../.."));
ck_assert_ptr_eq(NULL, url_normalize("abcde://a.b.c/d"));
}