Home | History | Annotate | Download | only in unittests
      1 // Copyright 2010, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 #include "testing/include/gmock/gmock.h"
     33 
     34 #include "client/windows/crash_generation/crash_generation_server.h"
     35 #include "client/windows/common/ipc_protocol.h"
     36 
     37 using testing::_;
     38 
     39 namespace {
     40 
     41 const wchar_t kPipeName[] =
     42   L"\\\\.\\pipe\\CrashGenerationServerTest\\TestCaseServer";
     43 
     44 const DWORD kPipeDesiredAccess = FILE_READ_DATA |
     45                                  FILE_WRITE_DATA |
     46                                  FILE_WRITE_ATTRIBUTES;
     47 
     48 const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
     49                                       SECURITY_SQOS_PRESENT;
     50 
     51 const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
     52 
     53 int kCustomInfoCount = 2;
     54 
     55 google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
     56     google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"),
     57     google_breakpad::CustomInfoEntry(L"ver", L"1.0"),
     58 };
     59 
     60 class CrashGenerationServerTest : public ::testing::Test {
     61  public:
     62   CrashGenerationServerTest()
     63       : crash_generation_server_(kPipeName,
     64                                  NULL,
     65                                  CallOnClientConnected, &mock_callbacks_,
     66                                  CallOnClientDumpRequested, &mock_callbacks_,
     67                                  CallOnClientExited, &mock_callbacks_,
     68                                  CallOnClientUploadRequested, &mock_callbacks_,
     69                                  false,
     70                                  NULL),
     71         thread_id_(0),
     72         exception_pointers_(NULL) {
     73     memset(&assert_info_, 0, sizeof(assert_info_));
     74   }
     75 
     76  protected:
     77   class MockCrashGenerationServerCallbacks {
     78    public:
     79     MOCK_METHOD1(OnClientConnected,
     80                  void(const google_breakpad::ClientInfo* client_info));
     81     MOCK_METHOD2(OnClientDumpRequested,
     82                  void(const google_breakpad::ClientInfo* client_info,
     83                       const std::wstring* file_path));
     84     MOCK_METHOD1(OnClientExited,
     85                  void(const google_breakpad::ClientInfo* client_info));
     86     MOCK_METHOD1(OnClientUploadRequested,
     87                  void(const DWORD crash_id));
     88   };
     89 
     90   enum ClientFault {
     91     NO_FAULT,
     92     CLOSE_AFTER_CONNECT,
     93     SEND_INVALID_REGISTRATION,
     94     TRUNCATE_REGISTRATION,
     95     CLOSE_AFTER_REGISTRATION,
     96     RESPONSE_BUFFER_TOO_SMALL,
     97     CLOSE_AFTER_RESPONSE,
     98     SEND_INVALID_ACK
     99   };
    100 
    101   void SetUp() {
    102     ASSERT_TRUE(crash_generation_server_.Start());
    103   }
    104 
    105   void FaultyClient(ClientFault fault_type) {
    106     HANDLE pipe = CreateFile(kPipeName,
    107                              kPipeDesiredAccess,
    108                              0,
    109                              NULL,
    110                              OPEN_EXISTING,
    111                              kPipeFlagsAndAttributes,
    112                              NULL);
    113 
    114     if (pipe == INVALID_HANDLE_VALUE) {
    115       ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError());
    116 
    117       // Cannot continue retrying if wait on pipe fails.
    118       ASSERT_TRUE(WaitNamedPipe(kPipeName, 500));
    119 
    120       pipe = CreateFile(kPipeName,
    121                         kPipeDesiredAccess,
    122                         0,
    123                         NULL,
    124                         OPEN_EXISTING,
    125                         kPipeFlagsAndAttributes,
    126                         NULL);
    127     }
    128 
    129     ASSERT_NE(pipe, INVALID_HANDLE_VALUE);
    130 
    131     DWORD mode = kPipeMode;
    132     ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL));
    133 
    134     DoFaultyClient(fault_type, pipe);
    135 
    136     CloseHandle(pipe);
    137   }
    138 
    139   void DoTestFault(ClientFault fault) {
    140     EXPECT_CALL(mock_callbacks_, OnClientConnected(_)).Times(0);
    141     ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
    142     ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
    143     ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
    144 
    145     EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
    146 
    147     ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
    148 
    149     // Slight hack. The OnClientConnected is only invoked after the ack is
    150     // received by the server. At that point, the FaultyClient call has already
    151     // returned. The best way to wait until the server is done handling that is
    152     // to send one more ping, whose processing will be blocked by delivery of
    153     // the OnClientConnected message.
    154     ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
    155   }
    156 
    157   MockCrashGenerationServerCallbacks mock_callbacks_;
    158 
    159  private:
    160   // Depends on the caller to successfully open the pipe before invocation and
    161   // to close it immediately afterwards.
    162   void DoFaultyClient(ClientFault fault_type, HANDLE pipe) {
    163     if (fault_type == CLOSE_AFTER_CONNECT) {
    164       return;
    165     }
    166 
    167     google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries,
    168                                                      kCustomInfoCount};
    169 
    170     google_breakpad::ProtocolMessage msg(
    171       fault_type == SEND_INVALID_REGISTRATION ?
    172         google_breakpad::MESSAGE_TAG_NONE :
    173         google_breakpad::MESSAGE_TAG_REGISTRATION_REQUEST,
    174       GetCurrentProcessId(),
    175       MiniDumpNormal,
    176       &thread_id_,
    177       &exception_pointers_,
    178       &assert_info_,
    179       custom_info,
    180       NULL,
    181       NULL,
    182       NULL);
    183 
    184     DWORD bytes_count = 0;
    185 
    186     ASSERT_TRUE(WriteFile(pipe,
    187                           &msg,
    188                           fault_type == TRUNCATE_REGISTRATION ?
    189                             sizeof(msg) / 2 : sizeof(msg),
    190                           &bytes_count,
    191                           NULL));
    192 
    193     if (fault_type == CLOSE_AFTER_REGISTRATION) {
    194       return;
    195     }
    196 
    197     google_breakpad::ProtocolMessage reply;
    198 
    199     if (!ReadFile(pipe,
    200                   &reply,
    201                   fault_type == RESPONSE_BUFFER_TOO_SMALL ?
    202                     sizeof(google_breakpad::ProtocolMessage) / 2 :
    203                     sizeof(google_breakpad::ProtocolMessage),
    204                   &bytes_count,
    205                   NULL)) {
    206       switch (fault_type) {
    207         case TRUNCATE_REGISTRATION:
    208         case RESPONSE_BUFFER_TOO_SMALL:
    209         case SEND_INVALID_REGISTRATION:
    210           return;
    211 
    212         default:
    213           FAIL() << "Unexpectedly failed to register.";
    214       }
    215     }
    216 
    217     if (fault_type == CLOSE_AFTER_RESPONSE) {
    218       return;
    219     }
    220 
    221     google_breakpad::ProtocolMessage ack_msg;
    222     ack_msg.tag = google_breakpad::MESSAGE_TAG_REGISTRATION_ACK;
    223 
    224     ASSERT_TRUE(WriteFile(pipe,
    225                           &ack_msg,
    226                           SEND_INVALID_ACK ?
    227                             sizeof(ack_msg) : sizeof(ack_msg) / 2,
    228                           &bytes_count,
    229                           NULL));
    230 
    231     return;
    232   }
    233 
    234   static void CallOnClientConnected(
    235     void* context, const google_breakpad::ClientInfo* client_info) {
    236     static_cast<MockCrashGenerationServerCallbacks*>(context)->
    237       OnClientConnected(client_info);
    238   }
    239 
    240   static void CallOnClientDumpRequested(
    241     void* context,
    242     const google_breakpad::ClientInfo* client_info,
    243     const std::wstring* file_path) {
    244     static_cast<MockCrashGenerationServerCallbacks*>(context)->
    245       OnClientDumpRequested(client_info, file_path);
    246   }
    247 
    248   static void CallOnClientExited(
    249     void* context, const google_breakpad::ClientInfo* client_info) {
    250     static_cast<MockCrashGenerationServerCallbacks*>(context)->
    251       OnClientExited(client_info);
    252   }
    253 
    254   static void CallOnClientUploadRequested(void* context, const DWORD crash_id) {
    255     static_cast<MockCrashGenerationServerCallbacks*>(context)->
    256       OnClientUploadRequested(crash_id);
    257   }
    258 
    259   DWORD thread_id_;
    260   EXCEPTION_POINTERS* exception_pointers_;
    261   MDRawAssertionInfo assert_info_;
    262 
    263   google_breakpad::CrashGenerationServer crash_generation_server_;
    264 };
    265 
    266 TEST_F(CrashGenerationServerTest, PingServerTest) {
    267   DoTestFault(CLOSE_AFTER_CONNECT);
    268 }
    269 
    270 TEST_F(CrashGenerationServerTest, InvalidRegistration) {
    271   DoTestFault(SEND_INVALID_REGISTRATION);
    272 }
    273 
    274 TEST_F(CrashGenerationServerTest, TruncateRegistration) {
    275   DoTestFault(TRUNCATE_REGISTRATION);
    276 }
    277 
    278 TEST_F(CrashGenerationServerTest, CloseAfterRegistration) {
    279   DoTestFault(CLOSE_AFTER_REGISTRATION);
    280 }
    281 
    282 TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) {
    283   DoTestFault(RESPONSE_BUFFER_TOO_SMALL);
    284 }
    285 
    286 TEST_F(CrashGenerationServerTest, CloseAfterResponse) {
    287   DoTestFault(CLOSE_AFTER_RESPONSE);
    288 }
    289 
    290 // It turns out that, as long as you send one byte, the ACK is accepted and
    291 // registration succeeds.
    292 TEST_F(CrashGenerationServerTest, SendInvalidAck) {
    293   EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
    294   ASSERT_NO_FATAL_FAILURE(FaultyClient(SEND_INVALID_ACK));
    295 
    296   // See DoTestFault for an explanation of this line
    297   ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
    298 
    299   EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
    300   ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
    301 
    302   // See DoTestFault for an explanation of this line
    303   ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
    304 }
    305 
    306 }  // anonymous namespace
    307