From 6983c1ff5841c000963f0162fbb895a1dd200cbb Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 7 Mar 2019 16:05:00 +0100 Subject: [PATCH 1/8] Fix formatting --- include/norns/norns.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/norns/norns.h b/include/norns/norns.h index 6cc982e..cfa41b9 100644 --- a/include/norns/norns.h +++ b/include/norns/norns.h @@ -84,16 +84,20 @@ norns_iotask_t 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_status(norns_iotask_t* task, norns_stat_t* stats) __THROW; /* Return a string describing the error number */ char* norns_strerror(norns_error_t errnum) __THROW; -- GitLab From 074515b8707f2e64183a1295cf32e84bf20927cc Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 7 Mar 2019 16:39:11 +0100 Subject: [PATCH 2/8] Rename norns_status() to norns_error() We need to provide a nornsctl_status() function to check the status of administrative data transfer tasks, but we already have a nornsctl_status() function in the API that checks the global status of the service. Thus, we decided to keep the current nornsctl_status() and rename norns_status() to norns_error() and provide a nornsctl_error() for simmetry. --- .gitlab-ci.yml | 4 +- include/norns/norns.h | 2 +- lib/libnorns.c | 2 +- tests/api-copy-local-data.cpp | 32 ++--- tests/api-copy-remote-data.cpp | 236 ++++++++++++++++---------------- tests/api-remove-local-data.cpp | 16 +-- tests/api-task-status.cpp | 8 +- 7 files changed, 150 insertions(+), 150 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0270e1..ac051b7 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/norns/norns.h b/include/norns/norns.h index cfa41b9..efa4d51 100644 --- a/include/norns/norns.h +++ b/include/norns/norns.h @@ -97,7 +97,7 @@ 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(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/lib/libnorns.c b/lib/libnorns.c index da4fd57..ed8de57 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/tests/api-copy-local-data.cpp b/tests/api-copy-local-data.cpp index c7a495f..4d62097 100644 --- a/tests/api-copy-local-data.cpp +++ b/tests/api-copy-local-data.cpp @@ -160,7 +160,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -194,7 +194,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -228,7 +228,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -267,7 +267,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -303,7 +303,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -339,7 +339,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -375,7 +375,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -411,7 +411,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -447,7 +447,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -485,7 +485,7 @@ SCENARIO("copy local POSIX file to local POSIX file", "[api::norns_submit_copy_l 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); @@ -1296,9 +1296,9 @@ 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); @@ -1419,9 +1419,9 @@ 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); @@ -1466,9 +1466,9 @@ 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); diff --git a/tests/api-copy-remote-data.cpp b/tests/api-copy-remote-data.cpp index 5447d1c..90c6bd8 100644 --- a/tests/api-copy-remote-data.cpp +++ b/tests/api-copy-remote-data.cpp @@ -170,7 +170,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 +205,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 +240,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 +282,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 +320,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 +359,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 +399,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 +438,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 +478,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 +517,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 +672,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 +720,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 +767,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 +816,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 +863,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 +910,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 +957,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 +1004,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 +1051,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 +1098,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 +1262,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 +1306,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 +1352,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 +1398,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 +1444,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 +1490,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 +1577,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 +1616,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 +1727,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 +1812,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 +1875,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 +2094,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 +2138,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 +2182,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 +2226,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 +2271,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 +2316,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 +2480,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 +2516,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 +2552,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 +2595,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 +2635,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 +2674,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 +2714,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 +2753,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 +2793,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 +2832,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 +2988,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 +3035,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 +3081,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 +3129,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 +3177,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 +3225,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 +3273,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 +3321,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 +3369,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 +3417,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 +3579,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 +3624,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 +3671,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 +3718,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 +3765,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 +3812,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 +3991,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 +4035,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 +4079,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 +4123,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 +4168,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 +4213,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-remove-local-data.cpp b/tests/api-remove-local-data.cpp index 907d945..25242d4 100644 --- a/tests/api-remove-local-data.cpp +++ b/tests/api-remove-local-data.cpp @@ -157,7 +157,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -189,7 +189,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -226,7 +226,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -262,7 +262,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -298,7 +298,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -334,7 +334,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -370,7 +370,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); @@ -406,7 +406,7 @@ SCENARIO("remove a local POSIX file", "[api::norns_submit_remove_local_posix_fil 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); diff --git a/tests/api-task-status.cpp b/tests/api-task-status.cpp index c99e397..27446a2 100644 --- a/tests/api-task-status.cpp +++ b/tests/api-task-status.cpp @@ -31,7 +31,7 @@ #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( @@ -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); @@ -107,7 +107,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); @@ -1143,7 +1143,7 @@ SCENARIO("check requests", "[api::nornsctl_status]") { for(size_t i=0; i Date: Thu, 7 Mar 2019 20:35:22 +0100 Subject: [PATCH 3/8] Simplify headers --- include/Makefile.am | 2 - include/norns/norns.h | 38 +++------- include/norns/norns_backends.h | 48 ------------- include/norns/norns_resources.h | 107 --------------------------- include/norns/norns_types.h | 123 +++++++++++++++++++++++++++++++- include/norns/nornsctl.h | 4 +- include/norns/nornsctl_types.h | 54 -------------- src/backends/posix-fs.hpp | 1 - src/backends/process-memory.hpp | 1 - 9 files changed, 132 insertions(+), 246 deletions(-) delete mode 100644 include/norns/norns_backends.h delete mode 100644 include/norns/norns_resources.h delete mode 100644 include/norns/nornsctl_types.h diff --git a/include/Makefile.am b/include/Makefile.am index fdbdcd6..633bbef 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 efa4d51..cb0bcff 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,39 +47,20 @@ 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 @@ -97,7 +76,8 @@ norns_cancel(norns_iotask_t* task) __THROW; /* Check the status of a submitted I/O task */ norns_error_t -norns_error(norns_iotask_t* task, norns_stat_t* stats) __THROW; +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 3eca26d..0000000 --- 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 35ff4b9..0000000 --- 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 d42a396..683d8ac 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 552ff97..db27794 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__ diff --git a/include/norns/nornsctl_types.h b/include/norns/nornsctl_types.h deleted file mode 100644 index f5aa133..0000000 --- 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/src/backends/posix-fs.hpp b/src/backends/posix-fs.hpp index 5e558b8..b631e8b 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 9db0236..8db4570 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; -- GitLab From d0158918e62f2f659406f5d440bb718c3657e8d9 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 7 Mar 2019 21:15:49 +0100 Subject: [PATCH 4/8] Add task functions to libnornsctl Add nornsctl_iotask_init() Add NORNSCTL_IOTASK() Add nornsctl_submit() Add nornsctl_wait() Add nornsctl_cancel() Add nornsctl_error() --- include/norns/nornsctl.h | 29 ++++++++++++++ lib/libnornsctl.c | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/include/norns/nornsctl.h b/include/norns/nornsctl.h index db27794..6333454 100644 --- a/include/norns/nornsctl.h +++ b/include/norns/nornsctl.h @@ -173,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/lib/libnornsctl.c b/lib/libnornsctl.c index d2bd5e1..625ee3d 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,90 @@ nornsctl_job_init(nornsctl_job_t* job, const char** hosts, size_t nhosts, job->j_nlimits = nlimits; } +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) { -- GitLab From 1ddd7046211ced960c886253011f9f435bb9e73e Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Fri, 8 Mar 2019 10:13:18 +0100 Subject: [PATCH 5/8] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9a1737c..bdb7e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ config.log src/old-sources src/spdlog_0.12/ build +build.* -- GitLab From 9344b2600733b7ed0cea339448c8cca0f756e827 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Mon, 11 Mar 2019 14:18:51 +0100 Subject: [PATCH 6/8] Add missing NORNSCTL_IOTASK --- lib/libnornsctl.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/libnornsctl.c b/lib/libnornsctl.c index 625ee3d..0e7c03d 100644 --- a/lib/libnornsctl.c +++ b/lib/libnornsctl.c @@ -332,6 +332,24 @@ 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, -- GitLab From 1e2d74d1e1c7c07f0ffb2f00b9cde4abf04ae656 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Tue, 12 Mar 2019 11:13:09 +0100 Subject: [PATCH 7/8] Add tests for new admin API functions --- tests/Makefile.am | 6 + tests/api-copy-local-data.cpp | 940 +++--- tests/api-copy-remote-data.cpp | 1 - tests/api-ctl-copy-local-data.cpp | 1638 +++++++++++ tests/api-ctl-copy-remote-data.cpp | 4239 +++++++++++++++++++++++++++ tests/api-ctl-remove-local-data.cpp | 774 +++++ tests/api-ctl-task-init.cpp | 224 ++ tests/api-ctl-task-status.cpp | 1136 +++++++ tests/api-ctl-task-submit.cpp | 567 ++++ tests/api-remove-local-data.cpp | 337 ++- tests/api-send-command.cpp | 2 +- tests/api-task-init.cpp | 79 +- tests/api-task-status.cpp | 261 +- tests/api-task-submit.cpp | 373 +-- 14 files changed, 9593 insertions(+), 984 deletions(-) create mode 100644 tests/api-ctl-copy-local-data.cpp create mode 100644 tests/api-ctl-copy-remote-data.cpp create mode 100644 tests/api-ctl-remove-local-data.cpp create mode 100644 tests/api-ctl-task-init.cpp create mode 100644 tests/api-ctl-task-status.cpp create mode 100644 tests/api-ctl-task-submit.cpp diff --git a/tests/Makefile.am b/tests/Makefile.am index 8de929b..9122ac0 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 4d62097..1e99cf9 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,31 +136,32 @@ 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_error(&task, &stats); @@ -174,25 +177,26 @@ 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_error(&task, &stats); @@ -208,25 +212,25 @@ 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_error(&task, &stats); @@ -241,31 +245,35 @@ 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_error(&task, &stats); @@ -280,28 +288,31 @@ 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_error(&task, &stats); @@ -316,28 +327,31 @@ 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_error(&task, &stats); @@ -352,28 +366,32 @@ 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_error(&task, &stats); @@ -388,28 +406,32 @@ 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_error(&task, &stats); @@ -424,28 +446,32 @@ 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_error(&task, &stats); @@ -465,25 +491,26 @@ 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_error(&task, &stats); @@ -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,7 +1404,8 @@ 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_error() reports NORNS_ESYSTEMERROR and EFAULT") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EFAULT") { norns_stat_t stats; rv = norns_error(&task, &stats); @@ -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,7 +1531,8 @@ 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_error() reports NORNS_ESYSTEMERROR and EISDIR") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { norns_stat_t stats; rv = norns_error(&task, &stats); @@ -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,7 +1579,8 @@ 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_error() reports NORNS_ESYSTEMERROR and EISDIR") { + THEN("norns_error() reports NORNS_ESYSTEMERROR and " + "EISDIR") { norns_stat_t stats; rv = norns_error(&task, &stats); @@ -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 90c6bd8..6a88aec 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" diff --git a/tests/api-ctl-copy-local-data.cpp b/tests/api-ctl-copy-local-data.cpp new file mode 100644 index 0000000..0b8318a --- /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 0000000..82c2316 --- /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 0000000..73fdf06 --- /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 0000000..5a1bbb6 --- /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 0000000..7dcfe3d --- /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 25242d4..2a3bd3c 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,28 +136,30 @@ 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_error(&task, &stats); @@ -172,22 +176,24 @@ 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_error(&task, &stats); @@ -204,27 +210,30 @@ 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_error(&task, &stats); @@ -240,27 +249,29 @@ 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_error(&task, &stats); @@ -276,27 +287,29 @@ 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_error(&task, &stats); @@ -312,27 +325,30 @@ 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_error(&task, &stats); @@ -348,27 +364,30 @@ 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_error(&task, &stats); @@ -384,27 +403,30 @@ 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_error(&task, &stats); @@ -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 ab5d518..dcafdc9 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 15e6b48..1f07bb5 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 27446a2..d5998e5 100644 --- a/tests/api-task-status.cpp +++ b/tests/api-task-status.cpp @@ -27,7 +27,6 @@ #include "norns.h" -#include "nornsctl.h" #include "test-env.hpp" #include "catch.hpp" @@ -45,8 +44,10 @@ SCENARIO("check request", "[api::norns_error]") { 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_error]") { // 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); @@ -93,11 +93,10 @@ SCENARIO("check request", "[api::norns_error]") { 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); @@ -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 Date: Tue, 12 Mar 2019 14:39:15 +0100 Subject: [PATCH 8/8] Make sure that task_manager is alive when register_completion is invoked --- src/io/task-manager.cpp | 20 +++++++++++--------- src/io/task-manager.hpp | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/io/task-manager.cpp b/src/io/task-manager.cpp index 6a1e4f4..c92b8de 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 36a10c7..03bce14 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 -- GitLab