1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stdio.h> 6#include <string> 7 8#include "base/compiler_specific.h" 9#include "base/environment.h" 10#include "base/logging.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/strings/stringprintf.h" 13#include "base/strings/utf_string_conversions.h" 14#include "breakpad/src/client/windows/crash_generation/client_info.h" 15#include "breakpad/src/client/windows/crash_generation/crash_generation_server.h" 16#include "testing/gmock/include/gmock/gmock.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace { 20 21// The name of the environment variable used to pass the crash server pipe name 22// to the crashing child process. 23const char kPipeVariableName[] = "REMOTING_BREAKPAD_WIN_DEATH_TEST_PIPE_NAME"; 24 25// The prefix string used to generate a unique crash server pipe name. 26// The name has to be unique as multiple test instances can be running 27// simultaneously. 28const wchar_t kPipeNamePrefix[] = L"\\\\.\\pipe\\"; 29 30class MockCrashServerCallbacks { 31 public: 32 MockCrashServerCallbacks(); 33 virtual ~MockCrashServerCallbacks(); 34 35 // |google_breakpad::CrashGenerationServer| invokes callbacks from artitrary 36 // thread pool threads. |OnClientDumpRequested| is the only one that happened 37 // to be called in synchronous manner. While it is still called on 38 // a thread pool thread, the crashing process will wait until the server 39 // signals an event after |OnClientDumpRequested| completes (or until 15 40 // seconds timeout expires). 41 MOCK_METHOD0(OnClientDumpRequested, void()); 42 43 static void OnClientDumpRequestCallback( 44 void* context, 45 const google_breakpad::ClientInfo* client_info, 46 const std::wstring* file_path); 47}; 48 49MockCrashServerCallbacks::MockCrashServerCallbacks() { 50} 51 52MockCrashServerCallbacks::~MockCrashServerCallbacks() { 53} 54 55// static 56void MockCrashServerCallbacks::OnClientDumpRequestCallback( 57 void* context, 58 const google_breakpad::ClientInfo* /* client_info */, 59 const std::wstring* /* file_path */) { 60 reinterpret_cast<MockCrashServerCallbacks*>(context)->OnClientDumpRequested(); 61} 62 63} // namespace 64 65namespace remoting { 66 67void InitializeCrashReportingForTest(const wchar_t* pipe_name); 68 69class BreakpadWinDeathTest : public testing::Test { 70 public: 71 BreakpadWinDeathTest(); 72 virtual ~BreakpadWinDeathTest(); 73 74 virtual void SetUp() OVERRIDE; 75 76 protected: 77 scoped_ptr<google_breakpad::CrashGenerationServer> crash_server_; 78 scoped_ptr<MockCrashServerCallbacks> callbacks_; 79 std::wstring pipe_name_; 80}; 81 82BreakpadWinDeathTest::BreakpadWinDeathTest() { 83} 84 85BreakpadWinDeathTest::~BreakpadWinDeathTest() { 86} 87 88void BreakpadWinDeathTest::SetUp() { 89 scoped_ptr<base::Environment> environment(base::Environment::Create()); 90 std::string pipe_name; 91 if (environment->GetVar(kPipeVariableName, &pipe_name)) { 92 // This is a child process. Initialize crash dump reporting to the crash 93 // dump server. 94 pipe_name_ = base::UTF8ToWide(pipe_name); 95 InitializeCrashReportingForTest(pipe_name_.c_str()); 96 } else { 97 // This is the parent process. Generate a unique pipe name and setup 98 // a dummy crash dump server. 99 UUID guid = {0}; 100 RPC_STATUS status = UuidCreate(&guid); 101 EXPECT_TRUE(status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY); 102 103 pipe_name_ = 104 base::StringPrintf( 105 L"%ls%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 106 kPipeNamePrefix, 107 guid.Data1, 108 guid.Data2, 109 guid.Data3, 110 guid.Data4[0], 111 guid.Data4[1], 112 guid.Data4[2], 113 guid.Data4[3], 114 guid.Data4[4], 115 guid.Data4[5], 116 guid.Data4[6], 117 guid.Data4[7]); 118 EXPECT_TRUE(environment->SetVar(kPipeVariableName, 119 base::WideToUTF8(pipe_name_))); 120 121 // Setup a dummy crash dump server. 122 callbacks_.reset(new MockCrashServerCallbacks()); 123 crash_server_.reset( 124 new google_breakpad::CrashGenerationServer( 125 pipe_name_, 126 NULL, 127 NULL, 128 NULL, 129 MockCrashServerCallbacks::OnClientDumpRequestCallback, 130 callbacks_.get(), 131 NULL, 132 NULL, 133 NULL, 134 NULL, 135 false, 136 NULL)); 137 ASSERT_TRUE(crash_server_->Start()); 138 } 139} 140 141TEST_F(BreakpadWinDeathTest, TestAccessViolation) { 142 if (callbacks_.get()) { 143 EXPECT_CALL(*callbacks_, OnClientDumpRequested()); 144 } 145 146 // Generate access violation exception. 147 ASSERT_DEATH(*reinterpret_cast<int*>(NULL) = 1, ""); 148} 149 150TEST_F(BreakpadWinDeathTest, TestInvalidParameter) { 151 if (callbacks_.get()) { 152 EXPECT_CALL(*callbacks_, OnClientDumpRequested()); 153 } 154 155 // Cause the invalid parameter callback to be called. 156 ASSERT_EXIT(printf(NULL), testing::ExitedWithCode(0), ""); 157} 158 159TEST_F(BreakpadWinDeathTest, TestDebugbreak) { 160 if (callbacks_.get()) { 161 EXPECT_CALL(*callbacks_, OnClientDumpRequested()); 162 } 163 164 // See if __debugbreak() is intercepted. 165 ASSERT_DEATH(__debugbreak(), ""); 166} 167 168} // namespace remoting 169