From: Lucian Petrut Date: Thu, 19 Dec 2019 13:21:49 +0000 (+0000) Subject: test: port Ceph tests to Windows X-Git-Tag: v16.1.0~69^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=9abf2388f248ae7873e84237df0528d52bc29090;p=ceph.git test: port Ceph tests to Windows We're porting to Windows some of the Ceph tests, mostly related to rados and rbd. Overall, this is about using compat.h functions and types as well as avoiding unsupported functionality. The systest framework will have to be limitted to threads instead of separate processes until we cover the process spawning and communication. Signed-off-by: Lucian Petrut --- diff --git a/src/log/test.cc b/src/log/test.cc index 5549e8d048bc..a2169543b162 100644 --- a/src/log/test.cc +++ b/src/log/test.cc @@ -362,7 +362,7 @@ TEST(Log, GarbleRecovery) log.flush(); log.stop(); struct stat file_status; - ASSERT_EQ(lstat(test_file, &file_status), 0); + ASSERT_EQ(stat(test_file, &file_status), 0); ASSERT_GT(file_status.st_size, 2000); } diff --git a/src/test/admin_socket.cc b/src/test/admin_socket.cc index eeea9c20bdbe..859328d9c78c 100644 --- a/src/test/admin_socket.cc +++ b/src/test/admin_socket.cc @@ -225,20 +225,29 @@ TEST(AdminSocketClient, Ping) { { bool ok; std::string result = client.ping(&ok); +#ifndef _WIN32 +// TODO: convert WSA errors. EXPECT_NE(std::string::npos, result.find("No such file or directory")); +#endif ASSERT_FALSE(ok); } // file exists but does not allow connections (no process, wrong type...) - ASSERT_TRUE(::creat(path.c_str(), 0777)); + int fd = ::creat(path.c_str(), 0777); + ASSERT_TRUE(fd); + // On Windows, we won't be able to remove the file unless we close it + // first. + ASSERT_FALSE(::close(fd)); { bool ok; std::string result = client.ping(&ok); +#ifndef _WIN32 #if defined(__APPLE__) || defined(__FreeBSD__) const char* errmsg = "Socket operation on non-socket"; #else const char* errmsg = "Connection refused"; #endif EXPECT_NE(std::string::npos, result.find(errmsg)); +#endif /* _WIN32 */ ASSERT_FALSE(ok); } // a daemon is connected to the socket @@ -259,7 +268,9 @@ TEST(AdminSocketClient, Ping) { ASSERT_TRUE(asoct.init(path)); bool ok; std::string result = client.ping(&ok); + #ifndef _WIN32 EXPECT_NE(std::string::npos, result.find("Resource temporarily unavailable")); + #endif ASSERT_FALSE(ok); { std::lock_guard l{blocking->_lock}; @@ -282,18 +293,22 @@ TEST(AdminSocket, bind_and_listen) { message = asoct.bind_and_listen(path, &fd); ASSERT_NE(0, fd); ASSERT_EQ("", message); - ASSERT_EQ(0, ::close(fd)); + ASSERT_EQ(0, ::compat_closesocket(fd)); ASSERT_EQ(0, ::unlink(path.c_str())); } // silently discard an existing file { int fd = 0; string message; - ASSERT_TRUE(::creat(path.c_str(), 0777)); + int fd2 = ::creat(path.c_str(), 0777); + ASSERT_TRUE(fd2); + // On Windows, we won't be able to remove the file unless we close it + // first. + ASSERT_FALSE(::close(fd2)); message = asoct.bind_and_listen(path, &fd); ASSERT_NE(0, fd); ASSERT_EQ("", message); - ASSERT_EQ(0, ::close(fd)); + ASSERT_EQ(0, ::compat_closesocket(fd)); ASSERT_EQ(0, ::unlink(path.c_str())); } // do not take over a live socket diff --git a/src/test/admin_socket_output_tests.cc b/src/test/admin_socket_output_tests.cc index f91a186b834c..5125a7db271c 100644 --- a/src/test/admin_socket_output_tests.cc +++ b/src/test/admin_socket_output_tests.cc @@ -42,7 +42,7 @@ bool test_dump_pgstate_history(std::string &output) { return false; } - uint total = 0; + unsigned int total = 0; if ((*iterone)->get_name() == "pgs") { JSONObjIter iter = (*(*iterone)->find_first())->find_first(); for (; !iter.end(); ++iter) { diff --git a/src/test/bufferlist.cc b/src/test/bufferlist.cc index 37bacee1c61e..74d23de0bc18 100644 --- a/src/test/bufferlist.cc +++ b/src/test/bufferlist.cc @@ -25,6 +25,7 @@ #include "include/buffer.h" #include "include/buffer_raw.h" +#include "include/compat.h" #include "include/utime.h" #include "include/coredumpctl.h" #include "include/encoding.h" @@ -2298,13 +2299,17 @@ TEST(BufferList, read_file) { bufferlist bl; ::unlink(FILENAME); EXPECT_EQ(-ENOENT, bl.read_file("UNLIKELY", &error)); - snprintf(cmd, sizeof(cmd), "echo ABC > %s ; chmod 0 %s", FILENAME, FILENAME); + snprintf(cmd, sizeof(cmd), "echo ABC> %s", FILENAME); + EXPECT_EQ(0, ::system(cmd)); + #ifndef _WIN32 + snprintf(cmd, sizeof(cmd), "chmod 0 %s", FILENAME); EXPECT_EQ(0, ::system(cmd)); if (getuid() != 0) { EXPECT_EQ(-EACCES, bl.read_file(FILENAME, &error)); } snprintf(cmd, sizeof(cmd), "chmod +r %s", FILENAME); EXPECT_EQ(0, ::system(cmd)); + #endif /* _WIN32 */ EXPECT_EQ(0, bl.read_file(FILENAME, &error)); ::unlink(FILENAME); EXPECT_EQ((unsigned)4, bl.length()); @@ -2339,7 +2344,9 @@ TEST(BufferList, write_file) { struct stat st; memset(&st, 0, sizeof(st)); ASSERT_EQ(0, ::stat(FILENAME, &st)); + #ifndef _WIN32 EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode); + #endif ::unlink(FILENAME); } diff --git a/src/test/ceph_crypto.cc b/src/test/ceph_crypto.cc index 09c0df37eb90..477d0c0db75d 100644 --- a/src/test/ceph_crypto.cc +++ b/src/test/ceph_crypto.cc @@ -268,11 +268,11 @@ void do_simple_crypto() { exit(0); } -#if GTEST_HAS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST && !defined(_WIN32) TEST_F(ForkDeathTest, MD5) { ASSERT_EXIT(do_simple_crypto(), ::testing::ExitedWithCode(0), "^$"); } -#endif //GTEST_HAS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST && !defined(_WIN32) int main(int argc, char **argv) { std::vector args(argv, argv + argc); diff --git a/src/test/common/test_hostname.cc b/src/test/common/test_hostname.cc index 4f9aeef4d29d..b0e631d20874 100644 --- a/src/test/common/test_hostname.cc +++ b/src/test/common/test_hostname.cc @@ -62,6 +62,10 @@ TEST(Hostname, short) { << ", skipping test because env var may or may not be short form" << std::endl; } else { - ASSERT_EQ(shn, exec("hostname -s")) ; + #ifdef _WIN32 + ASSERT_EQ(shn, exec("hostname")); + #else + ASSERT_EQ(shn, exec("hostname -s")); + #endif } } diff --git a/src/test/confutils.cc b/src/test/confutils.cc index 88e5bf450ac4..a46d347d9b10 100644 --- a/src/test/confutils.cc +++ b/src/test/confutils.cc @@ -17,6 +17,14 @@ #include "gtest/gtest.h" #include "include/buffer.h" +#if __has_include() +#include +namespace fs = std::filesystem; +#elif __has_include() +#include +namespace fs = std::experimental::filesystem; +#endif + #include #include #include @@ -47,10 +55,14 @@ static std::string get_temp_dir() ostringstream oss; oss << tmpdir << "/confutils_test_dir." << rand() << "." << getpid(); umask(022); - int res = mkdir(oss.str().c_str(), 01777); - if (res) { - cerr << "failed to create temp directory '" << temp_dir << "'" << std::endl; - return ""; + if (!fs::exists(oss.str())) { + std::error_code ec; + if (!fs::create_directory(oss.str(), ec)) { + cerr << "failed to create temp directory '" << temp_dir << "' " + << ec.message() << std::endl; + return ""; + } + fs::permissions(oss.str(), fs::perms::sticky_bit | fs::perms::all); } temp_dir = oss.str(); } diff --git a/src/test/lazy-omap-stats/lazy_omap_stats_test.cc b/src/test/lazy-omap-stats/lazy_omap_stats_test.cc index dd461429f300..87084e941bd6 100644 --- a/src/test/lazy-omap-stats/lazy_omap_stats_test.cc +++ b/src/test/lazy-omap-stats/lazy_omap_stats_test.cc @@ -26,6 +26,7 @@ #include #include "lazy_omap_stats_test.h" +#include "include/compat.h" using namespace std; namespace bp = boost::process; diff --git a/src/test/lazy-omap-stats/lazy_omap_stats_test.h b/src/test/lazy-omap-stats/lazy_omap_stats_test.h index 28e194441e1c..020c72c7358a 100644 --- a/src/test/lazy-omap-stats/lazy_omap_stats_test.h +++ b/src/test/lazy-omap-stats/lazy_omap_stats_test.h @@ -19,6 +19,7 @@ #include #include +#include "include/compat.h" #include "include/rados/librados.hpp" struct index_t { diff --git a/src/test/librados/misc.cc b/src/test/librados/misc.cc index 8d22244d3264..bffab46cbe1f 100644 --- a/src/test/librados/misc.cc +++ b/src/test/librados/misc.cc @@ -17,7 +17,9 @@ #include "test/librados/TestCase.h" #include "gtest/gtest.h" #include +#ifndef _WIN32 #include +#endif #include #include @@ -328,6 +330,7 @@ static void shutdown_racer_func() } } +#ifndef _WIN32 // See trackers #20988 and #42026 TEST_F(LibRadosMisc, ShutdownRace) { @@ -348,3 +351,4 @@ TEST_F(LibRadosMisc, ShutdownRace) threads[i].join(); ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rold), 0); } +#endif /* _WIN32 */ diff --git a/src/test/librados/test_shared.h b/src/test/librados/test_shared.h index 3c8ce7ed88ff..6f3747e7b41c 100644 --- a/src/test/librados/test_shared.h +++ b/src/test/librados/test_shared.h @@ -19,12 +19,21 @@ void assert_eq_sparse(ceph::bufferlist& expected, class TestAlarm { public: + #ifndef _WIN32 TestAlarm() { alarm(1200); } ~TestAlarm() { alarm(0); } + #else + // TODO: add a timeout mechanism for Windows as well, possibly by using + // CreateTimerQueueTimer. + TestAlarm() { + } + ~TestAlarm() { + } + #endif }; template -#include #include #include #include #include "common/debug.h" #include "include/ceph_assert.h" +#include "include/dlfcn_compat.h" #define dout_context g_ceph_context #define dout_subsys ceph_subsys_rados @@ -35,16 +35,12 @@ void TestClassHandler::open_class(const std::string& name, return; } - // clear any existing error - dlerror(); - // initialize void (*cls_init)() = reinterpret_cast( dlsym(handle, "__cls_init")); - char* error = nullptr; - if ((error = dlerror()) != nullptr) { - std::cerr << "Error locating initializer: " << error << std::endl; + if (!cls_init) { + std::cerr << "Error locating initializer: " << dlerror() << std::endl; } else if (cls_init) { m_class_handles.push_back(handle); cls_init(); @@ -71,7 +67,7 @@ void TestClassHandler::open_all_classes() { while ((pde = ::readdir(dir))) { std::string name(pde->d_name); if (!boost::algorithm::starts_with(name, "libcls_") || - !boost::algorithm::ends_with(name, ".so")) { + !boost::algorithm::ends_with(name, SHARED_LIB_SUFFIX)) { continue; } names.insert(name); diff --git a/src/test/librbd/fsx.cc b/src/test/librbd/fsx.cc index 1b86e2a74137..b8be4708e2d0 100644 --- a/src/test/librbd/fsx.cc +++ b/src/test/librbd/fsx.cc @@ -25,11 +25,13 @@ #endif #include #include +#ifndef _WIN32 #include +#include +#endif #if defined(__linux__) #include #endif -#include #ifdef HAVE_ERR_H #include #endif @@ -132,7 +134,7 @@ int logcount = 0; /* total ops */ #define OP_SKIPPED 101 #undef PAGE_SIZE -#define PAGE_SIZE getpagesize() +#define PAGE_SIZE get_page_size() #undef PAGE_MASK #define PAGE_MASK (PAGE_SIZE - 1) @@ -3070,7 +3072,7 @@ main(int argc, char **argv) goodfile[0] = 0; logfile[0] = 0; - page_size = getpagesize(); + page_size = PAGE_SIZE; page_mask = page_size - 1; mmap_mask = page_mask; @@ -3271,7 +3273,9 @@ main(int argc, char **argv) fprintf(stdout, "mapped writes DISABLED\n"); break; case 'Z': + #ifdef O_DIRECT o_direct = O_DIRECT; + #endif break; default: usage(); @@ -3285,6 +3289,7 @@ main(int argc, char **argv) pool = argv[0]; iname = argv[1]; + #ifndef _WIN32 signal(SIGHUP, cleanup); signal(SIGINT, cleanup); signal(SIGPIPE, cleanup); @@ -3295,6 +3300,7 @@ main(int argc, char **argv) signal(SIGVTALRM, cleanup); signal(SIGUSR1, cleanup); signal(SIGUSR2, cleanup); + #endif random_generator.seed(seed); diff --git a/src/test/system/cross_process_sem.cc b/src/test/system/cross_process_sem.cc index 93f10cbeae68..7438b8827815 100644 --- a/src/test/system/cross_process_sem.cc +++ b/src/test/system/cross_process_sem.cc @@ -17,7 +17,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif #include "include/ceph_assert.h" @@ -36,6 +38,7 @@ struct cross_process_sem_data_t int CrossProcessSem:: create(int initial_val, CrossProcessSem** res) { + #ifndef _WIN32 struct cross_process_sem_data_t *data = static_cast < cross_process_sem_data_t*> ( mmap(NULL, sizeof(struct cross_process_sem_data_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)); @@ -43,6 +46,11 @@ create(int initial_val, CrossProcessSem** res) int err = errno; return err; } + #else + // We can't use multiple processes on Windows for the time being. + struct cross_process_sem_data_t *data = (cross_process_sem_data_t*)malloc( + sizeof(cross_process_sem_data_t)); + #endif /* _WIN32 */ int ret = sem_init(&data->sem, 1, initial_val); if (ret) { return ret; @@ -54,7 +62,11 @@ create(int initial_val, CrossProcessSem** res) CrossProcessSem:: ~CrossProcessSem() { + #ifndef _WIN32 munmap(m_data, sizeof(struct cross_process_sem_data_t)); + #else + free(m_data); + #endif m_data = NULL; } diff --git a/src/test/system/st_rados_create_pool.cc b/src/test/system/st_rados_create_pool.cc index 9188fafc6006..a802d9da4f4a 100644 --- a/src/test/system/st_rados_create_pool.cc +++ b/src/test/system/st_rados_create_pool.cc @@ -13,6 +13,7 @@ */ #include "cross_process_sem.h" +#include "include/ceph_assert.h" #include "include/rados/librados.h" #include "st_rados_create_pool.h" #include "systest_runnable.h" diff --git a/src/test/system/systest_runnable.cc b/src/test/system/systest_runnable.cc index 98cb1741a776..f7342aa7ded0 100644 --- a/src/test/system/systest_runnable.cc +++ b/src/test/system/systest_runnable.cc @@ -25,9 +25,11 @@ #include #include #include +#ifndef _WIN32 #include -#include #include +#endif +#include #include #include #include @@ -40,6 +42,8 @@ static pid_t do_gettid(void) { #if defined(__linux__) return static_cast < pid_t >(syscall(SYS_gettid)); +#elif defined(_WIN32) + return static_cast < pid_t >(GetCurrentThreadId()); #else return static_cast < pid_t >(pthread_getthreadid_np()); #endif @@ -87,6 +91,10 @@ start() return ret; m_started = true; } else { + #ifdef _WIN32 + printf("Using separate processes is not supported on Windows.\n"); + return -1; + #else std::string err_msg; ret = preforker.prefork(err_msg); if (ret < 0) @@ -99,6 +107,7 @@ start() } else { m_started = true; } + #endif } return 0; } @@ -127,9 +136,13 @@ join() } return ""; } else { + #ifdef _WIN32 + return "Using separate processes is not supported on Windows.\n"; + #else std::string err_msg; ret = preforker.parent_wait(err_msg); return err_msg; + #endif } } diff --git a/src/test/system/systest_runnable.h b/src/test/system/systest_runnable.h index 72da4f4c1047..bfa9130ed752 100644 --- a/src/test/system/systest_runnable.h +++ b/src/test/system/systest_runnable.h @@ -20,7 +20,9 @@ #include #include +#ifndef _WIN32 #include "common/Preforker.h" +#endif #define RETURN1_IF_NOT_VAL(expected, expr) \ do {\ @@ -79,7 +81,9 @@ private: friend void* systest_runnable_pthread_helper(void *arg); + #ifndef _WIN32 Preforker preforker; + #endif const char **m_argv_orig; bool m_started; int m_id; diff --git a/src/test/system/systest_settings.cc b/src/test/system/systest_settings.cc index b1d14a259bf6..787d763fedc7 100644 --- a/src/test/system/systest_settings.cc +++ b/src/test/system/systest_settings.cc @@ -33,7 +33,14 @@ inst() bool SysTestSettings:: use_threads() const { + #ifdef _WIN32 + // We can't use multiple processes on Windows for the time being. + // We'd need a mechanism for spawning those procecesses and also handle + // the inter-process communication. + return true; + #else return m_use_threads; + #endif } std::string SysTestSettings:: diff --git a/src/test/test_subprocess.cc b/src/test/test_subprocess.cc index c316eb58a129..f2adf51cb9e8 100644 --- a/src/test/test_subprocess.cc +++ b/src/test/test_subprocess.cc @@ -23,6 +23,14 @@ #include "gtest/gtest.h" #include "common/fork_function.h" +#ifdef _WIN32 +// Some of the tests expect GNU binaries to be available. We'll just rely on +// the ones provided by Msys (which also comes with Git for Windows). +#define SHELL "bash.exe" +#else +#define SHELL "/bin/sh" +#endif + bool read_from_fd(int fd, std::string &out) { out.clear(); char buf[1024]; @@ -53,6 +61,10 @@ TEST(SubProcess, False) TEST(SubProcess, NotFound) { SubProcess p("NOTEXISTENTBINARY", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::PIPE); + #ifdef _WIN32 + // Windows will error out early. + ASSERT_EQ(p.spawn(), -1); + #else ASSERT_EQ(p.spawn(), 0); std::string buf; ASSERT_TRUE(read_from_fd(p.get_stderr(), buf)); @@ -60,6 +72,7 @@ TEST(SubProcess, NotFound) ASSERT_EQ(p.join(), 1); std::cerr << "err: " << p.err() << std::endl; ASSERT_FALSE(p.err().c_str()[0] == '\0'); + #endif } TEST(SubProcess, Echo) @@ -121,6 +134,7 @@ TEST(SubProcess, Killed) ASSERT_FALSE(cat.err().c_str()[0] == '\0'); } +#ifndef _WIN32 TEST(SubProcess, CatWithArgs) { SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); @@ -142,15 +156,16 @@ TEST(SubProcess, CatWithArgs) std::cerr << "err: " << cat.err() << std::endl; ASSERT_FALSE(cat.err().c_str()[0] == '\0'); } +#endif TEST(SubProcess, Subshell) { - SubProcess sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); + SubProcess sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); sh.add_cmd_args("-c", "sleep 0; " "cat; " "echo 'error from subshell' >&2; " - "/bin/sh -c 'exit 13'", NULL); + SHELL " -c 'exit 13'", NULL); ASSERT_EQ(sh.spawn(), 0); std::string msg("hello via subshell"); int n = write(sh.get_stdin(), msg.c_str(), msg.size()); @@ -210,8 +225,10 @@ TEST(SubProcessTimed, SleepTimedout) ASSERT_EQ(sleep.spawn(), 0); std::string buf; ASSERT_TRUE(read_from_fd(sleep.get_stderr(), buf)); + #ifndef _WIN32 std::cerr << "stderr: " << buf; ASSERT_FALSE(buf.empty()); + #endif ASSERT_EQ(sleep.join(), 128 + SIGKILL); std::cerr << "err: " << sleep.err() << std::endl; ASSERT_FALSE(sleep.err().c_str()[0] == '\0'); @@ -219,7 +236,7 @@ TEST(SubProcessTimed, SleepTimedout) TEST(SubProcessTimed, SubshellNoTimeout) { - SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 0); + SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 0); sh.add_cmd_args("-c", "cat >&2", NULL); ASSERT_EQ(sh.spawn(), 0); std::string msg("the quick brown fox jumps over the lazy dog"); @@ -239,8 +256,8 @@ TEST(SubProcessTimed, SubshellNoTimeout) TEST(SubProcessTimed, SubshellKilled) { - SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 10); - sh.add_cmd_args("-c", "sh -c cat", NULL); + SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 10); + sh.add_cmd_args("-c", SHELL "-c cat", NULL); ASSERT_EQ(sh.spawn(), 0); std::string msg("etaoin shrdlu"); int n = write(sh.get_stdin(), msg.c_str(), msg.size()); @@ -256,18 +273,21 @@ TEST(SubProcessTimed, SubshellKilled) TEST(SubProcessTimed, SubshellTimedout) { - SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 1, SIGTERM); + SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 1, SIGTERM); sh.add_cmd_args("-c", "sleep 1000& cat; NEVER REACHED", NULL); ASSERT_EQ(sh.spawn(), 0); std::string buf; + #ifndef _WIN32 ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf)); std::cerr << "stderr: " << buf; ASSERT_FALSE(buf.empty()); + #endif ASSERT_EQ(sh.join(), 128 + SIGTERM); std::cerr << "err: " << sh.err() << std::endl; ASSERT_FALSE(sh.err().c_str()[0] == '\0'); } +#ifndef _WIN32 TEST(fork_function, normal) { ASSERT_EQ(0, fork_function(10, std::cerr, [&]() { return 0; })); @@ -291,3 +311,4 @@ TEST(fork_function, timeout) sleep(60); return -111; })); } +#endif