Home | History | Annotate | Download | only in base
      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 
     19 namespace {
     20 
     21 // The name of the environment variable used to pass the crash server pipe name
     22 // to the crashing child process.
     23 const 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.
     28 const wchar_t kPipeNamePrefix[] = L"\\\\.\\pipe\\";
     29 
     30 class 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 
     49 MockCrashServerCallbacks::MockCrashServerCallbacks() {
     50 }
     51 
     52 MockCrashServerCallbacks::~MockCrashServerCallbacks() {
     53 }
     54 
     55 // static
     56 void 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 
     65 namespace remoting {
     66 
     67 void InitializeCrashReportingForTest(const wchar_t* pipe_name);
     68 
     69 class 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 
     82 BreakpadWinDeathTest::BreakpadWinDeathTest() {
     83 }
     84 
     85 BreakpadWinDeathTest::~BreakpadWinDeathTest() {
     86 }
     87 
     88 void 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_ = 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                                     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 
    141 TEST_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 
    150 TEST_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 
    159 TEST_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