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 <sjust@redhat.com>
This commit is contained in:
Samuel Just 2020-05-04 11:48:10 -07:00
parent 518c43b981
commit 79550342c6
3 changed files with 155 additions and 0 deletions

View File

@ -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<ValuesT...>::get();
}
auto unsafe_get0() {
return seastar::future<ValuesT...>::get0();
}
template <class FuncT>
auto finally(FuncT &&func) {
using func_result_t = std::invoke_result_t<FuncT>;

View File

@ -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;
}

View File

@ -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 <stdio.h>
#include <signal.h>
#include <thread>
#include <seastar/core/app-template.hh>
#include <seastar/core/future-util.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/alien.hh>
#include <seastar/core/thread.hh>
#include "gtest/gtest.h"
struct seastar_gtest_env_t {
seastar::app_template app;
seastar::file_desc begin_fd;
std::unique_ptr<seastar::readable_eventfd> 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 <typename Func>
void run(Func &&func) {
auto fut = seastar::alien::submit_to(0, std::forward<Func>(func));
fut.get();
}
};
struct seastar_test_suite_t : public ::testing::Test {
static seastar_gtest_env_t seastar_env;
template <typename Func>
void run(Func &&func) {
return seastar_env.run(std::forward<Func>(func));
}
template <typename Func>
void run_async(Func &&func) {
run(
[func=std::forward<Func>(func)]() mutable {
return seastar::async(std::forward<Func>(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(); });
}
};