Index: components/crash/content/app/fallback_crash_handler_win_unittest.cc |
diff --git a/components/crash/content/app/fallback_crash_handler_win_unittest.cc b/components/crash/content/app/fallback_crash_handler_win_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..64b58ef30be13bf58769aadce789ddcac7b0d585 |
--- /dev/null |
+++ b/components/crash/content/app/fallback_crash_handler_win_unittest.cc |
@@ -0,0 +1,164 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
scottmg
2017/01/06 18:29:04
2017
Sigurður Ásgeirsson
2017/01/06 20:59:11
Done.
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/crash/content/app/fallback_crash_handler_win.h" |
+ |
+#include "base/command_line.h" |
+#include "base/files/file_path.h" |
+#include "base/files/scoped_temp_dir.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/threading/platform_thread.h" |
+#include "base/win/scoped_handle.h" |
+#include "base/win/win_util.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/crashpad/crashpad/client/crash_report_database.h" |
+#include "third_party/crashpad/crashpad/client/settings.h" |
+#include "third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h" |
+#include "third_party/crashpad/crashpad/util/file/file_reader.h" |
+#include "third_party/crashpad/crashpad/util/misc/uuid.h" |
+ |
+namespace crash_reporter { |
+ |
+namespace { |
+ |
+class FallbackCrashHandlerWinTest : public testing::Test { |
+ public: |
+ FallbackCrashHandlerWinTest() { |
+ RtlCaptureContext(&ctx_); |
+ memset(&exc_, 0, sizeof(exc_)); |
+ exc_.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; |
+ |
+ exc_ptrs_.ExceptionRecord = &exc_; |
+ exc_ptrs_.ContextRecord = &ctx_; |
+ } |
+ |
+ void SetUp() override { |
+ ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); |
+ |
+ // Open a handle to our own process. |
+ DWORD kAccessMask = |
+ PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE; |
+ self_.Set(OpenProcess(kAccessMask, FALSE, GetCurrentProcessId())); |
+ ASSERT_EQ(ERROR_SUCCESS, GetLastError()); |
+ EXPECT_TRUE(self_.IsValid()); |
+ } |
+ |
+ std::string ExcPtrsAsString() const { |
+ return base::UintToString(reinterpret_cast<uintptr_t>(&exc_ptrs_)); |
+ }; |
+ |
+ std::string ProcessAsString() const { |
+ return base::UintToString(base::win::HandleToUint32(self_.Get())); |
+ }; |
+ |
+ void CreateDatabase() { |
+ std::unique_ptr<crashpad::CrashReportDatabase> database = |
+ crashpad::CrashReportDatabase::InitializeWithoutCreating( |
+ database_dir_.GetPath()); |
+ } |
+ |
+ protected: |
+ CONTEXT ctx_; |
+ EXCEPTION_RECORD exc_; |
+ EXCEPTION_POINTERS exc_ptrs_; |
+ |
+ base::win::ScopedHandle self_; |
+ base::ScopedTempDir database_dir_; |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(FallbackCrashHandlerWinTest, ParseCommandLine) { |
+ FallbackCrashHandler handler; |
+ |
+ // An empty command line shouldn't work. |
+ base::CommandLine cmd_line(base::FilePath(L"empty")); |
+ EXPECT_FALSE(handler.ParseCommandLine(&cmd_line)); |
+ |
+ cmd_line.AppendSwitchPath("database", database_dir_.GetPath()); |
+ cmd_line.AppendSwitchASCII("exception-pointers", ExcPtrsAsString()); |
+ cmd_line.AppendSwitchASCII("process", ProcessAsString()); |
+ |
+ // Thread missing, still should fail. |
+ EXPECT_FALSE(handler.ParseCommandLine(&cmd_line)); |
+ |
+ cmd_line.AppendSwitchASCII( |
+ "thread", base::UintToString(base::PlatformThread::CurrentId())); |
+ |
+ // Should succeed with a fully populated command line. |
+ // Because how handle ownership is guarded, we have to "disown" it before |
+ // the handler takes it over. |
+ self_.Take(); |
+ EXPECT_TRUE(handler.ParseCommandLine(&cmd_line)); |
+} |
+ |
+TEST_F(FallbackCrashHandlerWinTest, GenerateCrashDump) { |
+ FallbackCrashHandler handler; |
+ |
+ base::CommandLine cmd_line(base::FilePath(L"empty")); |
+ cmd_line.AppendSwitchPath("database", database_dir_.GetPath()); |
+ cmd_line.AppendSwitchASCII("exception-pointers", ExcPtrsAsString()); |
+ |
+ // TODO(siggi): It's probably safer to spawn a sacrificial process and then |
+ // terminate it. MinidumpWriteDump is alleged to occasionally hang if used |
+ // to dump own process. |
+ cmd_line.AppendSwitchASCII("process", ProcessAsString()); |
+ cmd_line.AppendSwitchASCII( |
+ "thread", base::UintToString(base::PlatformThread::CurrentId())); |
+ |
+ self_.Take(); |
+ ASSERT_TRUE(handler.ParseCommandLine(&cmd_line)); |
+ EXPECT_TRUE(handler.GenerateCrashDump()); |
+ |
+ // Validate that the database contains one valid crash dump. |
+ std::unique_ptr<crashpad::CrashReportDatabase> database = |
+ crashpad::CrashReportDatabase::InitializeWithoutCreating( |
+ database_dir_.GetPath()); |
+ |
+ std::vector<crashpad::CrashReportDatabase::Report> reports; |
+ ASSERT_EQ(crashpad::CrashReportDatabase::kNoError, |
+ database->GetPendingReports(&reports)); |
+ |
+ EXPECT_EQ(1U, reports.size()); |
+ |
+ // Validate crashpad can read the produced minidump. |
+ crashpad::FileReader minidump_file_reader; |
+ ASSERT_TRUE(minidump_file_reader.Open(reports[0].file_path)); |
+ |
+ crashpad::ProcessSnapshotMinidump minidump_process_snapshot; |
+ ASSERT_TRUE(minidump_process_snapshot.Initialize(&minidump_file_reader)); |
+ |
+ crashpad::UUID expected_client_id; |
+ ASSERT_TRUE(database->GetSettings()->GetClientID(&expected_client_id)); |
+ |
+ // Validate that the CrashpadInfo in the report contains the same basic |
+ // info, as does the database. |
+ crashpad::UUID client_id; |
+ minidump_process_snapshot.ClientID(&client_id); |
+ ASSERT_EQ(expected_client_id, client_id); |
+ |
+ crashpad::UUID report_id; |
+ minidump_process_snapshot.ReportID(&report_id); |
+ ASSERT_EQ(reports[0].uuid, report_id); |
+ |
+ std::map<std::string, std::string> parameters = |
+ minidump_process_snapshot.AnnotationsSimpleMap(); |
+ auto it = parameters.find("prod"); |
+ ASSERT_NE(parameters.end(), it); |
+ // ASSERT_EQ(kExpectedProductName, it->second); |
+ |
+ it = parameters.find("ver"); |
+ ASSERT_NE(parameters.end(), it); |
+ // ASSERT_EQ(kVersion, it->second); |
+ |
+ it = parameters.find("channel"); |
+ ASSERT_NE(parameters.end(), it); |
+ // ASSERT_EQ(kChannel, it->second); |
+ |
+ it = parameters.find("plat"); |
+ ASSERT_NE(parameters.end(), it); |
+ // ASSERT_EQ(kPlatform, it->second); |
+} |
+ |
+} // namespace crash_reporter |