Skip to content

Commit d2467ba

Browse files
committed
test: Breakpad Death Tests
Test that with enabled Breakpad crash handling Ceph creates correct minidumps. Signed-off-by: Marcel Lauhoff <[email protected]>
1 parent 92e115f commit d2467ba

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

src/test/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,15 @@ target_link_libraries(test_nvmeof_mon_encoding
10261026
mon ceph-common global-static
10271027
)
10281028

1029+
1030+
if(WITH_BREAKPAD)
1031+
# unittest_ceph_breakpad
1032+
add_executable(unittest_ceph_breakpad
1033+
ceph_breakpad.cc)
1034+
add_ceph_unittest(unittest_ceph_breakpad)
1035+
target_link_libraries(unittest_ceph_breakpad ceph-common global)
1036+
endif()
1037+
10291038
if(NOT WIN32)
10301039
# unittest_ceph_assert
10311040
add_executable(unittest_ceph_assert

src/test/ceph_breakpad.cc

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2+
// vim: ts=8 sw=2 smarttab
3+
/*
4+
* Ceph - scalable distributed file system
5+
*
6+
* Copyright (C) 2025 Clyso GmbH
7+
*
8+
* This is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License version 2.1, as published by the Free Software
11+
* Foundation. See file COPYING.
12+
*
13+
*/
14+
15+
#include <common/Thread.h>
16+
#include <common/ceph_time.h>
17+
#include <include/uuid.h>
18+
19+
#include <csignal>
20+
#include <exception>
21+
#include <filesystem>
22+
#include <fstream>
23+
#include <include/expected.hpp>
24+
#include <ios>
25+
26+
#include "common/ceph_argparse.h"
27+
#include "global/global_context.h"
28+
#include "global/global_init.h"
29+
#include "gtest/gtest.h"
30+
#include "include/ceph_assert.h"
31+
#include <google_breakpad/common/minidump_format.h>
32+
33+
class BreakpadDeathTest : public ::testing::Test {
34+
const std::filesystem::path crash_dir{
35+
g_conf().get_val<std::string>("crash_dir")};
36+
37+
void SetUp() override {
38+
std::filesystem::create_directories(crash_dir);
39+
std::cout << "using crash dir: " << crash_dir << std::endl;
40+
}
41+
42+
void TearDown() override { std::filesystem::remove_all(crash_dir);}
43+
44+
public:
45+
std::optional<std::filesystem::path> minidump() {
46+
for (auto const& dir_entry :
47+
std::filesystem::directory_iterator{crash_dir}) {
48+
if (dir_entry.is_regular_file() &&
49+
dir_entry.path().extension() == ".dmp") {
50+
return dir_entry.path();
51+
}
52+
}
53+
return std::nullopt;
54+
}
55+
56+
void check_minidump() {
57+
const auto md = minidump();
58+
ASSERT_TRUE(md.has_value());
59+
EXPECT_TRUE(std::filesystem::exists(md.value())) << md.value();
60+
61+
std::ifstream in(md.value(), std::ios::binary);
62+
std::array<char, sizeof(MDRawHeader)> buf{0};
63+
in.read(buf.data(), sizeof(MDRawHeader));
64+
65+
const auto* header = reinterpret_cast<MDRawHeader*>(buf.data());
66+
ASSERT_TRUE(header);
67+
EXPECT_EQ(header->signature, MD_HEADER_SIGNATURE);
68+
EXPECT_EQ(header->version, MD_HEADER_VERSION);
69+
EXPECT_GT(header->stream_count, 0);
70+
EXPECT_GT(header->time_date_stamp, 0);
71+
}
72+
73+
std::string expected_minidump_message() {
74+
return "minidump created in path " + crash_dir.string();
75+
}
76+
};
77+
78+
TEST_F(BreakpadDeathTest, CephAbortCreatesMinidump) {
79+
ASSERT_DEATH(ceph_abort(), expected_minidump_message());
80+
check_minidump();
81+
}
82+
83+
TEST_F(BreakpadDeathTest, AbortCreatesMinidump) {
84+
ASSERT_DEATH(abort(), expected_minidump_message());
85+
check_minidump();
86+
}
87+
88+
TEST_F(BreakpadDeathTest, SegfaultCreatesMinidump) {
89+
EXPECT_EXIT(
90+
std::raise(SIGSEGV), testing::KilledBySignal(SIGSEGV),
91+
expected_minidump_message());
92+
check_minidump();
93+
}
94+
95+
TEST_F(BreakpadDeathTest, TerminateCreatesMinidump) {
96+
ASSERT_DEATH(std::terminate(), expected_minidump_message());
97+
check_minidump();
98+
}
99+
100+
int main(int argc, char** argv) {
101+
testing::InitGoogleTest(&argc, argv);
102+
GTEST_FLAG_SET(death_test_style, "threadsafe");
103+
104+
const auto dir =
105+
std::filesystem::temp_directory_path() / "ceph_breakpad_test";
106+
std::map<std::string, std::string> defaults = {
107+
{"breakpad", "true"}, {"crash_dir", dir.string()}};
108+
auto args = argv_to_vec(argc, argv);
109+
auto cct = global_init(
110+
&defaults, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
111+
CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
112+
common_init_finish(g_ceph_context);
113+
return RUN_ALL_TESTS();
114+
}

0 commit comments

Comments
 (0)