From efbe428d832769f6ddb09e2b9cdba796e196e6af Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Mon, 13 Dec 2010 22:10:32 +0000 Subject: Add some unit tests for the mac MinidumpGenerator R=mark at http://breakpad.appspot.com/240001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@742 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/mac/Breakpad.xcodeproj/project.pbxproj | 41 +++- src/client/mac/handler/minidump_generator_test.cc | 81 ------- src/client/mac/tests/exception_handler_test.cc | 8 +- src/client/mac/tests/minidump_generator_test.cc | 251 ++++++++++++++++++++++ 4 files changed, 291 insertions(+), 90 deletions(-) delete mode 100644 src/client/mac/handler/minidump_generator_test.cc create mode 100644 src/client/mac/tests/minidump_generator_test.cc (limited to 'src') diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj index 3f18a726..6f106aa1 100644 --- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj +++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj @@ -51,6 +51,8 @@ 8B4BDABE12012CEF009C7060 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; }; 8B4BDAC512012D05009C7060 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; + D23F4B2E12A7E13200686C8D /* minidump_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D23F4B2C12A7E13200686C8D /* minidump_generator_test.cc */; }; + D23F4B3312A7E17700686C8D /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9A41512131EF0002747C1 /* libgtest.a */; }; D244536A12426F00009BBCE0 /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535112426EBB009BBCE0 /* logging.cc */; }; D244536B12426F00009BBCE0 /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535212426EBB009BBCE0 /* minidump.cc */; }; D244536C12426F00009BBCE0 /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535312426EBB009BBCE0 /* pathname_stripper.cc */; }; @@ -62,6 +64,10 @@ D2A5DD301188633800081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; }; D2A5DD401188640400081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; }; D2A5DD411188642E00081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; }; + D2C1DBE412AFC270006917BD /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535112426EBB009BBCE0 /* logging.cc */; }; + D2C1DBE512AFC270006917BD /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535212426EBB009BBCE0 /* minidump.cc */; }; + D2C1DBE612AFC270006917BD /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535312426EBB009BBCE0 /* pathname_stripper.cc */; }; + D2C1DBE712AFC270006917BD /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244534F12426E98009BBCE0 /* basic_code_modules.cc */; }; D2F9A3D51212F87C002747C1 /* exception_handler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A3D41212F87C002747C1 /* exception_handler_test.cc */; }; D2F9A43D12131F55002747C1 /* gmock-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A43C12131F55002747C1 /* gmock-all.cc */; }; D2F9A44012131F65002747C1 /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A43E12131F65002747C1 /* gtest_main.cc */; }; @@ -135,7 +141,6 @@ F93803D50F8083B7004D428B /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; }; F93803D60F8083B7004D428B /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; }; F93803D70F8083B7004D428B /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; }; - F93803DA0F8083D8004D428B /* minidump_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F93803D90F8083D8004D428B /* minidump_generator_test.cc */; }; F93DE2D80F82A70E00608B94 /* minidump_file_writer_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = F93DE2D70F82A70E00608B94 /* minidump_file_writer_unittest.cc */; }; F93DE2D90F82A73500608B94 /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C538F0ECCE70A009BE4BA /* minidump_file_writer.cc */; }; F93DE2DA0F82A73500608B94 /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C53870ECCE6C0009BE4BA /* convert_UTF.c */; }; @@ -312,6 +317,13 @@ remoteGlobalIDString = D21F97D211CBA0F200239E38; remoteInfo = test_assembler_unittest; }; + D23F4B2F12A7E16200686C8D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2F9A41412131EF0002747C1; + remoteInfo = gtest; + }; D2F9A44212131F80002747C1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -512,6 +524,7 @@ 8B31FFF611F0C90500FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 8DC2EF5B0486A6940098B216 /* Breakpad.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Breakpad.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D23F4B2C12A7E13200686C8D /* minidump_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_generator_test.cc; path = tests/minidump_generator_test.cc; sourceTree = ""; }; D244534F12426E98009BBCE0 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; }; D244535112426EBB009BBCE0 /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../processor/logging.cc; sourceTree = SOURCE_ROOT; }; D244535212426EBB009BBCE0 /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../processor/minidump.cc; sourceTree = SOURCE_ROOT; }; @@ -602,7 +615,6 @@ F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crash_report_sender.h; path = sender/crash_report_sender.h; sourceTree = ""; }; F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = crash_report_sender.m; path = sender/crash_report_sender.m; sourceTree = ""; }; F93803BE0F80820F004D428B /* generator_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = generator_test; sourceTree = BUILT_PRODUCTS_DIR; }; - F93803D90F8083D8004D428B /* minidump_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_generator_test.cc; path = handler/minidump_generator_test.cc; sourceTree = ""; }; F93DE2D10F82A67300608B94 /* minidump_file_writer_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_file_writer_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; F93DE2D70F82A70E00608B94 /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer_unittest.cc; path = ../minidump_file_writer_unittest.cc; sourceTree = SOURCE_ROOT; }; F93DE32C0F82C55600608B94 /* handler_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = handler_test; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -696,6 +708,7 @@ files = ( 8B31029411F0D54300FCF3E4 /* Foundation.framework in Frameworks */, 8B4BDABE12012CEF009C7060 /* libcrypto.dylib in Frameworks */, + D23F4B3312A7E17700686C8D /* libgtest.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -815,7 +828,6 @@ F92C53590ECCE3BB009BE4BA /* handler */ = { isa = PBXGroup; children = ( - F93803D90F8083D8004D428B /* minidump_generator_test.cc */, F92C53670ECCE3FD009BE4BA /* breakpad_exc_server.c */, F92C53680ECCE3FD009BE4BA /* breakpad_exc_server.h */, F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */, @@ -1009,6 +1021,7 @@ F9C77DDF0F7DD7CF0045F7DB /* tests */ = { isa = PBXGroup; children = ( + D23F4B2C12A7E13200686C8D /* minidump_generator_test.cc */, D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */, D2F9A3D41212F87C002747C1 /* exception_handler_test.cc */, F9C77DE00F7DD7E30045F7DB /* SimpleStringDictionaryTest.h */, @@ -1178,6 +1191,7 @@ buildRules = ( ); dependencies = ( + D23F4B3012A7E16200686C8D /* PBXTargetDependency */, ); name = generator_test; productName = generator_test; @@ -1621,6 +1635,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D2C1DBE412AFC270006917BD /* logging.cc in Sources */, + D2C1DBE512AFC270006917BD /* minidump.cc in Sources */, + D2C1DBE612AFC270006917BD /* pathname_stripper.cc in Sources */, + D2C1DBE712AFC270006917BD /* basic_code_modules.cc in Sources */, D2F9A4DF12133AD9002747C1 /* crash_generation_client.cc in Sources */, D2F9A4E012133AD9002747C1 /* crash_generation_server.cc in Sources */, D24BBD291211EDB100F3D417 /* MachIPC.mm in Sources */, @@ -1636,7 +1654,7 @@ F93803D50F8083B7004D428B /* macho_utilities.cc in Sources */, F93803D60F8083B7004D428B /* macho_walker.cc in Sources */, F93803D70F8083B7004D428B /* string_utilities.cc in Sources */, - F93803DA0F8083D8004D428B /* minidump_generator_test.cc in Sources */, + D23F4B2E12A7E13200686C8D /* minidump_generator_test.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1733,6 +1751,11 @@ name = minidump_upload; targetProxy = 8B31051E11F1010E00FCF3E4 /* PBXContainerItemProxy */; }; + D23F4B3012A7E16200686C8D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2F9A41412131EF0002747C1 /* gtest */; + targetProxy = D23F4B2F12A7E16200686C8D /* PBXContainerItemProxy */; + }; D2F9A44312131F80002747C1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D2F9A41412131EF0002747C1 /* gtest */; @@ -2094,7 +2117,15 @@ F93803C00F808210004D428B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../..; + GCC_PREPROCESSOR_DEFINITIONS = "BP_LOGGING_INCLUDE=\\\"client/mac/tests/testlogging.h\\\""; + HEADER_SEARCH_PATHS = ( + ../.., + ../../.., + ../../testing, + ../../testing/include, + ../../testing/gtest, + ../../testing/gtest/include, + ); PRODUCT_NAME = generator_test; }; name = Debug; diff --git a/src/client/mac/handler/minidump_generator_test.cc b/src/client/mac/handler/minidump_generator_test.cc deleted file mode 100644 index 3a77beb4..00000000 --- a/src/client/mac/handler/minidump_generator_test.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include - -#include -#include - -#include - -#include "minidump_generator.h" -#include "minidump_file_writer.h" - -using std::string; -using google_breakpad::MinidumpGenerator; - -static bool doneWritingReport = false; - -static void *Reporter(void *) { - char buffer[PATH_MAX]; - MinidumpGenerator md; - - // Write it to the desktop - snprintf(buffer, - sizeof(buffer), - "/tmp/test.dmp"); - - - fprintf(stdout, "Writing %s\n", buffer); - unlink(buffer); - md.Write(buffer); - doneWritingReport = true; - - return NULL; -} - -static void SleepyFunction() { - while (!doneWritingReport) { - usleep(100); - } -} - -int main(int argc, char * const argv[]) { - pthread_t reporter_thread; - - if (pthread_create(&reporter_thread, NULL, Reporter, NULL) == 0) { - pthread_detach(reporter_thread); - } else { - perror("pthread_create"); - } - - SleepyFunction(); - - return 0; -} diff --git a/src/client/mac/tests/exception_handler_test.cc b/src/client/mac/tests/exception_handler_test.cc index 004bc8e7..ae2e0513 100644 --- a/src/client/mac/tests/exception_handler_test.cc +++ b/src/client/mac/tests/exception_handler_test.cc @@ -155,7 +155,7 @@ TEST_F(ExceptionHandlerTest, DumpChildProcess) { pid_t pid = fork(); if (pid == 0) { // In the child process - close(fds[0]); + close(fds[1]); // Send parent process the task and thread ports. MachSendMessage child_message(0); @@ -168,12 +168,12 @@ TEST_F(ExceptionHandlerTest, DumpChildProcess) { // Wait for the parent process. uint8_t data; - read(fds[1], &data, 1); + read(fds[0], &data, 1); exit(0); } // In the parent process. ASSERT_NE(-1, pid); - close(fds[1]); + close(fds[0]); // Read the child's task and thread ports. MachReceiveMessage child_message; @@ -200,7 +200,7 @@ TEST_F(ExceptionHandlerTest, DumpChildProcess) { // Unblock child process uint8_t data = 1; - (void)write(fds[0], &data, 1); + (void)write(fds[1], &data, 1); // Child process should have exited with a zero status. int ret; diff --git a/src/client/mac/tests/minidump_generator_test.cc b/src/client/mac/tests/minidump_generator_test.cc new file mode 100644 index 00000000..5d0d5c28 --- /dev/null +++ b/src/client/mac/tests/minidump_generator_test.cc @@ -0,0 +1,251 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// minidump_generator_test.cc: Unit tests for google_breakpad::MinidumpGenerator + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "client/mac/handler/minidump_generator.h" +#include "client/mac/tests/auto_tempdir.h" +#include "common/mac/MachIPC.h" +#include "google_breakpad/processor/minidump.h" + +namespace google_breakpad { +// This acts as the log sink for INFO logging from the processor +// logging code. The logging output confuses XCode and makes it think +// there are unit test failures. testlogging.h handles the overriding. +std::ostringstream info_log; +} + +namespace { +using std::string; +using google_breakpad::AutoTempDir; +using google_breakpad::MinidumpGenerator; +using google_breakpad::MachPortSender; +using google_breakpad::MachReceiveMessage; +using google_breakpad::MachSendMessage; +using google_breakpad::Minidump; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpModule; +using google_breakpad::MinidumpModuleList; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpThread; +using google_breakpad::MinidumpThreadList; +using google_breakpad::ReceivePort; +using testing::Test; + +const MDCPUArchitecture kNativeArchitecture = +#if defined(__i386__) + MD_CPU_ARCHITECTURE_X86 +#elif defined(__x86_64__) + MD_CPU_ARCHITECTURE_AMD64 +#elif defined(__ppc__) || defined(__ppc64__) + MD_CPU_ARCHITECTURE_PPC +#else +#error "This test has not been ported to this CPU architecture." +#endif + ; + +const u_int32_t kNativeContext = +#if defined(__i386__) + MD_CONTEXT_X86 +#elif defined(__x86_64__) + MD_CONTEXT_AMD64 +#elif defined(__ppc__) || defined(__ppc64__) + MD_CONTEXT_PPC +#else +#error "This test has not been ported to this CPU architecture." +#endif + ; + +static string GetExecutablePath() { + char self_path[PATH_MAX]; + uint32_t size = sizeof(self_path); + if (_NSGetExecutablePath(self_path, &size) != 0) + return ""; + return self_path; +} + +class MinidumpGeneratorTest : public Test { + public: + AutoTempDir tempDir; +}; + +static void *Junk(void* data) { + bool* wait = reinterpret_cast(data); + while (!*wait) { + usleep(10000); + } + return NULL; +} + +TEST_F(MinidumpGeneratorTest, InProcess) { + MinidumpGenerator generator; + string dump_filename = MinidumpGenerator::UniqueNameInDirectory(tempDir.path, + NULL); + + // Run an extra thread since MinidumpGenerator assumes there + // are 2 or more threads. + pthread_t junk_thread; + bool quit = false; + ASSERT_EQ(0, pthread_create(&junk_thread, NULL, Junk, &quit)); + + ASSERT_TRUE(generator.Write(dump_filename.c_str())); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(dump_filename.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // join the background thread + quit = true; + pthread_join(junk_thread, NULL); + + // Read the minidump, sanity check some data. + Minidump minidump(dump_filename.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kNativeContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(GetExecutablePath(), main_module->code_file()); +} + +TEST_F(MinidumpGeneratorTest, OutOfProcess) { + const int kTimeoutMs = 2000; + // Create a mach port to receive the child task on. + char machPortName[128]; + sprintf(machPortName, "MinidumpGeneratorTest.%d", getpid()); + ReceivePort parent_recv_port(machPortName); + + // Give the child process a pipe to block on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // Fork off a child process to dump. + pid_t pid = fork(); + if (pid == 0) { + // In the child process + close(fds[1]); + + // Send parent process the task port. + MachSendMessage child_message(0); + child_message.AddDescriptor(mach_task_self()); + + MachPortSender child_sender(machPortName); + if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) { + fprintf(stderr, "Error sending message from child process!\n"); + exit(1); + } + + // Wait for the parent process. + uint8_t data; + read(fds[0], &data, 1); + exit(0); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[0]); + + // Read the child's task port. + MachReceiveMessage child_message; + ASSERT_EQ(KERN_SUCCESS, + parent_recv_port.WaitForMessage(&child_message, kTimeoutMs)); + mach_port_t child_task = child_message.GetTranslatedPort(0); + ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task); + + // Write a minidump of the child process. + MinidumpGenerator generator(child_task, MACH_PORT_NULL); + string dump_filename = MinidumpGenerator::UniqueNameInDirectory(tempDir.path, + NULL); + ASSERT_TRUE(generator.Write(dump_filename.c_str())); + + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(dump_filename.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // Unblock child process + uint8_t data = 1; + (void)write(fds[1], &data, 1); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump, sanity check some data. + Minidump minidump(dump_filename.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kNativeContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(GetExecutablePath(), main_module->code_file()); +} + +} -- cgit v1.2.1