diff --git a/.gitignore b/.gitignore index 9a1737c1493a8adfe682ebb8418e14ff97685972..bdb7e7fa8ac6a490ce962d3b58d211e09d7b0cf7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ config.log src/old-sources src/spdlog_0.12/ build +build.* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0270e18a960fd95e5fb54524fc4b0282f62e930..ac051b7f888b5b55fb31852836f6179975425abd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -209,9 +209,9 @@ test:coverage: - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./core -as - make -j$(nproc) api - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::NORNS_TASK]" + - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_error]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_iotask_init]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_resource_init]" - - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_status]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit_copy_buffer_to_file]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit_copy_local_posix_files]" @@ -325,9 +325,9 @@ test:optimized: - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./core -as - make -j$(nproc) api - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::NORNS_TASK]" + - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_error]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_iotask_init]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_resource_init]" - - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_status]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit_copy_buffer_to_file]" - NORNS_DEBUG_CONFIG_FILE_OVERRIDE=1 ./api -as "[api::norns_submit_copy_local_posix_files]" diff --git a/include/Makefile.am b/include/Makefile.am index fdbdcd64deb1fa0c272db04344d3fe4db17a2447..633bbef2667d866665b6a283b1bbaf13124deece 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -32,10 +32,8 @@ nornsincludedir=$(includedir)/norns nornsinclude_HEADERS = \ norns/norns.h \ norns/nornsctl.h \ - norns/norns_backends.h \ norns/norns_debug.h \ norns/norns_error.h \ - norns/norns_resources.h \ norns/norns_types.h include_HEADERS = \ diff --git a/include/norns/norns.h b/include/norns/norns.h index 6cc982e67cab93993b8d8d232678e62ce2e9982e..cb0bcffc0718a990aa396e2404fc599beb8a1dff 100644 --- a/include/norns/norns.h +++ b/include/norns/norns.h @@ -38,8 +38,6 @@ #include "norns_types.h" #include "norns_error.h" -#include "norns_backends.h" -#include "norns_resources.h" #ifdef __NORNS_DEBUG__ #include "norns_debug.h" @@ -49,51 +47,37 @@ extern "C" { #endif - -/* Descriptor for an I/O task */ -typedef struct { - norns_tid_t t_id; /* task identifier */ - norns_op_t t_op; /* operation to be performed */ - norns_resource_t t_src; /* source resource */ - norns_resource_t t_dst; /* destination resource */ -} norns_iotask_t; - -/* Task types */ -#define NORNS_IOTASK_COPY 0x1 -#define NORNS_IOTASK_MOVE 0x2 -#define NORNS_IOTASK_REMOVE 0x3 - -/* I/O task status descriptor */ -typedef struct { - norns_status_t st_status; /* task current status */ - norns_error_t st_task_error; /* task return value */ - int st_sys_errno; /* errno returned if st_task_error == NORNS_ESYSTEM_ERROR */ - size_t st_pending; /* bytes pending in task */ - size_t st_total; /* total bytes in task */ -} norns_stat_t; - /**************************************************************************/ /* Client API */ /**************************************************************************/ /* Initialize an asynchronous I/O task */ -void norns_iotask_init(norns_iotask_t* task, norns_op_t operation, - norns_resource_t* src, norns_resource_t* dst) __THROW; +void +norns_iotask_init(norns_iotask_t* task, + norns_op_t operation, + norns_resource_t* src, + norns_resource_t* dst) __THROW; norns_iotask_t -NORNS_IOTASK(norns_op_t operation, norns_resource_t src, ...) __THROW; +NORNS_IOTASK(norns_op_t operation, + norns_resource_t src, ...) __THROW; /* Submit an asynchronous I/O task */ -norns_error_t norns_submit(norns_iotask_t* task) __THROW; +norns_error_t +norns_submit(norns_iotask_t* task) __THROW; /* wait for the completion of the I/O task associated to 'task' */ -norns_error_t norns_wait(norns_iotask_t* task) __THROW; +norns_error_t +norns_wait(norns_iotask_t* task) __THROW; /* Try to cancel an asynchronous I/O task associated with task */ -norns_error_t norns_cancel(norns_iotask_t* task) __THROW; +norns_error_t +norns_cancel(norns_iotask_t* task) __THROW; /* Check the status of a submitted I/O task */ -norns_error_t norns_status(norns_iotask_t* task, norns_stat_t* stats) __THROW; +norns_error_t +norns_error(norns_iotask_t* task, + norns_stat_t* stats) __THROW; /* Return a string describing the error number */ char* norns_strerror(norns_error_t errnum) __THROW; diff --git a/include/norns/norns_backends.h b/include/norns/norns_backends.h deleted file mode 100644 index 3eca26da948d0d5abdaf305b2aa784a3a995035b..0000000000000000000000000000000000000000 --- a/include/norns/norns_backends.h +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************************************* - * Copyright (C) 2017-2018 Barcelona Supercomputing Center * - * Centro Nacional de Supercomputacion * - * All rights reserved. * - * * - * This file is part of the NORNS Data Scheduler, a service that allows * - * other programs to start, track and manage asynchronous transfers of * - * data resources transfers requests between different storage backends. * - * * - * See AUTHORS file in the top level directory for information * - * regarding developers and contributors. * - * * - * The NORNS Data Scheduler is free software: you can redistribute it * - * and/or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation, either * - * version 3 of the License, or (at your option) any later version. * - * * - * The NORNS Data Scheduler is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General * - * Public License along with the NORNS Data Scheduler. If not, see * - * . * - *************************************************************************/ - -#ifndef __NORNS_BACKENDS_H__ -#define __NORNS_BACKENDS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Storage backend types */ -//#define NORNS_BACKEND_LOCAL_NVML 0x10000000 -//#define NORNS_BACKEND_REMOTE_NVML 0x10000001 -//#define NORNS_BACKEND_PROCESS_MEMORY 0x10000005 // deprecated -#define NORNS_BACKEND_NVML 0x10000001 -#define NORNS_BACKEND_LUSTRE 0x10000002 -#define NORNS_BACKEND_ECHOFS 0x10000003 -#define NORNS_BACKEND_POSIX_FILESYSTEM 0x10000004 - -#ifdef __cplusplus -} -#endif - -#endif /* __NORNS_BACKENDS_H__ */ diff --git a/include/norns/norns_resources.h b/include/norns/norns_resources.h deleted file mode 100644 index 35ff4b94aa29a3443e970597e2c231dead9c0e9a..0000000000000000000000000000000000000000 --- a/include/norns/norns_resources.h +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************************************* - * Copyright (C) 2017-2018 Barcelona Supercomputing Center * - * Centro Nacional de Supercomputacion * - * All rights reserved. * - * * - * This file is part of the NORNS Data Scheduler, a service that allows * - * other programs to start, track and manage asynchronous transfers of * - * data resources transfers requests between different storage backends. * - * * - * See AUTHORS file in the top level directory for information * - * regarding developers and contributors. * - * * - * The NORNS Data Scheduler is free software: you can redistribute it * - * and/or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation, either * - * version 3 of the License, or (at your option) any later version. * - * * - * The NORNS Data Scheduler is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General * - * Public License along with the NORNS Data Scheduler. If not, see * - * . * - *************************************************************************/ - -#ifndef __NORNS_RESOURCES_H__ -#define __NORNS_RESOURCES_H__ 1 - -#include -#include -#include /* For uint32_t et al. */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Resource types */ -#define NORNS_PROCESS_MEMORY 0x0100000 /* Memory buffer */ -#define NORNS_POSIX_PATH 0x0200000 /* POSIX path */ -#define NORNS_NULL_RESOURCE 0x1000000 - -/* Access types */ -#define R_LOCAL 0x0000010 /* Local resource (default) */ -#define R_REMOTE 0x0000020 /* Remote resource */ -#define R_SHARED 0x0000040 /* Shared resource */ - -/* Descriptor for a memory region */ -typedef struct { - void* b_addr; /* base memory address */ - size_t b_size; /* region size */ -} norns_memory_region_t; - -/* Descriptor for a POSIX path */ -typedef struct { - const char* p_nsid; /* namespace id */ - const char* p_host; /* hostname (NULL if local) */ - const char* p_path; /* path to "data" (i.e. file or directory) */ -} norns_posix_path_t; - -/* Data resource descriptor */ -typedef struct { - - // options: - // - read from local nvm and write to lustre - // - read from lustre and write to local nvm - // - read from remote nvm and write to local nvm - // - read from local nvm and write to remote nvm - // - read from process memory and write to local nvm - // - read from process memory and write to lustre - // - echofs: "read" from lustre into echofs - // - echofs: "write" from echofs to lustre - // - // - // - NEXTGenIO input resources: - // 1. local nvm nvm://path/to/dir/[file] DAX-NVML - // 2. local tmpfs tmpfs://path/to/dir/[file] DAX-NVML - // 3. lustre lustre://path/to/dir/[file] POSIX - // 4. remote nvm nvm@hostname://path/to/dir/[file] DAX-NVML+RDMA/TCP - // 5. echofs echofs://path/to/dir/[file] CUSTOM - // 6. process memory [pointer + size] MEMORY - // - // - NEXTGenIO output resources: - // 1. local nvm nvm://path/to/dir/[file] DAX-NVML - // 2. local tmpfs tmpfs://path/to/dir/[file] DAX-NVML - // 3. lustre (path) lustre://path/to/dir/[file] POSIX - // 4. remote nvm nvm@hostname:://path/to/dir/[file] DAX-NVML+RDMA/TCP - // 5. echofs echofs://path/to/dir/[file] CUSTOM - - norns_flags_t r_flags; /* resource type and flags */ - union { - norns_memory_region_t r_buffer; - norns_posix_path_t r_posix_path; - }; -} norns_resource_t; - -norns_resource_t NORNS_MEMORY_REGION(void* addr, size_t size); -norns_resource_t NORNS_LOCAL_PATH(const char* nsid, const char* path); -norns_resource_t NORNS_REMOTE_PATH(const char* nsid, const char* host, const char* path); -norns_resource_t NORNS_SHARED_PATH(const char* nsid, const char* path); - -#ifdef __cplusplus -} -#endif - -#endif /* __NORNS_RESOURCES_H__ */ diff --git a/include/norns/norns_types.h b/include/norns/norns_types.h index d42a3963e9844d1052a3385739b358fa78777504..683d8acd391c6025b2ccc5e3868e38ad8ee6012a 100644 --- a/include/norns/norns_types.h +++ b/include/norns/norns_types.h @@ -28,17 +28,138 @@ #ifndef __NORNS_TYPES_H__ #define __NORNS_TYPES_H__ 1 +#include +#include /* For uint32_t et al. */ +#include + #ifdef __cplusplus extern "C" { #endif /* Types */ typedef uint32_t norns_tid_t; -typedef uint32_t norns_op_t; typedef uint32_t norns_flags_t; typedef int32_t norns_status_t; typedef int32_t norns_error_t; +/* Resource types */ +#define NORNS_PROCESS_MEMORY 0x0100000 /* Memory buffer */ +#define NORNS_POSIX_PATH 0x0200000 /* POSIX path */ +#define NORNS_NULL_RESOURCE 0x1000000 + +/* Access types */ +#define R_LOCAL 0x0000010 /* Local resource (default) */ +#define R_REMOTE 0x0000020 /* Remote resource */ +#define R_SHARED 0x0000040 /* Shared resource */ + +/* Descriptor for a memory region */ +typedef struct { + void* b_addr; /* base memory address */ + size_t b_size; /* region size */ +} norns_memory_region_t; + +/* Descriptor for a POSIX path */ +typedef struct { + const char* p_nsid; /* namespace id */ + const char* p_host; /* hostname (NULL if local) */ + const char* p_path; /* path to "data" (i.e. file or directory) */ +} norns_posix_path_t; + +/* Data resource descriptor */ +typedef struct { + + // options: + // - read from local nvm and write to lustre + // - read from lustre and write to local nvm + // - read from remote nvm and write to local nvm + // - read from local nvm and write to remote nvm + // - read from process memory and write to local nvm + // - read from process memory and write to lustre + // - echofs: "read" from lustre into echofs + // - echofs: "write" from echofs to lustre + // + // + // - NEXTGenIO input resources: + // 1. local nvm nvm://path/to/dir/[file] DAX-NVML + // 2. local tmpfs tmpfs://path/to/dir/[file] DAX-NVML + // 3. lustre lustre://path/to/dir/[file] POSIX + // 4. remote nvm nvm@hostname://path/to/dir/[file] DAX-NVML+RDMA/TCP + // 5. echofs echofs://path/to/dir/[file] CUSTOM + // 6. process memory [pointer + size] MEMORY + // + // - NEXTGenIO output resources: + // 1. local nvm nvm://path/to/dir/[file] DAX-NVML + // 2. local tmpfs tmpfs://path/to/dir/[file] DAX-NVML + // 3. lustre (path) lustre://path/to/dir/[file] POSIX + // 4. remote nvm nvm@hostname:://path/to/dir/[file] DAX-NVML+RDMA/TCP + // 5. echofs echofs://path/to/dir/[file] CUSTOM + + norns_flags_t r_flags; /* resource type and flags */ + union { + norns_memory_region_t r_buffer; + norns_posix_path_t r_posix_path; + }; +} norns_resource_t; + +norns_resource_t +NORNS_MEMORY_REGION(void* addr, + size_t size); + +norns_resource_t +NORNS_LOCAL_PATH(const char* nsid, + const char* path); + +norns_resource_t +NORNS_REMOTE_PATH(const char* nsid, + const char* host, + const char* path); + +norns_resource_t +NORNS_SHARED_PATH(const char* nsid, + const char* path); + +/* Task types */ +typedef enum { + NORNS_IOTASK_COPY = 0x1, + NORNS_IOTASK_MOVE = 0x2, + NORNS_IOTASK_REMOVE = 0x3 +} norns_op_t; + +/* Descriptor for an I/O task */ +typedef struct { + norns_tid_t t_id; /* task identifier */ + norns_op_t t_op; /* operation to be performed */ + norns_resource_t t_src; /* source resource */ + norns_resource_t t_dst; /* destination resource */ +} norns_iotask_t; + +/* I/O task status descriptor */ +typedef struct { + norns_status_t st_status; /* task current status */ + norns_error_t st_task_error; /* task return value */ + int st_sys_errno; /* errno returned if st_task_error == NORNS_ESYSTEM_ERROR */ + size_t st_pending; /* bytes pending in task */ + size_t st_total; /* total bytes in task */ +} norns_stat_t; + + + +/* Additional administrative types */ +typedef enum { + NORNS_BACKEND_NVML = 0x10000001, + NORNS_BACKEND_LUSTRE = 0x10000002, + NORNS_BACKEND_ECHOFS = 0x10000003, + NORNS_BACKEND_POSIX_FILESYSTEM = 0x10000004 +} nornsctl_backend_flags_t; + +/* Administrative command IDs valid for nornsctl_send_command() */ +typedef enum { + NORNSCTL_CMD_PING = 1000, + NORNSCTL_CMD_PAUSE_LISTEN, + NORNSCTL_CMD_RESUME_LISTEN, + NORNSCTL_CMD_SHUTDOWN, +} nornsctl_command_t; + #ifdef __cplusplus }; #endif diff --git a/include/norns/nornsctl.h b/include/norns/nornsctl.h index 552ff97745b43076b387007719a21d412eac1121..6333454b60fd4602cd855c802b785541ac850b53 100644 --- a/include/norns/nornsctl.h +++ b/include/norns/nornsctl.h @@ -32,9 +32,7 @@ #define NORNSCTL_API_VERSION 10 #endif -#include -#include -#include "nornsctl_types.h" +#include "norns_types.h" #include "norns_error.h" #ifdef __NORNS_DEBUG__ @@ -175,6 +173,35 @@ nornsctl_update_namespace(const char* nsid, norns_error_t nornsctl_unregister_namespace(const char* nsid) __THROW; + +/* Initialize an asynchronous I/O task */ +void +nornsctl_iotask_init(norns_iotask_t* task, + norns_op_t operation, + norns_resource_t* src, + norns_resource_t* dst) __THROW; +norns_iotask_t +NORNSCTL_IOTASK(norns_op_t operation, + norns_resource_t src, ...) __THROW; + + +/* Submit an asynchronous I/O task */ +norns_error_t +nornsctl_submit(norns_iotask_t* task) __THROW; + +/* wait for the completion of the I/O task associated to 'task' */ +norns_error_t +nornsctl_wait(norns_iotask_t* task) __THROW; + +/* Try to cancel an asynchronous I/O task associated with task */ +norns_error_t +nornsctl_cancel(norns_iotask_t* task) __THROW; + +/* Check the status of a submitted I/O task */ +norns_error_t +nornsctl_error(norns_iotask_t* task, + norns_stat_t* stats) __THROW; + /* Return a string describing the error number */ char* nornsctl_strerror(norns_error_t errnum) __THROW; diff --git a/include/norns/nornsctl_types.h b/include/norns/nornsctl_types.h deleted file mode 100644 index f5aa133155e7ae213b5aa0b4d48c22c73a00568c..0000000000000000000000000000000000000000 --- a/include/norns/nornsctl_types.h +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************************************* - * Copyright (C) 2017-2018 Barcelona Supercomputing Center * - * Centro Nacional de Supercomputacion * - * All rights reserved. * - * * - * This file is part of the NORNS Data Scheduler, a service that allows * - * other programs to start, track and manage asynchronous transfers of * - * data resources transfers requests between different storage backends. * - * * - * See AUTHORS file in the top level directory for information * - * regarding developers and contributors. * - * * - * The NORNS Data Scheduler is free software: you can redistribute it * - * and/or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation, either * - * version 3 of the License, or (at your option) any later version. * - * * - * The NORNS Data Scheduler is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General * - * Public License along with the NORNS Data Scheduler. If not, see * - * . * - *************************************************************************/ - -#ifndef __NORNSCTL_TYPES_H__ -#define __NORNSCTL_TYPES_H__ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#include "norns_types.h" - -/* Additional administrative types */ -typedef uint32_t nornsctl_backend_flags_t; -//typedef uint32_t nornsctl_command_t; - -/* Administrative command IDs valid for nornsctl_send_command() */ -typedef enum { - NORNSCTL_CMD_PING = 1000, - NORNSCTL_CMD_PAUSE_LISTEN, - NORNSCTL_CMD_RESUME_LISTEN, - NORNSCTL_CMD_SHUTDOWN, -} nornsctl_command_t; - - -#ifdef __cplusplus -}; -#endif - -#endif /* __NORNSCTL_TYPES_H__ */ diff --git a/lib/libnorns.c b/lib/libnorns.c index da4fd57ba90642a460498386f971734328638232..ed8de57932721c6160977bd7c68197d96fe85717 100644 --- a/lib/libnorns.c +++ b/lib/libnorns.c @@ -204,7 +204,7 @@ norns_submit(norns_iotask_t* task) { } norns_error_t -norns_status(norns_iotask_t* task, norns_stat_t* stats) { +norns_error(norns_iotask_t* task, norns_stat_t* stats) { if(task == NULL || stats == NULL) { return NORNS_EBADARGS; diff --git a/lib/libnornsctl.c b/lib/libnornsctl.c index d2bd5e153b9c95204de812aff78e3da5487fb60a..0e7c03d060846d84720d0942d6198e3754439cf9 100644 --- a/lib/libnornsctl.c +++ b/lib/libnornsctl.c @@ -45,6 +45,7 @@ #include "defaults.h" #define LIBNORNSCTL_LOG_PREFIX "libnornsctl" +#define MIN_WAIT_TIME ((useconds_t) 250*1e3) static bool validate_job(nornsctl_job_t* job); static bool validate_namespace(nornsctl_backend_t* backend); @@ -331,6 +332,108 @@ nornsctl_job_init(nornsctl_job_t* job, const char** hosts, size_t nhosts, job->j_nlimits = nlimits; } +norns_iotask_t +NORNSCTL_IOTASK(norns_op_t optype, norns_resource_t src, ...) { + norns_iotask_t task; + + if(optype == NORNS_IOTASK_REMOVE) { + nornsctl_iotask_init(&task, optype, &src, NULL); + return task; + } + + va_list ap; + va_start(ap, src); + norns_resource_t dst = va_arg(ap, norns_resource_t); + nornsctl_iotask_init(&task, optype, &src, &dst); + va_end(ap); + + return task; +} + +void +nornsctl_iotask_init(norns_iotask_t* task, + norns_op_t optype, + norns_resource_t* src, + norns_resource_t* dst) { + + if(task == NULL) { + return; + } + + memset(task, 0, sizeof(*task)); + + if(src == NULL) { + return; + } + + task->t_id = 0; + task->t_op = optype; + task->t_src = *src; + + if(dst != NULL) { + task->t_dst = *dst; + return; + } + + // dst is NULL, set r_flags so that we are aware of it later + task->t_dst.r_flags = NORNS_NULL_RESOURCE; +} + +norns_error_t +nornsctl_submit(norns_iotask_t* task) { + + if(task == NULL) { + return NORNS_EBADARGS; + } + + return send_submit_request(task); +} + +norns_error_t +nornsctl_error(norns_iotask_t* task, + norns_stat_t* stats) { + + if(task == NULL || stats == NULL) { + return NORNS_EBADARGS; + } + + return send_status_request(task, stats); +} + +/* wait for the completion of the I/O task associated to 'task' */ +norns_error_t +nornsctl_wait(norns_iotask_t* task) { + + norns_error_t rv; + norns_stat_t stats; + + if(task == NULL) { + ERR("invalid arguments"); + return NORNS_EBADARGS; + } + + do { + rv = send_status_request(task, &stats); + + if(rv != NORNS_SUCCESS) { + ERR("error waiting for request: %s", norns_strerror(rv)); + return rv; + } + + if(stats.st_status == NORNS_EFINISHED || + stats.st_status == NORNS_EFINISHEDWERROR) { + return NORNS_SUCCESS; + } + + // wait for 250 milliseconds + // before retrying + usleep(MIN_WAIT_TIME); + } while(true); + + return NORNS_SUCCESS; +} + + static bool validate_namespace(nornsctl_backend_t* backend) { diff --git a/src/backends/posix-fs.hpp b/src/backends/posix-fs.hpp index 5e558b87b4eadbb0a67bd0e24f736c9086b1d472..b631e8bce00e249a85dc8c60df0f8f85c694a7d6 100644 --- a/src/backends/posix-fs.hpp +++ b/src/backends/posix-fs.hpp @@ -31,7 +31,6 @@ #include #include -#include "norns/norns_backends.h" #include "backend-base.hpp" namespace bfs = boost::filesystem; diff --git a/src/backends/process-memory.hpp b/src/backends/process-memory.hpp index 9db0236b87e5644562d4ebb52dea6282b5831168..8db45700b294ebab287feb7f0c07a15e655dafff 100644 --- a/src/backends/process-memory.hpp +++ b/src/backends/process-memory.hpp @@ -31,7 +31,6 @@ #include #include -#include "norns/norns_backends.h" #include "backend-base.hpp" namespace bfs = boost::filesystem; diff --git a/src/io/task-manager.cpp b/src/io/task-manager.cpp index 6a1e4f40f6567ccfac2bb81c5714a1a4b0838670..c92b8ded442d00b4c030e662f60ea2d2f35b6fed 100644 --- a/src/io/task-manager.cpp +++ b/src/io/task-manager.cpp @@ -175,11 +175,13 @@ task_manager::create_task(iotask_type type, return it->second; }(); - // helper lambda to register the completion of tasks so that we can keep track - // of the consumed bandwidth by each task - // N.B: we use capture-by-value here so that the task_info_ptr is valid when - // the callback is invoked. - const auto register_completion = [=]() { + auto self(std::enable_shared_from_this::shared_from_this()); + + // helper lambda to register the completion of tasks so that we can keep + // track of the consumed bandwidth by each task + // N.B: we capture self and task_info_ptr (both shared_ptrs) by value to + // make sure that they will still be alive when the callback is invoked. + const auto register_completion = [self, task_info_ptr]() { assert(task_info_ptr->status() == task_status::finished || task_info_ptr->status() == task_status::finished_with_error); @@ -194,12 +196,12 @@ task_manager::create_task(iotask_type type, const auto key = std::make_pair(task_info_ptr->src_rinfo()->nsid(), task_info_ptr->dst_rinfo()->nsid()); - if(!m_bandwidth_backlog.count(key)) { - m_bandwidth_backlog.emplace(key, - boost::circular_buffer(m_backlog_size)); + if(!self->m_bandwidth_backlog.count(key)) { + self->m_bandwidth_backlog.emplace(key, + boost::circular_buffer(self->m_backlog_size)); } - m_bandwidth_backlog.at(key).push_back(bw); + self->m_bandwidth_backlog.at(key).push_back(bw); } }; diff --git a/src/io/task-manager.hpp b/src/io/task-manager.hpp index 36a10c7d795e29280da2f7c3c67361e14d705637..03bce143709da92f0198f032fa59a15df4685612 100644 --- a/src/io/task-manager.hpp +++ b/src/io/task-manager.hpp @@ -50,7 +50,7 @@ enum class task_status; struct task_stats; struct task_info; -struct task_manager { +struct task_manager : public std::enable_shared_from_this { struct pair_hash { template diff --git a/tests/Makefile.am b/tests/Makefile.am index 8de929bd3902425cc42bff9b69aaa02e7cb37dd3..9122ac0791d8275386e30b83f5efe7242bb0da5c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -63,6 +63,12 @@ api_SOURCES = \ api-task-submit.cpp \ api-task-status.cpp \ api-send-command.cpp \ + api-ctl-copy-local-data.cpp \ + api-ctl-task-init.cpp \ + api-ctl-task-submit.cpp \ + api-ctl-task-status.cpp \ + api-ctl-copy-remote-data.cpp \ + api-ctl-remove-local-data.cpp \ compare-files.cpp \ compare-files.hpp \ config-template.cpp \ diff --git a/tests/api-copy-local-data.cpp b/tests/api-copy-local-data.cpp index c7a495fb1b6f45362fef705cea7d3004a0737a95..1e99cf974f4d47dcae1884e3a8c0f65c27ea7f0e 100644 --- a/tests/api-copy-local-data.cpp +++ b/tests/api-copy-local-data.cpp @@ -26,14 +26,14 @@ *************************************************************************/ #include "norns.h" -#include "nornsctl.h" #include "test-env.hpp" #include "compare-files.hpp" #include "catch.hpp" namespace bfs = boost::filesystem; -SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_local_posix_files]") { +SCENARIO("copy local POSIX file to local POSIX file", + "[api::norns_submit_copy_local_posix_files]") { GIVEN("a running urd instance") { test_env env; @@ -43,8 +43,10 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l bfs::path src_mnt, dst_mnt; // create namespaces - std::tie(std::ignore, src_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); - std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid1, "mnt/tmp1", 16384); + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); // define input names const bfs::path src_file_at_root = "/file0"; @@ -134,33 +136,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // create required output directories env.add_to_namespace(nsid1, dst_subdir1); - /**************************************************************************************************************/ - /* tests for error conditions */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ // - trying to copy a non-existing file WHEN("copying a non-existing NORNS_LOCAL_PATH file") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -174,27 +177,28 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // - trying to copy a non-existing directory WHEN("copying a non-existing NORNS_LOCAL_PATH directory") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -208,27 +212,27 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // - trying to copy an empty directory WHEN("copying an empty NORNS_LOCAL_PATH directory") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_SUCCESS and ENOENT are reported") { + THEN("norns_error() reports NORNS_SUCCESS and ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -241,33 +245,37 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } -//FIXME: DISABLED in CI until impersonation is implemented or capabilities can be added to the docker service +//FIXME: DISABLED in CI until impersonation is implemented or +// capabilities can be added to the docker service #ifdef __SETCAP_TESTS__ - // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate permissions to access it") { + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -280,30 +288,33 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from a subdir without appropriate permissions to access it") { + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -316,30 +327,33 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from a subdir without appropriate permissions to access a parent") { + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -352,30 +366,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without appropriate permissions to access it") { + // - trying to copy a subdir from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -388,30 +406,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without appropriate permissions to access it") { + // - trying to copy a subdir from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access it") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -424,30 +446,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without appropriate permissions to access a parent") { + // - trying to copy a subdir from namespace root with invalid + // access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -465,27 +491,28 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l WHEN("copying a NORNS_LOCAL_PATH through a symbolic link that leads " "out of the src namespace") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, out_symlink.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, out_symlink.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -497,35 +524,38 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } - /**************************************************************************************************************/ - /* tests for single files */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for single files */ + /**********************************************************************/ // cp -r ns0://file0.txt -> ns1:// = ns1://file0.txt WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " - "another NORNS_LOCAL_PATH at dst namespace's root (keeping the name)") { + "another NORNS_LOCAL_PATH at dst namespace's root (keeping the " + "name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_root); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_files(src, dst) == true); } @@ -535,29 +565,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // cp -r ns0://file0.txt -> ns1://file1.txt = ns1://file1.txt WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " - "another NORNS_LOCAL_PATH at dst namespace's root (changing the name)") { + "another NORNS_LOCAL_PATH at dst namespace's root (changing the " + "name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_root); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root1); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root1); REQUIRE(compare_files(src, dst) == true); } @@ -565,31 +598,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../d/file0.txt -> ns1://file0.txt = ns1://file0.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at dst namespace's root (keeping the name)") { + // cp -r ns0://a/b/c/.../d/file0.txt -> + // ns1://file0.txt = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at dst namespace's root " + "(keeping the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_files(src, dst) == true); } @@ -597,31 +635,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../d/file0.txt -> ns1://file1.txt = ns1://file1.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at dst namespace's root (changing the name)") { + // cp -r ns0://a/b/c/.../d/file0.txt -> + // ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at dst namespace's root (changing " + "the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root1); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root1); REQUIRE(compare_files(src, dst) == true); } @@ -629,31 +672,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://file0.txt -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + // cp -r ns0://file0.txt -> + // ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping the name)") { + "another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping " + "the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_root); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir0); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir0); REQUIRE(compare_files(src, dst) == true); } @@ -661,31 +709,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://file0.txt -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + // cp -r ns0://file0.txt -> + // ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing the name)") { + "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing " + "the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_root); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir1); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir1); REQUIRE(compare_files(src, dst) == true); } @@ -693,31 +746,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../file0.txt -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping the name)") { + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping " + "the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir0); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir0); REQUIRE(compare_files(src, dst) == true); } @@ -725,31 +783,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../file0.txt -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing the name)") { + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir " + "(changing the name)") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir1); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir1); REQUIRE(compare_files(src, dst) == true); } @@ -757,31 +820,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../file0.txt -> ns1://e/f/g/.../file0.txt = ns1://e/f/g/.../file0.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing the parents names)") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://e/f/g/.../file0.txt = ns1://e/f/g/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir " + "(changing the parents names)") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir2.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir2.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir2); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir2); REQUIRE(compare_files(src, dst) == true); } @@ -789,31 +857,36 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - // cp -r ns0://a/b/c/.../file0.txt -> ns1://e/f/g/.../file1.txt = ns1://e/f/g/.../file1.txt - WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir to " - "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing the name)") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://e/f/g/.../file1.txt = ns1://e/f/g/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir (changing " + "the name)") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_subdir3.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir3.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_file_at_subdir); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_subdir3); + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir3); REQUIRE(compare_files(src, dst) == true); } @@ -821,34 +894,35 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - /**************************************************************************************************************/ - /* tests for directories */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for directories */ + /**********************************************************************/ // cp -r /a/contents.* -> / = /contents.* - WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src namespace's root to " - "dst namespace's root") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to dst namespace's root") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir0); - bfs::path dst = env.get_from_namespace(nsid1, dst_root); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); REQUIRE(compare_directories(src, dst) == true); } @@ -860,27 +934,28 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l WHEN("copying the contents of a NORNS_LOCAL_PATH arbitrary subdir to " "dst namespace's root") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir1); - bfs::path dst = env.get_from_namespace(nsid1, dst_root); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); REQUIRE(compare_directories(src, dst) == true); } @@ -890,30 +965,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // cp -r /a/contents.* -> /c = /c/contents.* // (c did not exist previously) - WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src namespace's root to " - "another NORNS_LOCAL_PATH subdir at dst namespace's root while changing its name") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir0); - bfs::path dst = env.get_from_namespace(nsid1, dst_subdir0); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); REQUIRE(compare_directories(src, dst) == true); } @@ -923,30 +1000,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // cp -r /a/contents.* -> /c = /c/contents.* // (c did exist previously) - WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src namespace's root to " - "another NORNS_LOCAL_PATH subdir at dst namespace's root while changing its name") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir0); - bfs::path dst = env.get_from_namespace(nsid1, dst_subdir1); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); REQUIRE(compare_directories(src, dst) == true); } @@ -956,30 +1035,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* // (c did not exist previously) - WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src namespace's root to " - "another NORNS_LOCAL_PATH subdir at dst namespace's root while changing its name") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir1); - bfs::path dst = env.get_from_namespace(nsid1, dst_subdir0); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); REQUIRE(compare_directories(src, dst) == true); } @@ -989,30 +1070,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* // (c did exist previously) - WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src namespace's root to " - "another NORNS_LOCAL_PATH subdir at dst namespace's root while changing its name") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Copied files are identical to original") { - bfs::path src = env.get_from_namespace(nsid0, src_subdir1); - bfs::path dst = env.get_from_namespace(nsid1, dst_subdir1); + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); REQUIRE(compare_directories(src, dst) == true); } @@ -1020,34 +1103,37 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - /**************************************************************************************************************/ - /* tests for soft links */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for soft links */ + /**********************************************************************/ WHEN("copying a single NORNS_LOCAL_PATH file from src namespace's '/' " "through a symlink also located at '/'" ) { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_root0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_root0); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_files(src, dst) == true); } @@ -1055,31 +1141,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's '/' " - "through a symlink also located at '/'" ) { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at '/'" ) { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_root1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directories are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_root1); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_directories(src, dst) == true); } @@ -1090,28 +1179,31 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" "through a symlink also located at '/'" ) { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_root2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directories are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_root2); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_directories(src, dst) == true); } @@ -1122,28 +1214,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l WHEN("copying a single NORNS_LOCAL_PATH file from src namespace's '/' " "through a symlink located in a subdir" ) { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Files are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_subdir0); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_files(src, dst) == true); } @@ -1151,31 +1247,34 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } } - WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's '/' " - "through a symlink also located at subdir" ) { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at subdir" ) { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directories are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_subdir1); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_directories(src, dst) == true); } @@ -1186,28 +1285,32 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" "through a symlink also located at a subdir" ) { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directories are equal") { - bfs::path src = env.get_from_namespace(nsid0, src_symlink_at_subdir2); - bfs::path dst = env.get_from_namespace(nsid1, dst_file_at_root0); + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); REQUIRE(compare_directories(src, dst) == true); } @@ -1238,7 +1341,8 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l } -SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_copy_buffer_to_file]") { +SCENARIO("copy local memory buffer to local POSIX file", + "[api::norns_submit_copy_buffer_to_file]") { GIVEN("a running urd instance") { test_env env; @@ -1247,7 +1351,8 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop bfs::path dst_mnt; // create namespaces - std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); // create input data buffer std::vector input_data(100, 42); @@ -1273,16 +1378,19 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop /* tests for error conditions */ /**************************************************************************************************************/ //TODO - // - copy a valid but removed memory region (cannot control => undefined behavior) - // - providing a non-existing directory path (i.e. finished with /) as output name - // - providing an existing path that points to a directory as output name + // - copy a valid but removed memory region + // (cannot control => undefined behavior) + // - providing a non-existing directory path (i.e. finished with /) as + // output name + // - providing an existing path that points to a directory as + // output name WHEN("copying an invalid memory region to a local POSIX file") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION((void*) 0x42, region_size), - NORNS_LOCAL_PATH(nsid0, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION((void*) 0x42, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); @@ -1296,9 +1404,10 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and EFAULT") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EFAULT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -1309,13 +1418,14 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX file located at '/'") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX file located " + "at '/'") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); @@ -1331,7 +1441,8 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop THEN("Output file contains buffer data") { - bfs::path dst = env.get_from_namespace(nsid0, dst_file_at_root0); + bfs::path dst = + env.get_from_namespace(nsid0, dst_file_at_root0); REQUIRE(compare(input_data, dst) == true); } @@ -1339,13 +1450,14 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX file located at a subdir") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX file located at a " + "subdir") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_file_at_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_subdir0.c_str())); norns_error_t rv = norns_submit(&task); @@ -1361,7 +1473,8 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop THEN("Output file contains buffer data") { - bfs::path dst = env.get_from_namespace(nsid0, dst_file_at_subdir0); + bfs::path dst = + env.get_from_namespace(nsid0, dst_file_at_subdir0); REQUIRE(compare(input_data, dst) == true); } @@ -1371,11 +1484,10 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop WHEN("copying a valid memory region to a local POSIX /") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_root.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_root.c_str())); norns_error_t rv = norns_submit(&task); @@ -1384,13 +1496,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX existing directory at /") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX existing " + "directory at /") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir0.c_str())); norns_error_t rv = norns_submit(&task); @@ -1399,13 +1511,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX existing directory at /") { + WHEN("copying a valid memory region to a local POSIX existing " + "directory at /") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir1.c_str())); norns_error_t rv = norns_submit(&task); @@ -1419,9 +1531,10 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and EISDIR") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); @@ -1431,13 +1544,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX existing directory at an arbitary subdir") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX existing " + "directory at an arbitary subdir") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir2.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir2.c_str())); norns_error_t rv = norns_submit(&task); @@ -1446,13 +1559,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX existing directory at an arbitary subdir") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX existing " + "directory at an arbitary subdir") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir3.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir3.c_str())); norns_error_t rv = norns_submit(&task); @@ -1466,9 +1579,10 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and EISDIR") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); @@ -1480,13 +1594,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop // i.e. a destination path that 'looks like' a directory - WHEN("copying a valid memory region to a local POSIX non-existing directory") { + WHEN("copying a valid memory region to a local POSIX non-existing " + "directory") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir4.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir4.c_str())); norns_error_t rv = norns_submit(&task); @@ -1495,13 +1609,13 @@ SCENARIO("copy local memory buffer to local POSIX file", "[api::norns_submit_cop } } - WHEN("copying a valid memory region to a local POSIX non-existing directory") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a valid memory region to a local POSIX non-existing " + "directory") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(region_addr, region_size), - NORNS_LOCAL_PATH(nsid0, dst_subdir5.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir5.c_str())); norns_error_t rv = norns_submit(&task); diff --git a/tests/api-copy-remote-data.cpp b/tests/api-copy-remote-data.cpp index 5447d1c5d62cee43c8b9c1950ba99924809d7bda..6a88aec28c2a16a3a7381f44108efc01900ac60d 100644 --- a/tests/api-copy-remote-data.cpp +++ b/tests/api-copy-remote-data.cpp @@ -26,7 +26,6 @@ *************************************************************************/ #include "norns.h" -#include "nornsctl.h" #include "test-env.hpp" #include "compare-files.hpp" #include "catch.hpp" @@ -170,7 +169,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -205,7 +204,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -240,7 +239,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_SUCCESS and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -282,7 +281,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -320,7 +319,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -359,7 +358,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -399,7 +398,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -438,7 +437,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -478,7 +477,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -517,7 +516,7 @@ SCENARIO("errors copying local POSIX path to remote POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -672,9 +671,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -720,9 +719,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -767,9 +766,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -816,9 +815,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -863,9 +862,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -910,9 +909,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -957,9 +956,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1004,9 +1003,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1051,9 +1050,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1098,9 +1097,9 @@ SCENARIO("copy local POSIX file to remote POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1262,9 +1261,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1306,9 +1305,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1352,9 +1351,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1398,9 +1397,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1444,9 +1443,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1490,9 +1489,9 @@ SCENARIO("copy local POSIX file to remote POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1577,9 +1576,9 @@ SCENARIO("copy local memory region to remote POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1616,9 +1615,9 @@ SCENARIO("copy local memory region to remote POSIX file", // wait until the task completes rv = norns_wait(&task); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -1727,10 +1726,10 @@ SCENARIO("errors copying local memory region to remote POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and " + THEN("norns_error() reports NORNS_ESYSTEMERROR and " "EFAULT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -1812,10 +1811,10 @@ SCENARIO("errors copying local memory region to remote POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and " + THEN("norns_error() reports NORNS_ESYSTEMERROR and " "EISDIR") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); @@ -1875,10 +1874,10 @@ SCENARIO("errors copying local memory region to remote POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_ESYSTEMERROR and " + THEN("norns_error() reports NORNS_ESYSTEMERROR and " "EISDIR") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); @@ -2094,9 +2093,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2138,9 +2137,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2182,9 +2181,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2226,9 +2225,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2271,9 +2270,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2316,9 +2315,9 @@ SCENARIO("copy local POSIX path to remote POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2480,7 +2479,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2516,7 +2515,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2552,7 +2551,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_SUCCESS and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -2595,7 +2594,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2635,7 +2634,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2674,7 +2673,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2714,7 +2713,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2753,7 +2752,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2793,7 +2792,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " "are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2832,7 +2831,7 @@ SCENARIO("errors copying remote POSIX path to local POSIX path", THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -2988,9 +2987,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3035,9 +3034,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() return NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3081,9 +3080,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3129,9 +3128,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3177,9 +3176,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3225,9 +3224,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3273,9 +3272,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3321,9 +3320,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3369,9 +3368,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3417,9 +3416,9 @@ SCENARIO("copy remote POSIX file to local POSIX file", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3579,9 +3578,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3624,9 +3623,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3671,9 +3670,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3718,9 +3717,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3765,9 +3764,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3812,9 +3811,9 @@ SCENARIO("copy remote POSIX subdir to local POSIX subdir", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -3991,9 +3990,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -4035,9 +4034,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -4079,9 +4078,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -4123,9 +4122,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -4168,9 +4167,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); @@ -4213,9 +4212,9 @@ SCENARIO("copy remote POSIX path to local POSIX path involving links", THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("norns_status() reports NORNS_EFINISHED") { + THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); diff --git a/tests/api-ctl-copy-local-data.cpp b/tests/api-ctl-copy-local-data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b8318a387f2050bb9c29b8dd0735e5af8a4acd3 --- /dev/null +++ b/tests/api-ctl-copy-local-data.cpp @@ -0,0 +1,1638 @@ +/************************************************************************* + * Copyright (C) 2017-2018 Barcelona Supercomputing Center * + * Centro Nacional de Supercomputacion * + * All rights reserved. * + * * + * This file is part of the NORNS Data Scheduler, a service that allows * + * other programs to start, track and manage asynchronous transfers of * + * data resources transfers requests between different storage backends. * + * * + * See AUTHORS file in the top level directory for information * + * regarding developers and contributors. * + * * + * The NORNS Data Scheduler is free software: you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation, either * + * version 3 of the License, or (at your option) any later version. * + * * + * The NORNS Data Scheduler is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General * + * Public License along with the NORNS Data Scheduler. If not, see * + * . * + *************************************************************************/ + +#include "nornsctl.h" +#include "test-env.hpp" +#include "compare-files.hpp" +#include "catch.hpp" + +namespace bfs = boost::filesystem; + +SCENARIO("copy local POSIX file to local POSIX file (admin)", + "[api::nornsctl_submit_copy_local_posix_files]") { + GIVEN("a running urd instance") { + + test_env env; + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 4096); + env.add_to_namespace(nsid0, src_file_at_subdir, 8192); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ + // - trying to copy a non-existing file + WHEN("copying a non-existing NORNS_LOCAL_PATH file") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_invalid_file.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy a non-existing directory + WHEN("copying a non-existing NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_invalid_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy an empty directory + WHEN("copying an empty NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_empty_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_SUCCESS and ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + REQUIRE(stats.st_task_error == NORNS_SUCCESS); + REQUIRE(stats.st_sys_errno == 0); + + REQUIRE(bfs::exists(dst_mnt / dst_file_at_root0)); + } + } + } + } + +//FIXME: DISABLED in CI until impersonation is implemented or +// capabilities can be added to the docker service +#ifdef __SETCAP_TESTS__ + + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_file2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access + // permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid + // access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } +#endif + + // symlink leading out of namespace + WHEN("copying a NORNS_LOCAL_PATH through a symbolic link that leads " + "out of the src namespace") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, out_symlink.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + + /**********************************************************************/ + /* tests for single files */ + /**********************************************************************/ + // cp -r ns0://file0.txt -> ns1:// = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " + "another NORNS_LOCAL_PATH at dst namespace's root (keeping the " + "name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://file0.txt -> ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " + "another NORNS_LOCAL_PATH at dst namespace's root (changing the " + "name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt -> + // ns1://file0.txt = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at dst namespace's root " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt -> + // ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at dst namespace's root (changing " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://file0.txt -> + // ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " + "another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://file0.txt -> + // ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from src namespace's root to " + "another NORNS_LOCAL_PATH at a dst namespace's subdir (changing " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir (keeping " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://e/f/g/.../file0.txt = ns1://e/f/g/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir " + "(changing the parents names)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir2.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir2); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt -> + // ns1://e/f/g/.../file1.txt = ns1://e/f/g/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a src namespace's subdir " + "to another NORNS_LOCAL_PATH at a dst namespace's subdir (changing " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir3.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_subdir3); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + /**********************************************************************/ + /* tests for directories */ + /**********************************************************************/ + // cp -r /a/contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to dst namespace's root") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_LOCAL_PATH arbitrary subdir to " + "dst namespace's root") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root to another NORNS_LOCAL_PATH subdir at dst " + "namespace's root while changing its name") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + /**********************************************************************/ + /* tests for soft links */ + /**********************************************************************/ + WHEN("copying a single NORNS_LOCAL_PATH file from src namespace's '/' " + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH file from src namespace's '/' " + "through a symlink located in a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace( + nsid0, src_symlink_at_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink also located at a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ECONNFAILED is returned") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + + +SCENARIO("copy local memory buffer to local POSIX file (admin)", + "[api::nornsctl_submit_copy_buffer_to_file]") { + GIVEN("a running urd instance") { + + test_env env; + + const char* nsid0 = "tmp0"; + bfs::path dst_mnt; + + // create namespaces + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + // output names + const bfs::path dst_file_at_root0 = "/file0"; + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0/"; // existing + const bfs::path dst_subdir1 = "/output_dir0"; // existing but does not look as a directory + const bfs::path dst_subdir2 = "/output_dir0/a/b/c/d/"; // existing + const bfs::path dst_subdir3 = "/output_dir0/a/b/c/d"; // existing but does not look as a directory + const bfs::path dst_subdir4 = "/output_dir1/"; // non-existing + const bfs::path dst_subdir5 = "/output_dir1/a/b/c/d/"; // non-existing + + // create required output directories + env.add_to_namespace(nsid0, dst_subdir0); + env.add_to_namespace(nsid0, dst_subdir2); + + /**************************************************************************************************************/ + /* tests for error conditions */ + /**************************************************************************************************************/ + //TODO + // - copy a valid but removed memory region + // (cannot control => undefined behavior) + // - providing a non-existing directory path (i.e. finished with /) as + // output name + // - providing an existing path that points to a directory as + // output name + WHEN("copying an invalid memory region to a local POSIX file") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION((void*) 0x42, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EFAULT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EFAULT); + } + } + } + } + + WHEN("copying a valid memory region to a local POSIX file located " + "at '/'") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Output file contains buffer data") { + + bfs::path dst = + env.get_from_namespace(nsid0, dst_file_at_root0); + + REQUIRE(compare(input_data, dst) == true); + } + } + } + } + + WHEN("copying a valid memory region to a local POSIX file located at a " + "subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Output file contains buffer data") { + + bfs::path dst = + env.get_from_namespace(nsid0, dst_file_at_subdir0); + + REQUIRE(compare(input_data, dst) == true); + } + } + } + } + + WHEN("copying a valid memory region to a local POSIX /") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a local POSIX existing " + "directory at /") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a local POSIX existing " + "directory at /") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EISDIR); + } + } + } + } + + WHEN("copying a valid memory region to a local POSIX existing " + "directory at an arbitary subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir2.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a local POSIX existing " + "directory at an arbitary subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir3.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EISDIR); + } + } + } + } + + + // i.e. a destination path that 'looks like' a directory + WHEN("copying a valid memory region to a local POSIX non-existing " + "directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir4.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a local POSIX non-existing " + "directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_LOCAL_PATH(nsid0, dst_subdir5.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + env.notify_success(); + } +} diff --git a/tests/api-ctl-copy-remote-data.cpp b/tests/api-ctl-copy-remote-data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82c23160aa2f47d17ea7acc6e2a01f94505e1e72 --- /dev/null +++ b/tests/api-ctl-copy-remote-data.cpp @@ -0,0 +1,4239 @@ +/************************************************************************* + * Copyright (C) 2017-2018 Barcelona Supercomputing Center * + * Centro Nacional de Supercomputacion * + * All rights reserved. * + * * + * This file is part of the NORNS Data Scheduler, a service that allows * + * other programs to start, track and manage asynchronous transfers of * + * data resources transfers requests between different storage backends. * + * * + * See AUTHORS file in the top level directory for information * + * regarding developers and contributors. * + * * + * The NORNS Data Scheduler is free software: you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation, either * + * version 3 of the License, or (at your option) any later version. * + * * + * The NORNS Data Scheduler is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General * + * Public License along with the NORNS Data Scheduler. If not, see * + * . * + *************************************************************************/ + +#include "nornsctl.h" +#include "test-env.hpp" +#include "compare-files.hpp" +#include "catch.hpp" + +namespace bfs = boost::filesystem; + +/******************************************************************************/ +/* tests for push transfers (errors) */ +/******************************************************************************/ +SCENARIO("errors copying local POSIX path to remote POSIX path (admin)", + "[api::nornsctl_submit_push_errors]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + // - trying to copy a non-existing file + WHEN("copying a non-existing NORNS_LOCAL_PATH file") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy a non-existing directory + WHEN("copying a non-existing NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy an empty directory + WHEN("copying an empty NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_SUCCESS and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + REQUIRE(stats.st_task_error == NORNS_SUCCESS); + REQUIRE(stats.st_sys_errno == 0); + + REQUIRE(bfs::exists(dst_mnt / dst_file_at_root0)); + } + } + } + } + +//FIXME: DISABLED in CI until impersonation is implemented or capabilities can be added to the docker service +#ifdef __SETCAP_TESTS__ + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir " + "without appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // symlink leading out of namespace + WHEN("copying a NORNS_LOCAL_PATH through a symbolic link that leads " + "out of the SRC namespace") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + out_symlink.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } +#endif + + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for push transfers (single files) */ +/******************************************************************************/ +SCENARIO("copy local POSIX file to remote POSIX file (admin)", + "[api::nornsctl_submit_push_to_posix_file]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + // cp -r ns0://file0.txt + // -> ns1:// = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_REMOTE_PATH at DST namespace's root " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at DST namespace's root " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt + // -> ns1://file0.txt = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at DST namespace's root (keeping " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt + // -> ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at DST namespace's root (changing " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://e/f/g/.../file0.txt = ns1://e/f/g/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the parents names)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir2.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir2); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://e/f/g/.../file1.txt = ns1://e/f/g/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_subdir3.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir3); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for push transfers (directories) */ +/******************************************************************************/ +SCENARIO("copy local POSIX file to remote POSIX subdir (admin)", + "[api::nornsctl_submit_push_to_posix_subdir]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + // cp -r /a/contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from SRC " + "namespace's root to DST namespace's root\n" + " cp -r /a/contents.* -> / = /contents.* ") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_LOCAL_PATH arbitrary subdir to " + "DST namespace's root\n" + " cp -r /a/b/c/.../contents.* -> / = /contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from SRC " + "namespace's root to another NORNS_REMOTE_PATH subdir at DST " + "namespace's root while changing its name\n" + " cp -r /a/contents.* -> /c = /c/contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from SRC " + "namespace's root to another NORNS_REMOTE_PATH subdir at DST " + "namespace's root while changing its name\n" + " cp -r /a/contents.* -> /c / /c/contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from SRC " + "namespace's root to a NORNS_REMOTE_PATH subdir at DST " + "namespace's root while changing its name\n" + "cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_LOCAL_PATH subdir from SRC " + "namespace's root to another NORNS_REMOTE_PATH subdir at DST " + "namespace's root while changing its name:" + " cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for push transfers (memory buffers) */ +/******************************************************************************/ +SCENARIO("copy local memory region to remote POSIX file (admin)", + "[api::nornsctl_submit_push_memory_to_posix_file]") { + + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env; + + const char* nsid0 = "tmp0"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path dst_mnt; + + // create namespaces + std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); + + // create input data buffer (around 40MiBs) + std::vector input_data(10000000, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + // output names + const bfs::path dst_file_at_root0 = "/file0"; + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0/"; // existing + const bfs::path dst_subdir1 = "/output_dir0"; // existing but does not look as a directory + const bfs::path dst_subdir2 = "/output_dir0/a/b/c/d/"; // existing + const bfs::path dst_subdir3 = "/output_dir0/a/b/c/d"; // existing but does not look as a directory + const bfs::path dst_subdir4 = "/output_dir1/"; // non-existing + const bfs::path dst_subdir5 = "/output_dir1/a/b/c/d/"; // non-existing + + // create required output directories + env.add_to_namespace(nsid0, dst_subdir0); + env.add_to_namespace(nsid0, dst_subdir2); + + // + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH file " + "located at DST's namespace root '/'") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Output file contains buffer data") { + + bfs::path dst = + env.get_from_namespace( + nsid0, dst_file_at_root0); + + REQUIRE(compare(input_data, dst) == true); + } + } + } + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH file " + "located at a DST's subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Output file contains buffer data") { + + bfs::path dst = + env.get_from_namespace( + nsid0, dst_file_at_subdir0); + + REQUIRE(compare(input_data, dst) == true); + } + } + } + } + } + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ECONNFAILED is returned") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + + +/******************************************************************************/ +/* tests for push transfers (memory buffers, errors) */ +/******************************************************************************/ +SCENARIO("errors copying local memory region to remote POSIX file (admin)", + "[api::nornsctl_submit_push_memory_to_posix_file_errors]") { + + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env; + + const char* nsid0 = "tmp0"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path dst_mnt; + + // create namespaces + std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); + + // create input data buffer (around 40MiBs) + std::vector input_data(10000000, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + // output names + const bfs::path dst_file_at_root0 = "/file0"; + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0/"; // existing + const bfs::path dst_subdir1 = "/output_dir0"; // existing but does not look as a directory + const bfs::path dst_subdir2 = "/output_dir0/a/b/c/d/"; // existing + const bfs::path dst_subdir3 = "/output_dir0/a/b/c/d"; // existing but does not look as a directory + const bfs::path dst_subdir4 = "/output_dir1/"; // non-existing + const bfs::path dst_subdir5 = "/output_dir1/a/b/c/d/"; // non-existing + + // create required output directories + env.add_to_namespace(nsid0, dst_subdir0); + env.add_to_namespace(nsid0, dst_subdir2); + + //TODO + // - copy a valid but removed memory region (cannot control => undefined behavior) + // - providing a non-existing directory path (i.e. finished with /) as output name + // - providing an existing path that points to a directory as output name + WHEN("copying an invalid memory region to a NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION((void*) 0x42, 42000), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EFAULT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EFAULT); + } + } + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH at " + "DST's /") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH existing " + "directory at DST's /") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH existing " + "directory at / that does not look like a directory") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EISDIR); + } + } + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH existing " + "directory at a DST's arbitary subdir") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir2.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH existing " + "directory at a DST's arbitary subdir that does not look like " + "a directory") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir3.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == EISDIR); + } + } + } + } + + + // i.e. a destination path that 'looks like' a directory + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH " + "corresponding to a non-existing directory at DST's /") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir4.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + WHEN("copying a valid memory region to a NORNS_REMOTE_PATH " + "non-existing arbitrary subdir at DST") { + + // create input data buffer + std::vector input_data(100, 42); + void* region_addr = input_data.data(); + size_t region_size = input_data.size() * sizeof(int); + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(region_addr, region_size), + NORNS_REMOTE_PATH(nsid0, + remote_host, + dst_subdir5.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_EBADARGS") { + REQUIRE(rv == NORNS_EBADARGS); + } + } + + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ECONNFAILED is returned") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + +/******************************************************************************/ +/* tests for push transfers (links) */ +/******************************************************************************/ +SCENARIO("copy local POSIX path to remote POSIX path involving links (admin)", + "[api::nornsctl_submit_push_links]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + WHEN("copying a single NORNS_LOCAL_PATH file from SRC namespace's '/' " + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH subdir from SRC " + "namespace's '/' through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH file from SRC namespace's '/' " + "through a symlink located in a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH subdir from SRC " + "namespace's '/' through a symlink also located at subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink also located at a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for pull transfers (errors) */ +/******************************************************************************/ +SCENARIO("errors copying remote POSIX path to local POSIX path (admin)", + "[api::nornsctl_submit_pull_errors]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + // - trying to copy a non-existing file + WHEN("copying a non-existing NORNS_LOCAL_PATH file") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_invalid_file.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy a non-existing directory + WHEN("copying a non-existing NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_invalid_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + // - trying to copy an empty directory + WHEN("copying an empty NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_empty_dir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_SUCCESS and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + REQUIRE(stats.st_task_error == NORNS_SUCCESS); + REQUIRE(stats.st_sys_errno == 0); + + REQUIRE(bfs::exists(dst_mnt / dst_file_at_root0)); + } + } + } + } + +//FIXME: DISABLED in CI until impersonation is implemented or capabilities can be added to the docker service +#ifdef __SETCAP_TESTS__ + +#if 0 // not adapted to pull semantics + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { + + norns_op_t task_op = NORNS_IOTASK_COPY; + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir " + "without appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL " + "are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // symlink leading out of namespace + WHEN("copying a NORNS_LOCAL_PATH through a symbolic link that leads " + "out of the SRC namespace") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + out_symlink.c_str()), + NORNS_REMOTE_PATH(nsid1, + remote_host, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } +#endif +#endif + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for pull transfers (single files) */ +/******************************************************************************/ +SCENARIO("copy remote POSIX file to local POSIX file (admin)", + "[api::nornsctl_submit_pull_to_posix_file]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + // cp -r ns0://file0.txt + // -> ns1:// = ns1://file0.txt + WHEN("copying a single NORNS_REMOTE_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at DST namespace's root " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at DST namespace's root " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt + // -> ns1://file0.txt = ns1://file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at DST namespace's root (keeping " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../d/file0.txt + // -> ns1://file1.txt = ns1://file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at DST namespace's root (changing " + "the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_root1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace(nsid0, + src_file_at_root); + bfs::path dst = + env.get_from_namespace(nsid1, + dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://file0.txt + // -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from SRC namespace's root to " + "another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_root.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_root); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://a/b/c/.../file0.txt = ns1://a/b/c/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(keeping the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://a/b/c/.../file1.txt = ns1://a/b/c/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir1); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://e/f/g/.../file0.txt = ns1://e/f/g/.../file0.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the parents names)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir2.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir2); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + // cp -r ns0://a/b/c/.../file0.txt + // -> ns1://e/f/g/.../file1.txt = ns1://e/f/g/.../file1.txt + WHEN("copying a single NORNS_LOCAL_PATH from a SRC namespace's subdir " + "to another NORNS_LOCAL_PATH at a DST namespace's subdir " + "(changing the name)") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_file_at_subdir.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_subdir3.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + bfs::path src = + env.get_from_namespace( + nsid0, src_file_at_subdir); + bfs::path dst = + env.get_from_namespace( + nsid1, dst_file_at_subdir3); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } +} + +/******************************************************************************/ +/* tests for pull transfers (directories) */ +/******************************************************************************/ +SCENARIO("copy remote POSIX subdir to local POSIX subdir (admin)", + "[api::nornsctl_submit_pull_to_posix_subdir]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + // cp -r /a/contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_REMOTE_PATH subdir from SRC " + "namespace's root to a NORNS_LOCAL_PATH at DST namespace's root\n" + " cp -r /a/contents.* -> / = /contents.* ") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied subdirs are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> / = /contents.* + WHEN("copying the contents of a NORNS_REMOTE_PATH arbitrary subdir to " + "a NORNS_LOCAL_PATH at DST namespace's root\n" + " cp -r /a/b/c/.../contents.* -> / = /contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_root.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied subdirs are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_root); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_REMOTE_PATH subdir from SRC " + "namespace's root to another NORNS_LOCAL_PATH subdir at DST " + "namespace's root while changing its name\n" + " cp -r /a/contents.* -> /c = /c/contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied subdirs are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/contents.* -> /c = /c/contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_REMOTE_PATH subdir from SRC " + "namespace's root to another NORNS_LOCAL_PATH subdir at DST " + "namespace's root while changing its name\n" + " cp -r /a/contents.* -> /c / /c/contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did not exist previously) + WHEN("copying the contents of a NORNS_REMOTE_PATH subdir from SRC " + "namespace's root to a NORNS_LOCAL_PATH subdir at DST " + "namespace's root while changing its name\n" + "cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_subdir0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + // cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.* + // (c did exist previously) + WHEN("copying the contents of a NORNS_REMOTE_PATH subdir from SRC " + "namespace's root to another NORNS_LOCAL_PATH subdir at DST " + "namespace's root while changing its name:" + " cp -r /a/b/c/.../contents.* -> /c = /c/a/b/c/.../contents.*") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_subdir1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Copied files are identical to original") { + bfs::path src = + env.get_from_namespace(nsid0, src_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_subdir1); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ECONNFAILED") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + +/******************************************************************************/ +/* tests for pull transfers (links) */ +/******************************************************************************/ +SCENARIO("copy remote POSIX path to local POSIX path involving links (admin)", + "[api::nornsctl_submit_pull_links]") { + GIVEN("a running urd instance") { + + /**********************************************************************/ + /* setup common environment */ + /**********************************************************************/ + test_env env(false); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* remote_host = "127.0.0.1:42000"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 40000); + env.add_to_namespace(nsid0, src_file_at_subdir, 80000); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* begin tests */ + /**********************************************************************/ + WHEN("copying a single NORNS_REMOTE_PATH file from SRC namespace's '/' " + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_root0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_REMOTE_PATH subdir from SRC " + "namespace's '/' through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_root1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_REMOTE_PATH arbitrary subdir" + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_root2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, src_symlink_at_root2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_REMOTE_PATH file from SRC namespace's '/' " + "through a symlink located in a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Files are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir0); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_files(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_REMOTE_PATH subdir from SRC " + "namespace's '/' through a symlink also located at subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir1); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + WHEN("copying a single NORNS_REMOTE_PATH arbitrary subdir" + "through a symlink also located at a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + remote_host, + src_symlink_at_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_EFINISHED") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHED); + + THEN("Directories are equal") { + + bfs::path src = + env.get_from_namespace(nsid0, + src_symlink_at_subdir2); + bfs::path dst = + env.get_from_namespace(nsid1, dst_file_at_root0); + + REQUIRE(compare_directories(src, dst) == true); + } + } + } + } + } + + env.notify_success(); + } +} diff --git a/tests/api-ctl-remove-local-data.cpp b/tests/api-ctl-remove-local-data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73fdf06695aa02ea2e4a114f1a878bfdd20b16bf --- /dev/null +++ b/tests/api-ctl-remove-local-data.cpp @@ -0,0 +1,774 @@ +/************************************************************************* + * Copyright (C) 2017-2018 Barcelona Supercomputing Center * + * Centro Nacional de Supercomputacion * + * All rights reserved. * + * * + * This file is part of the NORNS Data Scheduler, a service that allows * + * other programs to start, track and manage asynchronous transfers of * + * data resources transfers requests between different storage backends. * + * * + * See AUTHORS file in the top level directory for information * + * regarding developers and contributors. * + * * + * The NORNS Data Scheduler is free software: you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation, either * + * version 3 of the License, or (at your option) any later version. * + * * + * The NORNS Data Scheduler is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General * + * Public License along with the NORNS Data Scheduler. If not, see * + * . * + *************************************************************************/ + +#include "nornsctl.h" +#include "test-env.hpp" +#include "compare-files.hpp" +#include "catch.hpp" + +namespace bfs = boost::filesystem; + +SCENARIO("remove a local POSIX file (admin)", + "[api::nornsctl_submit_remove_local_posix_files]") { + GIVEN("a running urd instance") { + + test_env env; + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + const bfs::path src_file_at_root = "/file0"; + const bfs::path src_file_at_subdir = "/a/b/c/d/file0"; + const bfs::path src_invalid_file = "/a/b/c/d/does_not_exist_file0"; + const bfs::path src_invalid_dir = "/a/b/c/d/does_not_exist_dir0"; + const bfs::path src_subdir0 = "/input_dir0"; + const bfs::path src_subdir1 = "/input_dir0/a/b/c/input_dir1"; + const bfs::path src_empty_dir = "/empty_dir0"; + + const bfs::path src_noperms_file0 = "/noperms_file0"; + const bfs::path src_noperms_file1 = "/noperms/a/b/c/d/noperms_file0"; // parents accessible + const bfs::path src_noperms_file2 = "/noperms/noperms_subdir0/file0"; // parents non-accessible + const bfs::path src_noperms_subdir0 = "/noperms_subdir0"; // subdir non-accessible + const bfs::path src_noperms_subdir1 = "/noperms/a/b/c/d/noperms_subdir1"; // child subdir non-accessible + const bfs::path src_noperms_subdir2 = "/noperms/noperms_subdir2/a"; // parent subdir non-accessible + + const bfs::path src_symlink_at_root0 = "/symlink0"; + const bfs::path src_symlink_at_root1 = "/symlink1"; + const bfs::path src_symlink_at_root2 = "/symlink2"; + const bfs::path src_symlink_at_subdir0 = "/foo/bar/baz/symlink0"; + const bfs::path src_symlink_at_subdir1 = "/foo/bar/baz/symlink1"; + const bfs::path src_symlink_at_subdir2 = "/foo/bar/baz/symlink2"; + + const bfs::path dst_root = "/"; + const bfs::path dst_subdir0 = "/output_dir0"; + const bfs::path dst_subdir1 = "/output_dir1"; + const bfs::path dst_file_at_root0 = "/file0"; // same basename + const bfs::path dst_file_at_root1 = "/file1"; // different basename + const bfs::path dst_file_at_subdir0 = "/a/b/c/d/file0"; // same fullname + const bfs::path dst_file_at_subdir1 = "/a/b/c/d/file1"; // same parents, different basename + const bfs::path dst_file_at_subdir2 = "/e/f/g/h/i/file0"; // different parents, same basename + const bfs::path dst_file_at_subdir3 = "/e/f/g/h/i/file1"; // different fullname + + // create input data + env.add_to_namespace(nsid0, src_file_at_root, 4096); + env.add_to_namespace(nsid0, src_file_at_subdir, 8192); + env.add_to_namespace(nsid0, src_subdir0); + env.add_to_namespace(nsid0, src_subdir1); + env.add_to_namespace(nsid0, src_empty_dir); + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir0 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + for(int i=0; i<10; ++i) { + const bfs::path p{src_subdir1 / ("file" + std::to_string(i))}; + env.add_to_namespace(nsid0, p, 4096+i*10); + } + + // create input data with special permissions + auto p = env.add_to_namespace(nsid0, src_noperms_file0, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file1, 0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_file2, 0); + env.remove_access(p.parent_path()); + + p = env.add_to_namespace(nsid0, src_noperms_subdir0); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir1); + env.remove_access(p); + + p = env.add_to_namespace(nsid0, src_noperms_subdir2); + env.remove_access(p.parent_path()); + + // add symlinks to the namespace + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_root0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_root1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_root2); + + env.add_to_namespace(nsid0, src_file_at_root, src_symlink_at_subdir0); + env.add_to_namespace(nsid0, src_subdir0, src_symlink_at_subdir1); + env.add_to_namespace(nsid0, src_subdir1, src_symlink_at_subdir2); + + // manually create a symlink leading outside namespace 0 + boost::system::error_code ec; + const bfs::path out_symlink = "/out_symlink"; + bfs::create_symlink(dst_mnt, src_mnt / out_symlink, ec); + REQUIRE(!ec); + + + // create required output directories + env.add_to_namespace(nsid1, dst_subdir1); + + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ + // - trying to remove a non-existing file + WHEN("removing a non-existing NORNS_LOCAL_PATH file") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + + + // - trying to remove a non-existing directory + WHEN("removing a non-existing NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(stats.st_sys_errno == ENOENT); + } + } + } + } + +//FIXME: DISABLED in CI until impersonation is implemented or capabilities can be added to the docker service +#ifdef __SETCAP_TESTS__ + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a file from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access it") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } + + // - trying to copy a subdir from namespace root with invalid access permissions + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("nornsctl_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); + REQUIRE(stats.st_task_error == NORNS_ESYSTEMERROR); + REQUIRE(( (stats.st_sys_errno == EACCES) || + (stats.st_sys_errno == EPERM ) || + (stats.st_sys_errno == EINVAL) )); + } + } + } + } +#endif + + /**********************************************************************/ + /* tests for single files */ + /**********************************************************************/ + // rm ns0://file0.txt + WHEN("removing a single NORNS_LOCAL_PATH from src namespace's root") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str())); + const bfs::path p = env.get_from_namespace(nsid0, src_file_at_root); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("File no longer exists") { + REQUIRE(!bfs::exists(p)); + } + } + } + } + + // rm ns0://a/b/c/.../d/file0.txt + WHEN("removing a single NORNS_LOCAL_PATH from a src namespace's " + "subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, src_file_at_subdir); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("File no longer exists") { + REQUIRE(!bfs::exists(p)); + } + } + } + } + + /**********************************************************************/ + /* tests for directories */ + /**********************************************************************/ + // rm -r /a/contents.* + WHEN("removing the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str())); + const bfs::path p = env.get_from_namespace(nsid0, src_subdir0); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directory no longer exists") { + REQUIRE(!bfs::exists(p)); + } + } + } + } + + // rm -r /a/b/c/.../contents.* + WHEN("removing the contents of a NORNS_LOCAL_PATH arbitrary subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str())); + const bfs::path p = env.get_from_namespace(nsid0, src_subdir1); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directory no longer exists") { + REQUIRE(!bfs::exists(p)); + } + } + } + } + + WHEN("removing an empty NORNS_LOCAL_PATH directory") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str())); + const bfs::path p = env.get_from_namespace(nsid0, src_empty_dir); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("Directory no longer exists") { + REQUIRE(!bfs::exists(p)); + } + } + } + } + + + /**********************************************************************/ + /* tests for soft links */ + /**********************************************************************/ + WHEN("removing a single NORNS_LOCAL_PATH file from src namespace's '/' " + "through a symlink also located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root0.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_root0; + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("symlink no longer exists and original file is left " + "intact") { + REQUIRE(!bfs::exists(p)); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_file_at_root))); + } + } + } + } + + WHEN("removing a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink located at '/'" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root2.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_root2; + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("symlink no longer exists and original file is left " + "intact") { + REQUIRE(!bfs::exists(p)); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_subdir1))); + } + } + } + } + + WHEN("removing a single NORNS_LOCAL_PATH file from src namespace's '/' " + "through a symlink located in a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir0.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir0; + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("symlink no longer exists and original file is left " + "intact") { + REQUIRE(!bfs::exists(p)); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_file_at_root))); + } + } + } + } + + WHEN("removing a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at subdir") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir1.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir1; + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("symlink no longer exists and original file is left " + "intact") { + REQUIRE(!bfs::exists(p)); + REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_subdir0))); + } + } + } + } + + WHEN("removing a single NORNS_LOCAL_PATH arbitrary subdir" + "through a symlink also located at a subdir" ) { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir2.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir2; + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + // wait until the task completes + rv = nornsctl_wait(&task); + + THEN("nornsctl_wait() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + + THEN("symlink no longer exists and original file is left " + "intact") { + REQUIRE(!bfs::exists(p)); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_subdir1))); + } + } + } + } + + env.notify_success(); + } + + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ECONNFAILED is returned") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + diff --git a/tests/api-ctl-task-init.cpp b/tests/api-ctl-task-init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a1bbb6f839c55fade684b360ef38db196a283ad --- /dev/null +++ b/tests/api-ctl-task-init.cpp @@ -0,0 +1,224 @@ +/************************************************************************* + * Copyright (C) 2017-2018 Barcelona Supercomputing Center * + * Centro Nacional de Supercomputacion * + * All rights reserved. * + * * + * This file is part of the NORNS Data Scheduler, a service that allows * + * other programs to start, track and manage asynchronous transfers of * + * data resources transfers requests between different storage backends. * + * * + * See AUTHORS file in the top level directory for information * + * regarding developers and contributors. * + * * + * The NORNS Data Scheduler is free software: you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation, either * + * version 3 of the License, or (at your option) any later version. * + * * + * The NORNS Data Scheduler is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General * + * Public License along with the NORNS Data Scheduler. If not, see * + * . * + *************************************************************************/ + +#include +#include "nornsctl.h" +#include "catch.hpp" + +SCENARIO("initialize a task with nornsctl_iotask_init", + "[api::nornsctl_iotask_init]") { + + GIVEN("invalid task information") { + WHEN("initializing a task with NULL src and dst") { + + norns_iotask_t task; + norns_op_t task_op = NORNS_IOTASK_COPY; + + nornsctl_iotask_init(&task, task_op, NULL, NULL); + + AND_THEN("task is set to 0") { + norns_iotask_t dummy; + memset(&dummy, 0, sizeof(dummy)); + REQUIRE(memcmp(&task, &dummy, sizeof(norns_iotask_t)) == 0); + } + } + } + + GIVEN("invalid task information") { + WHEN("initializing a task with a NULL src") { + + norns_iotask_t task; + norns_op_t task_op = NORNS_IOTASK_COPY; + + const char* dst_nsid = "tmp://"; + const char* dst_path = "/a/b/c"; + norns_resource_t dst = NORNS_LOCAL_PATH(dst_nsid, dst_path); + + nornsctl_iotask_init(&task, task_op, NULL, &dst); + + THEN("task is set to 0") { + norns_iotask_t dummy; + memset(&dummy, 0, sizeof(dummy)); + REQUIRE(memcmp(&task, &dummy, sizeof(norns_iotask_t)) == 0); + } + } + } + + GIVEN("valid task information") { + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_POSIX_PATH | R_LOCAL") { + + norns_op_t task_op = NORNS_IOTASK_COPY; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + const char* dst_nsid = "tmp://"; + const char* dst_path = "/a/b/c"; + + norns_resource_t src = NORNS_MEMORY_REGION(src_addr, src_size); + + REQUIRE(src.r_buffer.b_addr == src_addr); + REQUIRE(src.r_buffer.b_size == src_size); + + norns_resource_t dst = NORNS_LOCAL_PATH(dst_nsid, dst_path); + + REQUIRE(strcmp(dst.r_posix_path.p_nsid, dst_nsid) == 0); + REQUIRE(dst.r_posix_path.p_host == NULL); + REQUIRE(strcmp(dst.r_posix_path.p_path, dst_path) == 0); + + norns_iotask_t task; + nornsctl_iotask_init(&task, task_op, &src, &dst); + + THEN("the norns_task structure is initialized as expected") { + REQUIRE(task.t_id == 0); + REQUIRE(task.t_op == task_op); + REQUIRE(memcmp(&task.t_src, &src, + sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_dst, &dst, + sizeof(norns_resource_t)) == 0); + } + } + } + + GIVEN("valid task information") { + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_POSIX_PATH | R_REMOTE") { + + norns_op_t task_op = NORNS_IOTASK_COPY; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + const char* dst_nsid = "tmp://"; + const char* dst_host = "node0"; + const char* dst_path = "/a/b/c"; + + norns_resource_t src = NORNS_MEMORY_REGION(src_addr, src_size); + + REQUIRE(src.r_buffer.b_addr == src_addr); + REQUIRE(src.r_buffer.b_size == src_size); + + norns_resource_t dst = NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path); + + REQUIRE(strcmp(dst.r_posix_path.p_nsid, dst_nsid) == 0); + REQUIRE(strcmp(dst.r_posix_path.p_host, dst_host) == 0); + REQUIRE(strcmp(dst.r_posix_path.p_path, dst_path) == 0); + + norns_iotask_t task; + nornsctl_iotask_init(&task, task_op, &src, &dst); + + THEN("the norns_task structure is initialized as expected") { + REQUIRE(task.t_id == 0); + REQUIRE(task.t_op == task_op); + REQUIRE(memcmp(&task.t_src, &src, + sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_dst, &dst, + sizeof(norns_resource_t)) == 0); + } + } + } +} + +SCENARIO("initialize a task with NORNSCTL_IOTASK", "[api::NORNSCTL_IOTASK]") { + + GIVEN("valid task information") { + WHEN("initializing a task with src=NORNS_MEMORY_REGION and " + "dst=NORNS_LOCAL_PATH") { + + norns_op_t task_op = NORNS_IOTASK_COPY; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + const char* dst_nsid = "tmp://"; + const char* dst_path = "/a/b/c"; + + norns_iotask_t task = + NORNSCTL_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + THEN("the norns_task structure is initialized as expected") { + REQUIRE(task.t_id == 0); + REQUIRE(task.t_op == task_op); + + REQUIRE(task.t_src.r_buffer.b_addr == src_addr); + + REQUIRE(strcmp(task.t_dst.r_posix_path.p_nsid, dst_nsid) == 0); + REQUIRE(strcmp(task.t_dst.r_posix_path.p_path, dst_path) == 0); + } + } + + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_REMOTE_PATH") { + norns_op_t task_op = NORNS_IOTASK_COPY; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + const char* dst_nsid = "tmp://"; + const char* dst_host = "node0"; + const char* dst_path = "/a/b/c"; + + norns_iotask_t task = + NORNSCTL_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + THEN("the norns_task structure is initialized as expected") { + REQUIRE(task.t_id == 0); + REQUIRE(task.t_op == task_op); + + REQUIRE(task.t_src.r_buffer.b_addr == src_addr); + + REQUIRE(strcmp(task.t_dst.r_posix_path.p_nsid, dst_nsid) == 0); + REQUIRE(strcmp(task.t_dst.r_posix_path.p_host, dst_host) == 0); + REQUIRE(strcmp(task.t_dst.r_posix_path.p_path, dst_path) == 0); + } + + } + + WHEN("initializing a task with src=NORNS_MEMORY_REGION and " + "dst=NORNS_LOCAL_PATH") { + + norns_op_t task_op = NORNS_IOTASK_COPY; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + const char* dst_nsid = "tmp://"; + const char* dst_path = "/a/b/c"; + + norns_iotask_t task = + NORNSCTL_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + THEN("the norns_task structure is initialized as expected") { + REQUIRE(task.t_id == 0); + REQUIRE(task.t_op == task_op); + + REQUIRE(task.t_src.r_buffer.b_addr == src_addr); + + REQUIRE(strcmp(task.t_dst.r_posix_path.p_nsid, dst_nsid) == 0); + REQUIRE(strcmp(task.t_dst.r_posix_path.p_path, dst_path) == 0); + } + } + } +} + diff --git a/tests/api-ctl-task-status.cpp b/tests/api-ctl-task-status.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7dcfe3d17bccf214f82c5e7b64fcca123549a73a --- /dev/null +++ b/tests/api-ctl-task-status.cpp @@ -0,0 +1,1136 @@ +/************************************************************************* + * Copyright (C) 2017-2018 Barcelona Supercomputing Center * + * Centro Nacional de Supercomputacion * + * All rights reserved. * + * * + * This file is part of the NORNS Data Scheduler, a service that allows * + * other programs to start, track and manage asynchronous transfers of * + * data resources transfers requests between different storage backends. * + * * + * See AUTHORS file in the top level directory for information * + * regarding developers and contributors. * + * * + * The NORNS Data Scheduler is free software: you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation, either * + * version 3 of the License, or (at your option) any later version. * + * * + * The NORNS Data Scheduler is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General * + * Public License along with the NORNS Data Scheduler. If not, see * + * . * + *************************************************************************/ + + +#include "nornsctl.h" +#include "test-env.hpp" +#include "catch.hpp" + +SCENARIO("check control request", "[api::nornsctl_error]") { + GIVEN("a running urd instance") { + + test_env env( + fake_daemon_cfg { + true /* dry_run? */ + } + ); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + std::vector input_data(100, 42); + void* src_buf = input_data.data(); + size_t src_buf_size = input_data.size() * sizeof(int); + const bfs::path src_file = "/a/b/c/file"; + size_t src_file_size = 4096; + + // define output names + const bfs::path dst_file = "/b/c/d/file"; + + // create input data + env.add_to_namespace(nsid0, "/a/b/c/file", 4096); + + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ + + WHEN("checking the status of an active request") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_buf, src_buf_size), + NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + THEN("NORNS_SUCCESS is returned and task status is valid") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE((stats.st_status == NORNS_EPENDING || + stats.st_status == NORNS_EINPROGRESS || + stats.st_status == NORNS_EFINISHED)); + } + } + } + + WHEN("checking the status of an active request") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + +retry: + norns_stat_t stats; + rv = nornsctl_error(&task, &stats); + + THEN("NORNS_SUCCESS is returned and task status is valid") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE((stats.st_status == NORNS_EPENDING || + stats.st_status == NORNS_EINPROGRESS || + stats.st_status == NORNS_EFINISHED)); + } + + if(stats.st_status != NORNS_EFINISHED) + goto retry; + } + } + + env.notify_success(); +/* + WHEN("submitting a request to copy data using unregistered backends") { + + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_path = "/a/b/c"; + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ENOSUCHBACKEND is returned") { + REQUIRE(rv == NORNS_ENOSUCHBACKEND); + } + } + + WHEN("submitting a request to copy data using an unregistered src backend") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "lustre://"; + const char* dst_mnt = "/mnt/lustre0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t ns = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 1024); + + norns_error_t rv = nornsctl_register_namespace(&b); + + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOSUCHBACKEND is returned") { + REQUIRE(rv == NORNS_ENOSUCHBACKEND); + } + + rv = nornsctl_unregister_namespace(dst_nsid); + + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to copy data using an unregistered dst backend") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "lustre://"; + const char* dst_mnt = "/mnt/lustre0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t ns = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 1024); + norns_error_t rv = nornsctl_register_namespace(&b); + + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOSUCHBACKEND is returned") { + REQUIRE(rv == NORNS_ENOSUCHBACKEND); + } + + rv = nornsctl_unregister_namespace(src_nsid); + + REQUIRE(rv == NORNS_SUCCESS); + } +*/ + + +#if 0 + /**************************************************************************************************************/ + /* tests for NORNS_IOTASK_COPY */ + /**************************************************************************************************************/ + /* copy from process memory to .* */ + WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_LOCAL_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_POSIX_FILESYSTEM, dst_mnt, 8192); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_SHARED_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_REMOTE_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_host = "node0"; + const char* dst_path = "/a/b/c"; + + /* + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + */ + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* copy from local path to .* */ + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_LOCAL_PATH") { + + const char* src_nsid = "tmp0://"; + const char* src_mnt = "/mnt/tmp0"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "tmp1://"; + const char* dst_mnt = "/mnt/tmp1"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_POSIX_FILESYSTEM, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_SHARED_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "lustre://"; + const char* dst_mnt = "/mnt/lustre"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_REMOTE_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_host = "node1"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + /* + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_NVML, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + */ + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_LOCAL_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_path = "/b/c/d"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_NVML, dst_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_SHARED_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_path = "/b/c/d"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_REMOTE_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_host = "node1"; + const char* dst_path = "/b/c/d"; + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_SHARED_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "lustre://"; + const char* src_mnt = "/mnt/lustre"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_LUSTRE, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_SHARED_PATH(src_nsid, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + + /**************************************************************************************************************/ + /* tests for NORNS_IOTASK_MOVE */ + /**************************************************************************************************************/ + /* move from process memory to .* */ + WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_LOCAL_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_POSIX_FILESYSTEM, dst_mnt, 8192); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_SHARED_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp0"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_REMOTE_PATH") { + + const char* src_nsid = "mem://"; + void* src_addr = (void*) 0xdeadbeef; + size_t src_size = (size_t) 42; + + const char* dst_nsid = "tmp://"; + const char* dst_host = "node0"; + const char* dst_path = "/a/b/c"; + + /* + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + */ + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* move from local path to .* */ + WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_LOCAL_PATH") { + + const char* src_nsid = "tmp0://"; + const char* src_mnt = "/mnt/tmp0"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "tmp1://"; + const char* dst_mnt = "/mnt/tmp1"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_POSIX_FILESYSTEM, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_SHARED_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "lustre://"; + const char* dst_mnt = "/mnt/lustre"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_REMOTE_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/b/c/d"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_host = "node1"; + const char* dst_path = "/a/b/c"; + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + /* + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_NVML, dst_mnt, 8192); + rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + */ + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_SUCCESS is returned") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_LOCAL_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_path = "/b/c/d"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_NVML, dst_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_SHARED_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_mnt = "/mnt/tmp"; + const char* dst_path = "/b/c/d"; + + nornsctl_backend_t bdst = NORNSCTL_BACKEND(dst_nsid, NORNS_BACKEND_LUSTRE, dst_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bdst); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_SHARED_PATH(dst_nsid, dst_path)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_REMOTE_PATH") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "tmp://"; + const char* dst_host = "node1"; + const char* dst_path = "/b/c/d"; + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "tmp://"; + const char* src_mnt = "/mnt/tmp"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_NVML, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(src_nsid, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_SHARED_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "lustre://"; + const char* src_mnt = "/mnt/lustre"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + + nornsctl_backend_t bsrc = NORNSCTL_BACKEND(src_nsid, NORNS_BACKEND_LUSTRE, src_mnt, 16384); + norns_error_t rv = nornsctl_register_namespace(&bsrc); + REQUIRE(rv == NORNS_SUCCESS); + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_SHARED_PATH(src_nsid, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + // cleanup + rv = nornsctl_unregister_namespace(src_nsid); + REQUIRE(rv == NORNS_SUCCESS); + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_PROCESS_MEMORY") { + + const char* src_nsid = "tmp://"; + const char* src_host = "node0"; + const char* src_path = "/a/b/c"; + + const char* dst_nsid = "mem://"; + void* dst_addr = (void*) 0xdeadbeef; + size_t dst_size = (size_t) 42; + + norns_iotask_t task = NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(src_nsid, src_host, src_path), + NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); + + rv = nornsctl_submit(&task); + + THEN("NORNS_ENOTSUPPORTED is returned") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + + rv = nornsctl_unregister_namespace(dst_nsid); + REQUIRE(rv == NORNS_SUCCESS); + } +#endif + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = + NORNSCTL_IOTASK( + NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", "node1", "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("NORNS_ECONNFAILED is returned") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} + + +SCENARIO("check requests", "[api::nornsctl_status]") { + GIVEN("a running urd instance") { + + test_env env( + fake_daemon_cfg { + true /* dry_run? */ + } + ); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + bfs::path src_mnt, dst_mnt; + + // create namespaces + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + + // define input names + void* src_buf; + size_t src_buf_size __attribute__((unused)); + const bfs::path src_file = "/a/b/c/file"; + size_t src_file_size = 4096; + + // define output names + const bfs::path dst_file = "/b/c/d/file"; + + // create input data + env.add_to_namespace(nsid0, src_file, 4096); + + // 64MiB buffer + std::vector input_data(16*1024*1024, 42); + src_buf = input_data.data(); + src_buf_size = input_data.size() * sizeof(int); + + WHEN("checking the status of all requests without actual requests running") { + nornsctl_stat_t global_stats; + norns_error_t rv = nornsctl_status(&global_stats); + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(global_stats.st_pending_tasks == 0); + REQUIRE(global_stats.st_running_tasks == 0); + REQUIRE(global_stats.st_eta == 0.0); + } + + WHEN("checking the status of all requests") { + + const size_t ntasks = 10; + norns_iotask_t tasks[ntasks]; + size_t sizes[] = + { 4*1024*1024, 16*1024*1024, 32*1024*1024, 64*1024*1024 }; + + for(size_t i=0; i. * + *************************************************************************/ + +#include "norns.h" +#include "test-env.hpp" +#include "catch.hpp" + +SCENARIO("submit control request", "[api::nornsctl_submit]") { + GIVEN("a running urd instance") { + + test_env env( + fake_daemon_cfg { + true /* dry_run? */ + } + ); + + const char* nsid0 = "tmp0"; + const char* nsid1 = "tmp1"; + const char* nsid3 = "lustre0"; + bfs::path tmp0_mnt, tmp1_mnt, lustre_mnt; + + // create namespaces + std::tie(std::ignore, tmp0_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, tmp1_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); + std::tie(std::ignore, lustre_mnt) = + env.create_namespace(nsid3, "mnt/lustre0", 16384); + + // define input names + const char* src_host0 = "node0"; + const bfs::path src_file0 = "/a/b/c"; + const bfs::path src_file1 = "/b/c/d"; + void* src_mem_addr = (void*) 0xdeadbeef; + const size_t src_mem_size = (size_t) 42; + + // define output names + const char* dst_host0 = "node0"; + const bfs::path dst_file0 = "/a/b/c"; + const bfs::path dst_file1 = "/b/c/d"; + void* dst_mem_addr = (void*) 0xdeadbeef; + const size_t dst_mem_size = (size_t) 42; + + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ + WHEN("submitting a request to copy data using unregistered " + "namespaces") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_LOCAL_PATH("tmp2", dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOSUCHNAMESPACE") { + REQUIRE(rv == NORNS_ENOSUCHNAMESPACE); + } + } + + WHEN("submitting a request to copy data using an unregistered src " + "namespace") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("tmp2", src_file0.c_str()), + NORNS_SHARED_PATH(nsid3, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOSUCHNAMESPACE") { + REQUIRE(rv == NORNS_ENOSUCHNAMESPACE); + } + } + + WHEN("submitting a request to copy data using an unregistered dst " + "namespace") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file0.c_str()), + NORNS_SHARED_PATH("tmp2", dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOSUCHNAMESPACE") { + REQUIRE(rv == NORNS_ENOSUCHNAMESPACE); + } + } + + + /**********************************************************************/ + /* tests for NORNS_IOTASK_COPY */ + /**********************************************************************/ + /* copy from process memory to .* */ + WHEN("submitting a request to copy from NORNS_MEMORY_REGION to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_LOCAL_PATH(nsid0, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to copy from NORNS_MEMORY_REGION to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_SHARED_PATH(nsid0, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to copy from a NORNS_MEMORY_REGION to " + "a NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_REMOTE_PATH(nsid0, + dst_host0, + dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + } + } + + /* copy from local path to .* */ + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_SHARED_PATH(nsid3, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to " + "NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_REMOTE_PATH(nsid1, + dst_host0, + dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() return NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_SHARED_PATH(nsid1, dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to " + "NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_REMOTE_PATH(nsid1, + dst_host0, + dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_LOCAL_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, + dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_SHARED_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_SHARED_PATH(nsid3, src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, + dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to copy from NORNS_REMOTE_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, + dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + + /**********************************************************************/ + /* tests for NORNS_IOTASK_MOVE */ + /**********************************************************************/ + /* move from process memory to .* */ + WHEN("submitting a request to move from NORNS_MEMORY_REGION to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_LOCAL_PATH(nsid1, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to move from NORNS_MEMORY_REGION to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_SHARED_PATH(nsid1, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to move from NORNS_MEMORY_REGION to " + "NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_MEMORY_REGION(src_mem_addr, src_mem_size), + NORNS_REMOTE_PATH(nsid1, + dst_host0, + dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + } + } + + /* move from local path to .* */ + WHEN("submitting a request to move from NORNS_LOCAL_PATH to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to move from NORNS_LOCAL_PATH to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_SHARED_PATH(nsid3, dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + WHEN("submitting a request to move from NORNS_LOCAL_PATH to " + "NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(nsid0, src_file1.c_str()), + NORNS_REMOTE_PATH(nsid1, + dst_host0, + dst_file0.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + REQUIRE(task.t_id != 0); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to " + "NORNS_LOCAL_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_SUCCESS") { + REQUIRE(rv == NORNS_SUCCESS); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to " + "NORNS_SHARED_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_SHARED_PATH(nsid1, dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using a remote node as source is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to " + "NORNS_REMOTE_PATH") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_REMOTE_PATH(nsid1, + dst_host0, + dst_file1.c_str())); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_LOCAL_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_LOCAL_PATH(nsid0, src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, + dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_SHARED_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_SHARED_PATH(nsid3, src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + /* using the process memory as destination is not allowed (yet) */ + WHEN("submitting a request to move from NORNS_REMOTE_PATH to " + "NORNS_MEMORY_REGION") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_MOVE, + NORNS_REMOTE_PATH(nsid0, + src_host0, + src_file0.c_str()), + NORNS_MEMORY_REGION(dst_mem_addr, + dst_mem_size)); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ENOTSUPPORTED") { + REQUIRE(rv == NORNS_ENOTSUPPORTED); + } + } + + env.notify_success(); + } + +#ifndef USE_REAL_DAEMON + GIVEN("a non-running urd instance") { + WHEN("attempting to request a transfer") { + + norns_iotask_t task = + NORNSCTL_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH("nvml0://", "/a/b/c/"), + NORNS_REMOTE_PATH("nvml0://", + "node1", + "/a/b/d/")); + + norns_error_t rv = nornsctl_submit(&task); + + THEN("nornsctl_submit() returns NORNS_ECONNFAILED") { + REQUIRE(rv == NORNS_ECONNFAILED); + } + } + } +#endif +} diff --git a/tests/api-remove-local-data.cpp b/tests/api-remove-local-data.cpp index 907d945dd36ee1dd3f8230a6e67edf0f5db4d8e5..2a3bd3c680f449e05ed72d474d5570bc67ceeb34 100644 --- a/tests/api-remove-local-data.cpp +++ b/tests/api-remove-local-data.cpp @@ -26,14 +26,14 @@ *************************************************************************/ #include "norns.h" -#include "nornsctl.h" #include "test-env.hpp" #include "compare-files.hpp" #include "catch.hpp" namespace bfs = boost::filesystem; -SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_files]") { +SCENARIO("remove a local POSIX file", + "[api::norns_submit_remove_local_posix_files]") { GIVEN("a running urd instance") { test_env env; @@ -43,8 +43,10 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil bfs::path src_mnt, dst_mnt; // create namespaces - std::tie(std::ignore, src_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); - std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid1, "mnt/tmp1", 16384); + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); // define input names const bfs::path src_file_at_root = "/file0"; @@ -134,30 +136,32 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil // create required output directories env.add_to_namespace(nsid1, dst_subdir1); - /**************************************************************************************************************/ - /* tests for error conditions */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ // - trying to remove a non-existing file WHEN("removing a non-existing NORNS_LOCAL_PATH file") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_invalid_file.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -172,24 +176,26 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil // - trying to remove a non-existing directory WHEN("removing a non-existing NORNS_LOCAL_PATH directory") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_invalid_dir.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and ENOENT are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "ENOENT") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -204,29 +210,32 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil #ifdef __SETCAP_TESTS__ // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate permissions to access it") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH file from \"/\" without appropriate " + "permissions to access it") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_file0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -240,29 +249,31 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from a subdir without appropriate permissions to access it") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access it") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -276,29 +287,31 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // - trying to copy a file from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH file from a subdir without appropriate permissions to access a parent") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH file from a subdir without " + "appropriate permissions to access a parent") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_noperms_file2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -312,29 +325,32 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without appropriate permissions to access it") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH subdir from \"/\" without " + "appropriate permissions to access it") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir0.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir0.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -348,29 +364,32 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without appropriate permissions to access it") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access it") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir1.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir1.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -384,29 +403,32 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // - trying to copy a subdir from namespace root with invalid access permissions - WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without appropriate permissions to access a parent") { - - norns_op_t task_op = NORNS_IOTASK_COPY; + WHEN("copying a NORNS_LOCAL_PATH subdir from another subdir without " + "appropriate permissions to access a parent") { - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_noperms_subdir2.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file_at_root0.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, + src_noperms_subdir2.c_str()), + NORNS_LOCAL_PATH(nsid1, + dst_file_at_root0.c_str())); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("NORNS_ESYSTEMERROR and EACCES|EPERM|EINVAL are reported") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EACCES|EPERM|EINVAL") { norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHEDWERROR); @@ -420,26 +442,27 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } #endif - /**************************************************************************************************************/ - /* tests for single files */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for single files */ + /**********************************************************************/ // rm ns0://file0.txt WHEN("removing a single NORNS_LOCAL_PATH from src namespace's root") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_file_at_root.c_str())); const bfs::path p = env.get_from_namespace(nsid0, src_file_at_root); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("File no longer exists") { @@ -450,22 +473,26 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // rm ns0://a/b/c/.../d/file0.txt - WHEN("removing a single NORNS_LOCAL_PATH from a src namespace's subdir") { + WHEN("removing a single NORNS_LOCAL_PATH from a src namespace's " + "subdir") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_file_at_subdir.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, src_file_at_subdir); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_file_at_subdir.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, src_file_at_subdir); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("File no longer exists") { @@ -475,26 +502,28 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } } - /**************************************************************************************************************/ - /* tests for directories */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for directories */ + /**********************************************************************/ // rm -r /a/contents.* - WHEN("removing the contents of a NORNS_LOCAL_PATH subdir from src namespace's root") { - - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str())); + WHEN("removing the contents of a NORNS_LOCAL_PATH subdir from src " + "namespace's root") { + + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_subdir0.c_str())); const bfs::path p = env.get_from_namespace(nsid0, src_subdir0); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directory no longer exists") { @@ -505,22 +534,23 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } // rm -r /a/b/c/.../contents.* - WHEN("removing the contents of a NORNS_LOCAL_PATH arbitrary subdir to") { + WHEN("removing the contents of a NORNS_LOCAL_PATH arbitrary subdir") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_subdir1.c_str())); const bfs::path p = env.get_from_namespace(nsid0, src_subdir1); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directory no longer exists") { @@ -532,20 +562,21 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil WHEN("removing an empty NORNS_LOCAL_PATH directory") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, src_empty_dir.c_str())); const bfs::path p = env.get_from_namespace(nsid0, src_empty_dir); norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); THEN("Directory no longer exists") { @@ -556,31 +587,36 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil } - /**************************************************************************************************************/ - /* tests for soft links */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for soft links */ + /**********************************************************************/ WHEN("removing a single NORNS_LOCAL_PATH file from src namespace's '/' " "through a symlink also located at '/'" ) { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_root0.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, "/") / src_symlink_at_root0; + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root0.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_root0; norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("symlink no longer exists and original file is left intact") { + THEN("symlink no longer exists and original file is left " + "intact") { REQUIRE(!bfs::exists(p)); - REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_file_at_root))); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_file_at_root))); } } } @@ -589,25 +625,30 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil WHEN("removing a single NORNS_LOCAL_PATH arbitrary subdir" "through a symlink located at '/'" ) { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_root2.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, "/") / src_symlink_at_root2; + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_root2.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_root2; norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("symlink no longer exists and original file is left intact") { + THEN("symlink no longer exists and original file is left " + "intact") { REQUIRE(!bfs::exists(p)); - REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_subdir1))); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_subdir1))); } } } @@ -616,50 +657,59 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil WHEN("removing a single NORNS_LOCAL_PATH file from src namespace's '/' " "through a symlink located in a subdir" ) { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir0.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir0; + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir0.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir0; norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("symlink no longer exists and original file is left intact") { + THEN("symlink no longer exists and original file is left " + "intact") { REQUIRE(!bfs::exists(p)); - REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_file_at_root))); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_file_at_root))); } } } } - WHEN("removing a single NORNS_LOCAL_PATH subdir from src namespace's '/' " - "through a symlink also located at subdir" ) { + WHEN("removing a single NORNS_LOCAL_PATH subdir from src namespace's " + "'/' through a symlink also located at subdir") { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir1.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir1; + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir1.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir1; norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("symlink no longer exists and original file is left intact") { + THEN("symlink no longer exists and original file is left " + "intact") { REQUIRE(!bfs::exists(p)); REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_subdir0))); } @@ -670,25 +720,30 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil WHEN("removing a single NORNS_LOCAL_PATH arbitrary subdir" "through a symlink also located at a subdir" ) { - norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_REMOVE, - NORNS_LOCAL_PATH(nsid0, src_symlink_at_subdir2.c_str())); - const bfs::path p = env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir2; + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_REMOVE, + NORNS_LOCAL_PATH(nsid0, + src_symlink_at_subdir2.c_str())); + const bfs::path p = + env.get_from_namespace(nsid0, "/") / src_symlink_at_subdir2; norns_error_t rv = norns_submit(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // wait until the task completes rv = norns_wait(&task); - THEN("NORNS_SUCCESS is returned") { + THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); - THEN("symlink no longer exists and original file is left intact") { + THEN("symlink no longer exists and original file is left " + "intact") { REQUIRE(!bfs::exists(p)); - REQUIRE(bfs::exists(env.get_from_namespace(nsid0, src_subdir1))); + REQUIRE(bfs::exists( + env.get_from_namespace(nsid0, src_subdir1))); } } } diff --git a/tests/api-send-command.cpp b/tests/api-send-command.cpp index ab5d518592211836d48d68a63ba48059be63cdff..dcafdc92a0382510c99e110c2cd28ac246c35fe0 100644 --- a/tests/api-send-command.cpp +++ b/tests/api-send-command.cpp @@ -144,7 +144,7 @@ SCENARIO("send control commands to urd", "[api::nornsctl_send_command]") { REQUIRE(rv == NORNS_ETASKSPENDING); AND_WHEN("all tasks complete") { - rv = norns_wait(&tasks[ntasks-1]); + rv = nornsctl_wait(&tasks[ntasks-1]); THEN("nornsctl_send_command() returns NORNS_SUCCESS") { rv = nornsctl_send_command(NORNSCTL_CMD_SHUTDOWN, NULL); diff --git a/tests/api-task-init.cpp b/tests/api-task-init.cpp index 15e6b48bd8f64f9ce0a27150b32e6b64a5b14a7b..1f07bb5849783460610ac987a2a766f7f44908ef 100644 --- a/tests/api-task-init.cpp +++ b/tests/api-task-init.cpp @@ -27,10 +27,10 @@ #include #include "norns.h" -#include "nornsctl.h" #include "catch.hpp" -SCENARIO("initialize a task with norns_iotask_init", "[api::norns_iotask_init]") { +SCENARIO("initialize a task with norns_iotask_init", + "[api::norns_iotask_init]") { GIVEN("invalid task information") { WHEN("initializing a task with NULL src and dst") { @@ -40,7 +40,7 @@ SCENARIO("initialize a task with norns_iotask_init", "[api::norns_iotask_init]") norns_iotask_init(&task, task_op, NULL, NULL); - THEN("task is set to 0") { + AND_THEN("task is set to 0") { norns_iotask_t dummy; memset(&dummy, 0, sizeof(dummy)); REQUIRE(memcmp(&task, &dummy, sizeof(norns_iotask_t)) == 0); @@ -68,30 +68,9 @@ SCENARIO("initialize a task with norns_iotask_init", "[api::norns_iotask_init]") } } -///XXX this case is no longer invalid -/// GIVEN("invalid task information") { -/// WHEN("initializing a task with a NULL dst") { -/// -/// norns_iotask_t task; -/// norns_op_t task_op = NORNS_IOTASK_COPY; -/// -/// void* src_addr = (void*) 0xdeadbeef; -/// size_t src_size = (size_t) 42; -/// -/// norns_resource_t src = NORNS_MEMORY_REGION(src_addr, src_size); -/// -/// norns_iotask_init(&task, task_op, &src, NULL); -/// -/// THEN("task is set to 0") { -/// norns_iotask_t dummy; -/// memset(&dummy, 0, sizeof(dummy)); -/// REQUIRE(memcmp(&task, &dummy, sizeof(norns_iotask_t)) == 0); -/// } -/// } -/// } - GIVEN("valid task information") { - WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and dst=NORNS_POSIX_PATH | R_LOCAL") { + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_POSIX_PATH | R_LOCAL") { norns_op_t task_op = NORNS_IOTASK_COPY; void* src_addr = (void*) 0xdeadbeef; @@ -116,14 +95,17 @@ SCENARIO("initialize a task with norns_iotask_init", "[api::norns_iotask_init]") THEN("the norns_task structure is initialized as expected") { REQUIRE(task.t_id == 0); REQUIRE(task.t_op == task_op); - REQUIRE(memcmp(&task.t_src, &src, sizeof(norns_resource_t)) == 0); - REQUIRE(memcmp(&task.t_dst, &dst, sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_src, &src, + sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_dst, &dst, + sizeof(norns_resource_t)) == 0); } } } GIVEN("valid task information") { - WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and dst=NORNS_POSIX_PATH | R_REMOTE") { + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_POSIX_PATH | R_REMOTE") { norns_op_t task_op = NORNS_IOTASK_COPY; void* src_addr = (void*) 0xdeadbeef; @@ -149,17 +131,20 @@ SCENARIO("initialize a task with norns_iotask_init", "[api::norns_iotask_init]") THEN("the norns_task structure is initialized as expected") { REQUIRE(task.t_id == 0); REQUIRE(task.t_op == task_op); - REQUIRE(memcmp(&task.t_src, &src, sizeof(norns_resource_t)) == 0); - REQUIRE(memcmp(&task.t_dst, &dst, sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_src, &src, + sizeof(norns_resource_t)) == 0); + REQUIRE(memcmp(&task.t_dst, &dst, + sizeof(norns_resource_t)) == 0); } } } } -SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { +SCENARIO("initialize a task with NORNS_IOTASK", "[api::NORNS_IOTASK]") { GIVEN("valid task information") { - WHEN("initializing a task with src=NORNS_MEMORY_REGION and dst=NORNS_LOCAL_PATH") { + WHEN("initializing a task with src=NORNS_MEMORY_REGION and " + "dst=NORNS_LOCAL_PATH") { norns_op_t task_op = NORNS_IOTASK_COPY; void* src_addr = (void*) 0xdeadbeef; @@ -167,9 +152,10 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { const char* dst_nsid = "tmp://"; const char* dst_path = "/a/b/c"; - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(src_addr, src_size), - NORNS_LOCAL_PATH(dst_nsid, dst_path)); + norns_iotask_t task = + NORNS_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_LOCAL_PATH(dst_nsid, dst_path)); THEN("the norns_task structure is initialized as expected") { REQUIRE(task.t_id == 0); @@ -182,7 +168,8 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { } } - WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and dst=NORNS_REMOTE_PATH") { + WHEN("initializing a task with src=NORNS_PROCESS_MEMORY and " + "dst=NORNS_REMOTE_PATH") { norns_op_t task_op = NORNS_IOTASK_COPY; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -190,9 +177,10 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { const char* dst_host = "node0"; const char* dst_path = "/a/b/c"; - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(src_addr, src_size), - NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); + norns_iotask_t task = + NORNS_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); THEN("the norns_task structure is initialized as expected") { REQUIRE(task.t_id == 0); @@ -207,7 +195,8 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { } - WHEN("initializing a task with src=NORNS_MEMORY_REGION and dst=NORNS_LOCAL_PATH") { + WHEN("initializing a task with src=NORNS_MEMORY_REGION and " + "dst=NORNS_LOCAL_PATH") { norns_op_t task_op = NORNS_IOTASK_COPY; void* src_addr = (void*) 0xdeadbeef; @@ -215,9 +204,10 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { const char* dst_nsid = "tmp://"; const char* dst_path = "/a/b/c"; - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(src_addr, src_size), - NORNS_SHARED_PATH(dst_nsid, dst_path)); + norns_iotask_t task = + NORNS_IOTASK(task_op, + NORNS_MEMORY_REGION(src_addr, src_size), + NORNS_SHARED_PATH(dst_nsid, dst_path)); THEN("the norns_task structure is initialized as expected") { REQUIRE(task.t_id == 0); @@ -231,4 +221,3 @@ SCENARIO("initialize a task with NORNS_TASK", "[api::NORNS_TASK]") { } } } - diff --git a/tests/api-task-status.cpp b/tests/api-task-status.cpp index c99e397e6e697fa3f0e1fa5d89f9d56f8da8b99b..d5998e5afc14e535b74aeef275dba1a3055f98b9 100644 --- a/tests/api-task-status.cpp +++ b/tests/api-task-status.cpp @@ -27,11 +27,10 @@ #include "norns.h" -#include "nornsctl.h" #include "test-env.hpp" #include "catch.hpp" -SCENARIO("check request", "[api::norns_status]") { +SCENARIO("check request", "[api::norns_error]") { GIVEN("a running urd instance") { test_env env( @@ -45,8 +44,10 @@ SCENARIO("check request", "[api::norns_status]") { bfs::path src_mnt, dst_mnt; // create namespaces - std::tie(std::ignore, src_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); - std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid1, "mnt/tmp1", 16384); + std::tie(std::ignore, src_mnt) = + env.create_namespace(nsid0, "mnt/tmp0", 16384); + std::tie(std::ignore, dst_mnt) = + env.create_namespace(nsid1, "mnt/tmp1", 16384); // define input names std::vector input_data(100, 42); @@ -61,17 +62,16 @@ SCENARIO("check request", "[api::norns_status]") { // create input data env.add_to_namespace(nsid0, "/a/b/c/file", 4096); - /**************************************************************************************************************/ - /* tests for error conditions */ - /**************************************************************************************************************/ + /**********************************************************************/ + /* tests for error conditions */ + /**********************************************************************/ WHEN("checking the status of an active request") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_MEMORY_REGION(src_buf, src_buf_size), - NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_MEMORY_REGION(src_buf, src_buf_size), + NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); norns_error_t rv = norns_submit(&task); @@ -80,7 +80,7 @@ SCENARIO("check request", "[api::norns_status]") { REQUIRE(task.t_id != 0); norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); THEN("NORNS_SUCCESS is returned and task status is valid") { REQUIRE(rv == NORNS_SUCCESS); @@ -93,11 +93,10 @@ SCENARIO("check request", "[api::norns_status]") { WHEN("checking the status of an active request") { - norns_op_t task_op = NORNS_IOTASK_COPY; - - norns_iotask_t task = NORNS_IOTASK(task_op, - NORNS_LOCAL_PATH(nsid0, src_file.c_str()), - NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); + norns_iotask_t task = + NORNS_IOTASK(NORNS_IOTASK_COPY, + NORNS_LOCAL_PATH(nsid0, src_file.c_str()), + NORNS_LOCAL_PATH(nsid1, dst_file.c_str())); norns_error_t rv = norns_submit(&task); @@ -107,7 +106,7 @@ SCENARIO("check request", "[api::norns_status]") { retry: norns_stat_t stats; - rv = norns_status(&task, &stats); + rv = norns_error(&task, &stats); THEN("NORNS_SUCCESS is returned and task status is valid") { REQUIRE(rv == NORNS_SUCCESS); @@ -125,15 +124,13 @@ retry: /* WHEN("submitting a request to copy data using unregistered backends") { - norns_op_t task_op = NORNS_IOTASK_COPY; - void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; const char* dst_nsid = "tmp://"; const char* dst_path = "/a/b/c"; - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_MEMORY_REGION(src_addr, src_size), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -146,8 +143,6 @@ retry: WHEN("submitting a request to copy data using an unregistered src backend") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp0"; const char* src_path = "/a/b/c"; @@ -162,7 +157,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -179,8 +174,6 @@ retry: WHEN("submitting a request to copy data using an unregistered dst backend") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp0"; const char* src_path = "/a/b/c"; @@ -194,7 +187,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -218,8 +211,6 @@ retry: /* copy from process memory to .* */ WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -232,7 +223,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -253,8 +244,6 @@ retry: WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -268,7 +257,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -289,8 +278,6 @@ retry: WHEN("submitting a request to copy from NORNS_PROCESS_MEMORY to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -305,7 +292,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); */ - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -324,8 +311,6 @@ retry: /* copy from local path to .* */ WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp0://"; const char* src_mnt = "/mnt/tmp0"; const char* src_path = "/b/c/d"; @@ -342,7 +327,7 @@ retry: rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -363,8 +348,6 @@ retry: WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/b/c/d"; @@ -381,7 +364,7 @@ retry: rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -402,8 +385,6 @@ retry: WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/b/c/d"; @@ -423,7 +404,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); */ - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -442,8 +423,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -456,7 +435,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -474,8 +453,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -488,7 +465,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -506,8 +483,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -516,7 +491,7 @@ retry: const char* dst_host = "node1"; const char* dst_path = "/b/c/d"; - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -530,8 +505,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_LOCAL_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/a/b/c"; @@ -545,7 +518,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bsrc); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -566,8 +539,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_SHARED_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "lustre://"; const char* src_mnt = "/mnt/lustre"; const char* src_path = "/a/b/c"; @@ -581,7 +552,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bsrc); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_SHARED_PATH(src_nsid, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -602,8 +573,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to copy from NORNS_REMOTE_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_COPY; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -612,7 +581,7 @@ retry: void* dst_addr = (void*) 0xdeadbeef; size_t dst_size = (size_t) 42; - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -633,8 +602,6 @@ retry: /* move from process memory to .* */ WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -647,7 +614,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -668,8 +635,6 @@ retry: WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -683,7 +648,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -704,8 +669,6 @@ retry: WHEN("submitting a request to move from NORNS_PROCESS_MEMORY to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "mem://"; void* src_addr = (void*) 0xdeadbeef; size_t src_size = (size_t) 42; @@ -720,7 +683,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); */ - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_MEMORY_REGION(src_nsid, src_addr, src_size), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -739,8 +702,6 @@ retry: /* move from local path to .* */ WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp0://"; const char* src_mnt = "/mnt/tmp0"; const char* src_path = "/b/c/d"; @@ -757,7 +718,7 @@ retry: rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -778,8 +739,6 @@ retry: WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/b/c/d"; @@ -796,7 +755,7 @@ retry: rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -817,8 +776,6 @@ retry: WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/b/c/d"; @@ -838,7 +795,7 @@ retry: REQUIRE(rv == NORNS_SUCCESS); */ - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -857,8 +814,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_LOCAL_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -871,7 +826,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_LOCAL_PATH(dst_nsid, dst_path)); @@ -889,8 +844,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_SHARED_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -903,7 +856,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bdst); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_SHARED_PATH(dst_nsid, dst_path)); @@ -921,8 +874,6 @@ retry: /* using a remote node as source is not allowed (yet) */ WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_REMOTE_PATH") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -931,7 +882,7 @@ retry: const char* dst_host = "node1"; const char* dst_path = "/b/c/d"; - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_REMOTE_PATH(dst_nsid, dst_host, dst_path)); @@ -945,8 +896,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to move from NORNS_LOCAL_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_mnt = "/mnt/tmp"; const char* src_path = "/a/b/c"; @@ -960,7 +909,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bsrc); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_LOCAL_PATH(src_nsid, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -981,8 +930,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to move from NORNS_SHARED_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "lustre://"; const char* src_mnt = "/mnt/lustre"; const char* src_path = "/a/b/c"; @@ -996,7 +943,7 @@ retry: norns_error_t rv = nornsctl_register_namespace(&bsrc); REQUIRE(rv == NORNS_SUCCESS); - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_SHARED_PATH(src_nsid, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -1017,8 +964,6 @@ retry: /* using the process memory as destination is not allowed (yet) */ WHEN("submitting a request to move from NORNS_REMOTE_PATH to NORNS_PROCESS_MEMORY") { - norns_op_t task_op = NORNS_IOTASK_MOVE; - const char* src_nsid = "tmp://"; const char* src_host = "node0"; const char* src_path = "/a/b/c"; @@ -1027,7 +972,7 @@ retry: void* dst_addr = (void*) 0xdeadbeef; size_t dst_size = (size_t) 42; - norns_iotask_t task = NORNS_IOTASK(task_op, + norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_MOVE, NORNS_REMOTE_PATH(src_nsid, src_host, src_path), NORNS_MEMORY_REGION(dst_nsid, dst_addr, dst_size)); @@ -1063,125 +1008,3 @@ retry: } #endif } - - -SCENARIO("check requests", "[api::nornsctl_status]") { - GIVEN("a running urd instance") { - - test_env env( - fake_daemon_cfg { - true /* dry_run? */ - } - ); - - const char* nsid0 = "tmp0"; - const char* nsid1 = "tmp1"; - bfs::path src_mnt, dst_mnt; - - // create namespaces - std::tie(std::ignore, src_mnt) = env.create_namespace(nsid0, "mnt/tmp0", 16384); - std::tie(std::ignore, dst_mnt) = env.create_namespace(nsid1, "mnt/tmp1", 16384); - - // define input names - void* src_buf; - size_t src_buf_size __attribute__((unused)); - const bfs::path src_file = "/a/b/c/file"; - size_t src_file_size = 4096; - - // define output names - const bfs::path dst_file = "/b/c/d/file"; - - // create input data - env.add_to_namespace(nsid0, src_file, 4096); - - // 64MiB buffer - std::vector input_data(16*1024*1024, 42); - src_buf = input_data.data(); - src_buf_size = input_data.size() * sizeof(int); - - WHEN("checking the status of all requests without actual requests running") { - nornsctl_stat_t global_stats; - norns_error_t rv = nornsctl_status(&global_stats); - REQUIRE(rv == NORNS_SUCCESS); - REQUIRE(global_stats.st_pending_tasks == 0); - REQUIRE(global_stats.st_running_tasks == 0); - REQUIRE(global_stats.st_eta == 0.0); - } - - WHEN("checking the status of all requests") { - - norns_op_t task_op = NORNS_IOTASK_COPY; - - const size_t ntasks = 10; - norns_iotask_t tasks[ntasks]; - size_t sizes[] = { 4*1024*1024, 16*1024*1024, 32*1024*1024, 64*1024*1024 }; - - for(size_t i=0; i