| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. |
| |
| #include "src/developer/forensics/exceptions/handler/report_builder.h" |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/developer/forensics/exceptions/tests/crasher_wrapper.h" |
| #include "src/lib/fsl/vmo/strings.h" |
| |
| namespace forensics { |
| namespace exceptions { |
| namespace handler { |
| namespace { |
| |
| class CrashReportBuilderTest : public testing::Test { |
| protected: |
| // Use an invalid process/thread becuase we don't care about the specific name and koid of each. |
| void SetUp() { builder_.SetProcess(zx::process{}).SetThread(zx::thread{}); } |
| |
| CrashReportBuilder builder_; |
| }; |
| |
| TEST_F(CrashReportBuilderTest, SetsMinidump) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_specific_report()); |
| ASSERT_TRUE(crash_report.specific_report().is_native()); |
| |
| std::string minidump_content; |
| ASSERT_TRUE( |
| fsl::StringFromVmo(crash_report.specific_report().native().minidump(), &minidump_content)); |
| EXPECT_STREQ(minidump_content.c_str(), "minidump"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_ChannelOverflow) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kChannelOverflow); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-unknown_process-channel-overflow"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_PortObserverOverflow) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kPortObserverOverflow); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-unknown_process-port-observer-overflow"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_PortPacketOverflow) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kPortPacketOverflow); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-unknown_process-port-packet-overflow"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_PageFaultIo) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kPageFaultIo); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-page_fault-io"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_PageFaultIoDataIntegrity) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kPageFaultIoDataIntegrity); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-page_fault-io_data_integrity"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExceptionReason_PageFaultBadState) { |
| fsl::SizedVmo minidump_vmo; |
| ASSERT_TRUE(fsl::VmoFromString("minidump", &minidump_vmo)); |
| |
| builder_.SetMinidump(std::move(minidump_vmo.vmo())) |
| .SetExceptionReason(ExceptionReason::kPageFaultBadState); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-page_fault-bad_state"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ProcessTerminated) { |
| builder_.SetProcessTerminated(); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_specific_report()); |
| |
| ASSERT_TRUE(crash_report.has_program_name()); |
| ASSERT_EQ(crash_report.program_name(), "unknown_process"); |
| |
| ASSERT_FALSE(crash_report.has_program_uptime()); |
| |
| ASSERT_TRUE(crash_report.specific_report().is_native()); |
| EXPECT_FALSE(crash_report.specific_report().native().has_minidump()); |
| |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-no-minidump-process-terminated"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, ExpiredException) { |
| builder_.SetExceptionExpired(); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_specific_report()); |
| |
| ASSERT_TRUE(crash_report.specific_report().is_native()); |
| EXPECT_FALSE(crash_report.specific_report().native().has_minidump()); |
| |
| ASSERT_TRUE(crash_report.has_crash_signature()); |
| EXPECT_EQ(crash_report.crash_signature(), "fuchsia-no-minidump-exception-expired"); |
| } |
| |
| TEST_F(CrashReportBuilderTest, IsFatal) { |
| builder_.SetExceptionExpired(); |
| |
| auto crash_report = builder_.Consume(); |
| ASSERT_TRUE(crash_report.has_is_fatal()); |
| EXPECT_TRUE(crash_report.is_fatal()); |
| } |
| |
| TEST(ReportBuilderTest, TestUptime) { |
| CrashReportBuilder builder; |
| ExceptionContext exception; |
| |
| // Spawn the 'crasher' process. |
| ASSERT_TRUE(SpawnCrasher(&exception)); |
| // If we don't mark it as handled, the exception will bubble out of our environment. |
| ASSERT_TRUE(MarkExceptionAsHandled(&exception)); |
| |
| zx::process process; |
| zx::thread thread; |
| ASSERT_EQ(exception.exception.get_process(&process), ZX_OK); |
| ASSERT_EQ(exception.exception.get_thread(&thread), ZX_OK); |
| builder.SetProcess(process).SetThread(thread); |
| builder.SetProcessTerminated(); |
| |
| auto crash_report = builder.Consume(); |
| ASSERT_TRUE(crash_report.has_program_name()); |
| ASSERT_EQ(crash_report.program_name(), "crasher"); |
| ASSERT_TRUE(crash_report.has_program_uptime()); |
| ASSERT_GE(crash_report.program_uptime(), 0); |
| |
| // We kill the jobs. This kills the underlying process. We do this so that the crashed process |
| // doesn't get rescheduled. Otherwise the exception on the crash program would bubble out of our |
| // environment and create noise on the overall system. |
| exception.job.kill(); |
| } |
| |
| } // namespace |
| } // namespace handler |
| } // namespace exceptions |
| } // namespace forensics |