Loading tests/mpi/Makefile.am +2 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ mpi_tests_SOURCES = \ $(top_srcdir)/tests/catch.hpp \ mpi-tests-main.cpp \ mpi-remote-transfers.cpp \ mpi-helpers.hpp \ mpi-helpers.cpp \ ../fake-daemon.cpp \ ../fake-daemon.hpp \ ../test-env.cpp \ Loading tests/mpi/commands.hpp 0 → 100644 +37 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #ifndef COMMANDS_HPP #define COMMANDS_HPP enum class server_command : int { accept = 0, restart, shutdown }; #endif // COMMANDS_HPP tests/mpi/mpi-helpers.cpp 0 → 100644 +111 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #include <stdexcept> #include <stdlib.h> #include "mpi-helpers.hpp" #ifdef MPI_TEST_DEBUG #include <iostream> #include <sstream> #endif // MPI_TEST_DEBUG namespace mpi { void initialize(int* argc, char** argv[]) { if(::MPI_Init(argc, argv) != MPI_SUCCESS) { throw std::runtime_error("Failed to initialize MPI"); } } void finalize() { if(::MPI_Finalize() != MPI_SUCCESS) { throw std::runtime_error("Failed to finalize MPI"); } } int get_rank() { int world_rank; if(::MPI_Comm_rank(MPI_COMM_WORLD, &world_rank) != MPI_SUCCESS) { throw std::runtime_error("Failed to determine own rank"); } return world_rank; } void barrier() { #ifdef MPI_TEST_DEBUG std::cerr << __PRETTY_FUNCTION__ << "\n"; std::cerr << "Entering MPI_Barrier()\n"; #endif // MPI_TEST_DEBUG ::MPI_Barrier(MPI_COMM_WORLD); #ifdef MPI_TEST_DEBUG std::cerr << "Exiting MPI_Barrier()\n"; #endif // MPI_TEST_DEBUG } server_command broadcast_command(server_command cmd) { int c = static_cast<int>(cmd); #ifdef MPI_TEST_DEBUG std::stringstream ss; ss << __PRETTY_FUNCTION__ << "(" << c << ")" << "\n"; std::cerr << ss.str(); std::cerr << "Entering MPI_Bcast()\n"; #endif // MPI_TEST_DEBUG ::MPI_Bcast(&c, 1, MPI_INT, 0, MPI_COMM_WORLD); #ifdef MPI_TEST_DEBUG MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) { std::stringstream ss; ss << "command was " << c << "\n"; std::cerr << ss.str(); } #endif #ifdef MPI_TEST_DEBUG std::cerr << "Exiting MPI_Bcast()\n"; #endif // MPI_TEST_DEBUG return static_cast<server_command>(c); } } // namespace mpi tests/mpi/mpi-helpers.hpp 0 → 100644 +59 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #ifndef MPI_HELPERS_HPP #define MPI_HELPERS_HPP #include <mpi.h> #include "commands.hpp" // #define MPI_TEST_DEBUG namespace mpi { void initialize(int* argc, char** argv[]); void finalize(); int get_rank(); server_command broadcast_command(server_command cmd = server_command::accept); void barrier(); } // namespace mpi #define MPI_RANK_EQ(r) (mpi::get_rank() == r) #define MPI_RANK_NEQ(r) (mpi::get_rank() != r) #define MPI_TEST_RUN_IF(expr) if(expr) #endif // MPI_HELPERS_HPP tests/mpi/mpi-remote-transfers.cpp +210 −143 Original line number Diff line number Diff line Loading @@ -25,23 +25,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ #include <mpi.h> #include "mpi-helpers.hpp" #include "commands.hpp" #include "norns.h" #include "nornsctl.h" #include "test-env.hpp" #include "catch.hpp" /******************************************************************************/ /* tests for push transfers (single files) */ /******************************************************************************/ SCENARIO("copy local POSIX file to remote POSIX file", "[mpi::norns_submit_push_to_posix_file]") { GIVEN("two running urd instances (local and remote)") { namespace test_data { /**********************************************************************/ /* setup common environment */ /**********************************************************************/ struct { // define input names const bfs::path src_file_at_root = "/file0"; Loading Loading @@ -75,26 +67,89 @@ SCENARIO("copy local POSIX file to remote POSIX file", 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 } test_context; } context; } /******************************************************************************/ /* tests for push transfers (single files) */ /******************************************************************************/ SCENARIO("copy local POSIX file to remote POSIX file", "[mpi::norns_submit_push_to_posix_file]") { using test_data::context; GIVEN("two running urd instances (local and remote)") { /**********************************************************************/ /* setup common environment */ /**********************************************************************/ test_env env(false); const char* remote_host = "127.0.0.1:42000"; // Get the number of processes int world_size; if(MPI_Comm_size(MPI_COMM_WORLD, &world_size) != MPI_SUCCESS) { FAIL("Failed to determine number of processes"); const char* hostname; if((hostname = ::getenv("MPICH_INTERFACE_HOSTNAME")) != NULL) { std::cerr << "hostname" << hostname << "\n"; } // Get the rank of the process int world_rank; if(MPI_Comm_rank(MPI_COMM_WORLD, &world_rank) != MPI_SUCCESS) { FAIL("Failed to determine own rank"); // code for the test servers MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) { bool shutdown = false; do { test_env env(false); std::string nsid("server" + std::to_string(mpi::get_rank())); bfs::path mountdir; // create namespaces std::tie(std::ignore, mountdir) = env.create_namespace(nsid, "mnt/" + nsid, 16384); // create required output directories env.add_to_namespace(nsid, context.dst_subdir1); // sync with client after preparing the test environment mpi::barrier(); bool restart = false; // servers do nothing but wait for client to complete do { int command = 0; server_command cmd = mpi::broadcast_command(); switch(cmd) { case server_command::shutdown: shutdown = true; break; case server_command::restart: restart = true; break; default: continue; } } while(!restart && !shutdown); env.notify_success(); } while(!shutdown); return; }; // MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) // code for the test client auto client = [world_rank, &env, &test_context] { MPI_TEST_RUN_IF(MPI_RANK_EQ(0)) { test_env env(false); std::string nsid("client"); bfs::path mountdir; Loading @@ -103,118 +158,127 @@ SCENARIO("copy local POSIX file to remote POSIX file", env.create_namespace(nsid, "mnt/" + nsid, 16384); // create input data env.add_to_namespace(nsid, test_context.src_file_at_root, 40000); env.add_to_namespace(nsid, test_context.src_file_at_subdir, 80000); env.add_to_namespace(nsid, test_context.src_subdir0); env.add_to_namespace(nsid, test_context.src_subdir1); env.add_to_namespace(nsid, test_context.src_empty_dir); env.add_to_namespace(nsid, context.src_file_at_root, 40000); env.add_to_namespace(nsid, context.src_file_at_subdir, 80000); env.add_to_namespace(nsid, context.src_subdir0); env.add_to_namespace(nsid, context.src_subdir1); env.add_to_namespace(nsid, context.src_empty_dir); for(int i=0; i<10; ++i) { const bfs::path p{test_context.src_subdir0 / const bfs::path p{context.src_subdir0 / ("file" + std::to_string(i))}; env.add_to_namespace(nsid, p, 4096+i*10); } for(int i=0; i<10; ++i) { const bfs::path p{test_context.src_subdir1 / const bfs::path p{context.src_subdir1 / ("file" + std::to_string(i))}; env.add_to_namespace(nsid, p, 4096+i*10); } // create input data with special permissions auto p = env.add_to_namespace(nsid, test_context.src_noperms_file0, 0); env.add_to_namespace(nsid, context.src_noperms_file0, 0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_file1, 0); p = env.add_to_namespace(nsid, context.src_noperms_file1, 0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_file2, 0); p = env.add_to_namespace(nsid, context.src_noperms_file2, 0); env.remove_access(p.parent_path()); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir0); p = env.add_to_namespace(nsid, context.src_noperms_subdir0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir1); p = env.add_to_namespace(nsid, context.src_noperms_subdir1); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir2); p = env.add_to_namespace(nsid, context.src_noperms_subdir2); env.remove_access(p.parent_path()); // add symlinks to the namespace env.add_to_namespace(nsid, test_context.src_file_at_root, test_context.src_symlink_at_root0); env.add_to_namespace(nsid, test_context.src_subdir0, test_context.src_symlink_at_root1); env.add_to_namespace(nsid, test_context.src_subdir1, test_context.src_symlink_at_root2); env.add_to_namespace(nsid, test_context.src_file_at_root, test_context.src_symlink_at_subdir0); env.add_to_namespace(nsid, test_context.src_subdir0, test_context.src_symlink_at_subdir1); env.add_to_namespace(nsid, test_context.src_subdir1, test_context.src_symlink_at_subdir2); env.add_to_namespace(nsid, context.src_file_at_root, context.src_symlink_at_root0); env.add_to_namespace(nsid, context.src_subdir0, context.src_symlink_at_root1); env.add_to_namespace(nsid, context.src_subdir1, context.src_symlink_at_root2); env.add_to_namespace(nsid, context.src_file_at_root, context.src_symlink_at_subdir0); env.add_to_namespace(nsid, context.src_subdir0, context.src_symlink_at_subdir1); env.add_to_namespace(nsid, context.src_subdir1, context.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(env.basedir(), mountdir / out_symlink, ec); REQUIRE(!ec); }; // code for the test servers auto server = [world_rank, &env, &test_context] { std::string nsid("server" + std::to_string(world_rank)); bfs::path mountdir; /******************************************************************/ /* 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.* ") { // create namespaces std::tie(std::ignore, mountdir) = env.create_namespace(nsid, "mnt/" + nsid, 16384); norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH("client", context.src_subdir0.c_str()), NORNS_REMOTE_PATH("server1", remote_host, context.dst_root.c_str())); // create required output directories env.add_to_namespace(nsid, test_context.dst_subdir1); }; norns_error_t rv = norns_submit(&task); THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // register code std::vector<std::function<void()>> functors; functors.reserve(world_size); // wait until the task completes rv = norns_wait(&task, NULL); functors.push_back(client); THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); for(int i = 1; i < world_size; ++i) { functors.push_back(server); } THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; rv = norns_error(&task, &stats); // run registered code for each process functors.at(world_rank)(); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); // wait for everyone to finish preparing the test environment MPI_Barrier(MPI_COMM_WORLD); #if 0 THEN("Copied files are identical to original") { bfs::path src = env.get_from_namespace("client", src_subdir0); bfs::path dst = env.get_from_namespace("server1", dst_root); if(world_rank != 0) { // servers do nothing but wait for client to complete MPI_Barrier(MPI_COMM_WORLD); env.notify_success(); return; REQUIRE(compare_directories(src, dst) == true); } #endif } } } } /**********************************************************************/ /* 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.* ") { WHEN("copying the contents of a NORNS_LOCAL_PATH arbitrary subdir " "to DST namespace's root\n" " cp -r /a/b/c/.../contents.* -> / = /contents.*") { ///XXX wrong test case norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH("client", test_context.src_subdir0.c_str()), context.src_subdir0.c_str()), NORNS_REMOTE_PATH("server1", remote_host, test_context.dst_root.c_str())); context.dst_root.c_str())); norns_error_t rv = norns_submit(&task); Loading Loading @@ -250,7 +314,10 @@ SCENARIO("copy local POSIX file to remote POSIX file", } } MPI_Barrier(MPI_COMM_WORLD); env.notify_success(); } // MPI_TEST_RUN_IF(MPI_RANK_EQ(0)) } std::cout << "Check!\n"; } Loading
tests/mpi/Makefile.am +2 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ mpi_tests_SOURCES = \ $(top_srcdir)/tests/catch.hpp \ mpi-tests-main.cpp \ mpi-remote-transfers.cpp \ mpi-helpers.hpp \ mpi-helpers.cpp \ ../fake-daemon.cpp \ ../fake-daemon.hpp \ ../test-env.cpp \ Loading
tests/mpi/commands.hpp 0 → 100644 +37 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #ifndef COMMANDS_HPP #define COMMANDS_HPP enum class server_command : int { accept = 0, restart, shutdown }; #endif // COMMANDS_HPP
tests/mpi/mpi-helpers.cpp 0 → 100644 +111 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #include <stdexcept> #include <stdlib.h> #include "mpi-helpers.hpp" #ifdef MPI_TEST_DEBUG #include <iostream> #include <sstream> #endif // MPI_TEST_DEBUG namespace mpi { void initialize(int* argc, char** argv[]) { if(::MPI_Init(argc, argv) != MPI_SUCCESS) { throw std::runtime_error("Failed to initialize MPI"); } } void finalize() { if(::MPI_Finalize() != MPI_SUCCESS) { throw std::runtime_error("Failed to finalize MPI"); } } int get_rank() { int world_rank; if(::MPI_Comm_rank(MPI_COMM_WORLD, &world_rank) != MPI_SUCCESS) { throw std::runtime_error("Failed to determine own rank"); } return world_rank; } void barrier() { #ifdef MPI_TEST_DEBUG std::cerr << __PRETTY_FUNCTION__ << "\n"; std::cerr << "Entering MPI_Barrier()\n"; #endif // MPI_TEST_DEBUG ::MPI_Barrier(MPI_COMM_WORLD); #ifdef MPI_TEST_DEBUG std::cerr << "Exiting MPI_Barrier()\n"; #endif // MPI_TEST_DEBUG } server_command broadcast_command(server_command cmd) { int c = static_cast<int>(cmd); #ifdef MPI_TEST_DEBUG std::stringstream ss; ss << __PRETTY_FUNCTION__ << "(" << c << ")" << "\n"; std::cerr << ss.str(); std::cerr << "Entering MPI_Bcast()\n"; #endif // MPI_TEST_DEBUG ::MPI_Bcast(&c, 1, MPI_INT, 0, MPI_COMM_WORLD); #ifdef MPI_TEST_DEBUG MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) { std::stringstream ss; ss << "command was " << c << "\n"; std::cerr << ss.str(); } #endif #ifdef MPI_TEST_DEBUG std::cerr << "Exiting MPI_Bcast()\n"; #endif // MPI_TEST_DEBUG return static_cast<server_command>(c); } } // namespace mpi
tests/mpi/mpi-helpers.hpp 0 → 100644 +59 −0 Original line number Diff line number Diff line /************************************************************************* * 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 * * <http://www.gnu.org/licenses/>. * *************************************************************************/ #ifndef MPI_HELPERS_HPP #define MPI_HELPERS_HPP #include <mpi.h> #include "commands.hpp" // #define MPI_TEST_DEBUG namespace mpi { void initialize(int* argc, char** argv[]); void finalize(); int get_rank(); server_command broadcast_command(server_command cmd = server_command::accept); void barrier(); } // namespace mpi #define MPI_RANK_EQ(r) (mpi::get_rank() == r) #define MPI_RANK_NEQ(r) (mpi::get_rank() != r) #define MPI_TEST_RUN_IF(expr) if(expr) #endif // MPI_HELPERS_HPP
tests/mpi/mpi-remote-transfers.cpp +210 −143 Original line number Diff line number Diff line Loading @@ -25,23 +25,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ #include <mpi.h> #include "mpi-helpers.hpp" #include "commands.hpp" #include "norns.h" #include "nornsctl.h" #include "test-env.hpp" #include "catch.hpp" /******************************************************************************/ /* tests for push transfers (single files) */ /******************************************************************************/ SCENARIO("copy local POSIX file to remote POSIX file", "[mpi::norns_submit_push_to_posix_file]") { GIVEN("two running urd instances (local and remote)") { namespace test_data { /**********************************************************************/ /* setup common environment */ /**********************************************************************/ struct { // define input names const bfs::path src_file_at_root = "/file0"; Loading Loading @@ -75,26 +67,89 @@ SCENARIO("copy local POSIX file to remote POSIX file", 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 } test_context; } context; } /******************************************************************************/ /* tests for push transfers (single files) */ /******************************************************************************/ SCENARIO("copy local POSIX file to remote POSIX file", "[mpi::norns_submit_push_to_posix_file]") { using test_data::context; GIVEN("two running urd instances (local and remote)") { /**********************************************************************/ /* setup common environment */ /**********************************************************************/ test_env env(false); const char* remote_host = "127.0.0.1:42000"; // Get the number of processes int world_size; if(MPI_Comm_size(MPI_COMM_WORLD, &world_size) != MPI_SUCCESS) { FAIL("Failed to determine number of processes"); const char* hostname; if((hostname = ::getenv("MPICH_INTERFACE_HOSTNAME")) != NULL) { std::cerr << "hostname" << hostname << "\n"; } // Get the rank of the process int world_rank; if(MPI_Comm_rank(MPI_COMM_WORLD, &world_rank) != MPI_SUCCESS) { FAIL("Failed to determine own rank"); // code for the test servers MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) { bool shutdown = false; do { test_env env(false); std::string nsid("server" + std::to_string(mpi::get_rank())); bfs::path mountdir; // create namespaces std::tie(std::ignore, mountdir) = env.create_namespace(nsid, "mnt/" + nsid, 16384); // create required output directories env.add_to_namespace(nsid, context.dst_subdir1); // sync with client after preparing the test environment mpi::barrier(); bool restart = false; // servers do nothing but wait for client to complete do { int command = 0; server_command cmd = mpi::broadcast_command(); switch(cmd) { case server_command::shutdown: shutdown = true; break; case server_command::restart: restart = true; break; default: continue; } } while(!restart && !shutdown); env.notify_success(); } while(!shutdown); return; }; // MPI_TEST_RUN_IF(MPI_RANK_NEQ(0)) // code for the test client auto client = [world_rank, &env, &test_context] { MPI_TEST_RUN_IF(MPI_RANK_EQ(0)) { test_env env(false); std::string nsid("client"); bfs::path mountdir; Loading @@ -103,118 +158,127 @@ SCENARIO("copy local POSIX file to remote POSIX file", env.create_namespace(nsid, "mnt/" + nsid, 16384); // create input data env.add_to_namespace(nsid, test_context.src_file_at_root, 40000); env.add_to_namespace(nsid, test_context.src_file_at_subdir, 80000); env.add_to_namespace(nsid, test_context.src_subdir0); env.add_to_namespace(nsid, test_context.src_subdir1); env.add_to_namespace(nsid, test_context.src_empty_dir); env.add_to_namespace(nsid, context.src_file_at_root, 40000); env.add_to_namespace(nsid, context.src_file_at_subdir, 80000); env.add_to_namespace(nsid, context.src_subdir0); env.add_to_namespace(nsid, context.src_subdir1); env.add_to_namespace(nsid, context.src_empty_dir); for(int i=0; i<10; ++i) { const bfs::path p{test_context.src_subdir0 / const bfs::path p{context.src_subdir0 / ("file" + std::to_string(i))}; env.add_to_namespace(nsid, p, 4096+i*10); } for(int i=0; i<10; ++i) { const bfs::path p{test_context.src_subdir1 / const bfs::path p{context.src_subdir1 / ("file" + std::to_string(i))}; env.add_to_namespace(nsid, p, 4096+i*10); } // create input data with special permissions auto p = env.add_to_namespace(nsid, test_context.src_noperms_file0, 0); env.add_to_namespace(nsid, context.src_noperms_file0, 0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_file1, 0); p = env.add_to_namespace(nsid, context.src_noperms_file1, 0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_file2, 0); p = env.add_to_namespace(nsid, context.src_noperms_file2, 0); env.remove_access(p.parent_path()); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir0); p = env.add_to_namespace(nsid, context.src_noperms_subdir0); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir1); p = env.add_to_namespace(nsid, context.src_noperms_subdir1); env.remove_access(p); p = env.add_to_namespace(nsid, test_context.src_noperms_subdir2); p = env.add_to_namespace(nsid, context.src_noperms_subdir2); env.remove_access(p.parent_path()); // add symlinks to the namespace env.add_to_namespace(nsid, test_context.src_file_at_root, test_context.src_symlink_at_root0); env.add_to_namespace(nsid, test_context.src_subdir0, test_context.src_symlink_at_root1); env.add_to_namespace(nsid, test_context.src_subdir1, test_context.src_symlink_at_root2); env.add_to_namespace(nsid, test_context.src_file_at_root, test_context.src_symlink_at_subdir0); env.add_to_namespace(nsid, test_context.src_subdir0, test_context.src_symlink_at_subdir1); env.add_to_namespace(nsid, test_context.src_subdir1, test_context.src_symlink_at_subdir2); env.add_to_namespace(nsid, context.src_file_at_root, context.src_symlink_at_root0); env.add_to_namespace(nsid, context.src_subdir0, context.src_symlink_at_root1); env.add_to_namespace(nsid, context.src_subdir1, context.src_symlink_at_root2); env.add_to_namespace(nsid, context.src_file_at_root, context.src_symlink_at_subdir0); env.add_to_namespace(nsid, context.src_subdir0, context.src_symlink_at_subdir1); env.add_to_namespace(nsid, context.src_subdir1, context.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(env.basedir(), mountdir / out_symlink, ec); REQUIRE(!ec); }; // code for the test servers auto server = [world_rank, &env, &test_context] { std::string nsid("server" + std::to_string(world_rank)); bfs::path mountdir; /******************************************************************/ /* 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.* ") { // create namespaces std::tie(std::ignore, mountdir) = env.create_namespace(nsid, "mnt/" + nsid, 16384); norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH("client", context.src_subdir0.c_str()), NORNS_REMOTE_PATH("server1", remote_host, context.dst_root.c_str())); // create required output directories env.add_to_namespace(nsid, test_context.dst_subdir1); }; norns_error_t rv = norns_submit(&task); THEN("norns_submit() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); REQUIRE(task.t_id != 0); // register code std::vector<std::function<void()>> functors; functors.reserve(world_size); // wait until the task completes rv = norns_wait(&task, NULL); functors.push_back(client); THEN("norns_wait() returns NORNS_SUCCESS") { REQUIRE(rv == NORNS_SUCCESS); for(int i = 1; i < world_size; ++i) { functors.push_back(server); } THEN("norns_error() reports NORNS_EFINISHED") { norns_stat_t stats; rv = norns_error(&task, &stats); // run registered code for each process functors.at(world_rank)(); REQUIRE(rv == NORNS_SUCCESS); REQUIRE(stats.st_status == NORNS_EFINISHED); // wait for everyone to finish preparing the test environment MPI_Barrier(MPI_COMM_WORLD); #if 0 THEN("Copied files are identical to original") { bfs::path src = env.get_from_namespace("client", src_subdir0); bfs::path dst = env.get_from_namespace("server1", dst_root); if(world_rank != 0) { // servers do nothing but wait for client to complete MPI_Barrier(MPI_COMM_WORLD); env.notify_success(); return; REQUIRE(compare_directories(src, dst) == true); } #endif } } } } /**********************************************************************/ /* 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.* ") { WHEN("copying the contents of a NORNS_LOCAL_PATH arbitrary subdir " "to DST namespace's root\n" " cp -r /a/b/c/.../contents.* -> / = /contents.*") { ///XXX wrong test case norns_iotask_t task = NORNS_IOTASK(NORNS_IOTASK_COPY, NORNS_LOCAL_PATH("client", test_context.src_subdir0.c_str()), context.src_subdir0.c_str()), NORNS_REMOTE_PATH("server1", remote_host, test_context.dst_root.c_str())); context.dst_root.c_str())); norns_error_t rv = norns_submit(&task); Loading Loading @@ -250,7 +314,10 @@ SCENARIO("copy local POSIX file to remote POSIX file", } } MPI_Barrier(MPI_COMM_WORLD); env.notify_success(); } // MPI_TEST_RUN_IF(MPI_RANK_EQ(0)) } std::cout << "Check!\n"; }