]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
test: Breakpad Death Tests 61264/head
authorMarcel Lauhoff <marcel.lauhoff@clyso.com>
Fri, 9 May 2025 18:20:30 +0000 (20:20 +0200)
committerMarcel Lauhoff <marcel.lauhoff@clyso.com>
Tue, 13 May 2025 11:35:42 +0000 (13:35 +0200)
Test that with enabled Breakpad crash handling Ceph creates correct
minidumps.

Signed-off-by: Marcel Lauhoff <marcel.lauhoff@clyso.com>
src/test/CMakeLists.txt
src/test/ceph_breakpad.cc [new file with mode: 0644]

index a94826f7ad76105fbcaaea22823e8dd55eaad448..9167ab2a30e5c2138c3d5161658d84f8d5b4ca52 100644 (file)
@@ -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 (file)
index 0000000..fe38198
--- /dev/null
@@ -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 <common/Thread.h>
+#include <common/ceph_time.h>
+#include <include/uuid.h>
+
+#include <csignal>
+#include <exception>
+#include <filesystem>
+#include <fstream>
+#include <include/expected.hpp>
+#include <ios>
+
+#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 <google_breakpad/common/minidump_format.h>
+
+class BreakpadDeathTest : public ::testing::Test {
+  const std::filesystem::path crash_dir{
+      g_conf().get_val<std::string>("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<std::filesystem::path> 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<char, sizeof(MDRawHeader)> buf{0};
+    in.read(buf.data(), sizeof(MDRawHeader));
+
+    const auto* header = reinterpret_cast<MDRawHeader*>(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<std::string, std::string> 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();
+}