From: Samuel Just Date: Mon, 4 May 2020 18:48:10 +0000 (-0700) Subject: crimson/gtest_seastar: add helpers for building seastar gtest unit tests X-Git-Tag: wip-pdonnell-testing-20200918.022351~1267^2~3 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=79550342c6228d9043fbe732adf63f73780d19bf;p=ceph-ci.git crimson/gtest_seastar: add helpers for building seastar gtest unit tests Also adds unsafe_get methods for errorator for use within unit tests. Signed-off-by: Samuel Just --- diff --git a/src/crimson/common/errorator.h b/src/crimson/common/errorator.h index b0030142ad2..b7a7c8eff00 100644 --- a/src/crimson/common/errorator.h +++ b/src/crimson/common/errorator.h @@ -564,6 +564,23 @@ private: }); } + /** + * unsafe_thread_get + * + * Only valid within a seastar_thread. Ignores errorator protections + * and throws any contained exceptions. + * + * Should really only be used within test code + * (see test/crimson/gtest_seastar.h). + */ + auto &&unsafe_get() { + return seastar::future::get(); + } + auto unsafe_get0() { + return seastar::future::get0(); + } + + template auto finally(FuncT &&func) { using func_result_t = std::invoke_result_t; diff --git a/src/test/crimson/gtest_seastar.cc b/src/test/crimson/gtest_seastar.cc new file mode 100644 index 00000000000..e8d6ae22f73 --- /dev/null +++ b/src/test/crimson/gtest_seastar.cc @@ -0,0 +1,72 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "include/ceph_assert.h" +#include "gtest_seastar.h" + +seastar_gtest_env_t seastar_test_suite_t::seastar_env; + +seastar_gtest_env_t::seastar_gtest_env_t() : + begin_fd{seastar::file_desc::eventfd(0, 0)} {} + +void seastar_gtest_env_t::init(int _argc, char **_argv) +{ + argc = _argc; + argv = new char *[argc]; + for (int i = 0; i < argc; ++i) argv[i] = strdup(_argv[i]); + + thread = std::thread([this] { reactor(); }); + eventfd_t result = 0; + if (int r = ::eventfd_read(begin_fd.get(), &result); r < 0) { + std::cerr << "unable to eventfd_read():" << errno << std::endl; + throw std::runtime_error("Cannot start seastar"); + } +} + +void seastar_gtest_env_t::stop() +{ + run([this] { + on_end->write_side().signal(1); + return seastar::now(); + }); + thread.join(); +} + +seastar_gtest_env_t::~seastar_gtest_env_t() +{ + ceph_assert(argv); + for (int i = 0; i < argc; ++i) free(argv[i]); + delete[] argv; +} + +void seastar_gtest_env_t::reactor() +{ + app.run(argc, argv, [this] { + on_end.reset(new seastar::readable_eventfd); + return seastar::now().then([this] { + ::eventfd_write(begin_fd.get(), 1); + return seastar::now(); + }).then([this] { + return on_end->wait().then([](size_t){}); + }).handle_exception([](auto ep) { + std::cerr << "Error: " << ep << std::endl; + }).finally([this] { + on_end.reset(); + }); + }); +} + +int main(int argc, char **argv) +{ + seastar_test_suite_t::seastar_env.init(argc, argv); + + seastar::global_logger_registry().set_all_loggers_level( + seastar::log_level::debug + ); + + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + + seastar_test_suite_t::seastar_env.stop(); + return ret; +} diff --git a/src/test/crimson/gtest_seastar.h b/src/test/crimson/gtest_seastar.h new file mode 100644 index 00000000000..ed02891f840 --- /dev/null +++ b/src/test/crimson/gtest_seastar.h @@ -0,0 +1,66 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +struct seastar_gtest_env_t { + seastar::app_template app; + seastar::file_desc begin_fd; + std::unique_ptr on_end; + + int argc = 0; + char **argv = nullptr; + std::thread thread; + + seastar_gtest_env_t(); + ~seastar_gtest_env_t(); + + void init(int argc, char **argv); + void stop(); + void reactor(); + + template + void run(Func &&func) { + auto fut = seastar::alien::submit_to(0, std::forward(func)); + fut.get(); + } +}; + +struct seastar_test_suite_t : public ::testing::Test { + static seastar_gtest_env_t seastar_env; + + template + void run(Func &&func) { + return seastar_env.run(std::forward(func)); + } + + template + void run_async(Func &&func) { + run( + [func=std::forward(func)]() mutable { + return seastar::async(std::forward(func)); + }); + } + + virtual seastar::future<> set_up_fut() { return seastar::now(); } + void SetUp() final { + return run([this] { return set_up_fut(); }); + } + + virtual seastar::future<> tear_down_fut() { return seastar::now(); } + void TearDown() final { + return run([this] { return tear_down_fut(); }); + } +};