From d2467bac505f2d7234e8d7c4a8031e86d49a1c42 Mon Sep 17 00:00:00 2001 From: Marcel Lauhoff Date: Fri, 9 May 2025 20:20:30 +0200 Subject: [PATCH] test: Breakpad Death Tests Test that with enabled Breakpad crash handling Ceph creates correct minidumps. Signed-off-by: Marcel Lauhoff --- src/test/CMakeLists.txt | 9 +++ src/test/ceph_breakpad.cc | 114 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/test/ceph_breakpad.cc diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index a94826f7ad7..9167ab2a30e 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1026,6 +1026,15 @@ target_link_libraries(test_nvmeof_mon_encoding mon ceph-common global-static ) + +if(WITH_BREAKPAD) +# unittest_ceph_breakpad +add_executable(unittest_ceph_breakpad + ceph_breakpad.cc) +add_ceph_unittest(unittest_ceph_breakpad) +target_link_libraries(unittest_ceph_breakpad ceph-common global) +endif() + if(NOT WIN32) # unittest_ceph_assert add_executable(unittest_ceph_assert diff --git a/src/test/ceph_breakpad.cc b/src/test/ceph_breakpad.cc new file mode 100644 index 00000000000..fe381982148 --- /dev/null +++ b/src/test/ceph_breakpad.cc @@ -0,0 +1,114 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2025 Clyso GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common/ceph_argparse.h" +#include "global/global_context.h" +#include "global/global_init.h" +#include "gtest/gtest.h" +#include "include/ceph_assert.h" +#include + +class BreakpadDeathTest : public ::testing::Test { + const std::filesystem::path crash_dir{ + g_conf().get_val("crash_dir")}; + + void SetUp() override { + std::filesystem::create_directories(crash_dir); + std::cout << "using crash dir: " << crash_dir << std::endl; + } + + void TearDown() override { std::filesystem::remove_all(crash_dir);} + + public: + std::optional minidump() { + for (auto const& dir_entry : + std::filesystem::directory_iterator{crash_dir}) { + if (dir_entry.is_regular_file() && + dir_entry.path().extension() == ".dmp") { + return dir_entry.path(); + } + } + return std::nullopt; + } + + void check_minidump() { + const auto md = minidump(); + ASSERT_TRUE(md.has_value()); + EXPECT_TRUE(std::filesystem::exists(md.value())) << md.value(); + + std::ifstream in(md.value(), std::ios::binary); + std::array buf{0}; + in.read(buf.data(), sizeof(MDRawHeader)); + + const auto* header = reinterpret_cast(buf.data()); + ASSERT_TRUE(header); + EXPECT_EQ(header->signature, MD_HEADER_SIGNATURE); + EXPECT_EQ(header->version, MD_HEADER_VERSION); + EXPECT_GT(header->stream_count, 0); + EXPECT_GT(header->time_date_stamp, 0); + } + + std::string expected_minidump_message() { + return "minidump created in path " + crash_dir.string(); + } +}; + +TEST_F(BreakpadDeathTest, CephAbortCreatesMinidump) { + ASSERT_DEATH(ceph_abort(), expected_minidump_message()); + check_minidump(); +} + +TEST_F(BreakpadDeathTest, AbortCreatesMinidump) { + ASSERT_DEATH(abort(), expected_minidump_message()); + check_minidump(); +} + +TEST_F(BreakpadDeathTest, SegfaultCreatesMinidump) { + EXPECT_EXIT( + std::raise(SIGSEGV), testing::KilledBySignal(SIGSEGV), + expected_minidump_message()); + check_minidump(); +} + +TEST_F(BreakpadDeathTest, TerminateCreatesMinidump) { + ASSERT_DEATH(std::terminate(), expected_minidump_message()); + check_minidump(); +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); + + const auto dir = + std::filesystem::temp_directory_path() / "ceph_breakpad_test"; + std::map defaults = { + {"breakpad", "true"}, {"crash_dir", dir.string()}}; + auto args = argv_to_vec(argc, argv); + auto cct = global_init( + &defaults, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, + CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); + common_init_finish(g_ceph_context); + return RUN_ALL_TESTS(); +} -- 2.39.5