• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CrashGenerationServerTest()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 
SetUp()101   void SetUp() {
102     ASSERT_TRUE(crash_generation_server_.Start());
103   }
104 
FaultyClient(ClientFault fault_type)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 
DoTestFault(ClientFault fault)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.
DoFaultyClient(ClientFault fault_type,HANDLE pipe)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 
CallOnClientConnected(void * context,const google_breakpad::ClientInfo * client_info)234   static void CallOnClientConnected(
235     void* context, const google_breakpad::ClientInfo* client_info) {
236     static_cast<MockCrashGenerationServerCallbacks*>(context)->
237       OnClientConnected(client_info);
238   }
239 
CallOnClientDumpRequested(void * context,const google_breakpad::ClientInfo * client_info,const std::wstring * file_path)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 
CallOnClientExited(void * context,const google_breakpad::ClientInfo * client_info)248   static void CallOnClientExited(
249     void* context, const google_breakpad::ClientInfo* client_info) {
250     static_cast<MockCrashGenerationServerCallbacks*>(context)->
251       OnClientExited(client_info);
252   }
253 
CallOnClientUploadRequested(void * context,const DWORD crash_id)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 
TEST_F(CrashGenerationServerTest,PingServerTest)266 TEST_F(CrashGenerationServerTest, PingServerTest) {
267   DoTestFault(CLOSE_AFTER_CONNECT);
268 }
269 
TEST_F(CrashGenerationServerTest,InvalidRegistration)270 TEST_F(CrashGenerationServerTest, InvalidRegistration) {
271   DoTestFault(SEND_INVALID_REGISTRATION);
272 }
273 
TEST_F(CrashGenerationServerTest,TruncateRegistration)274 TEST_F(CrashGenerationServerTest, TruncateRegistration) {
275   DoTestFault(TRUNCATE_REGISTRATION);
276 }
277 
TEST_F(CrashGenerationServerTest,CloseAfterRegistration)278 TEST_F(CrashGenerationServerTest, CloseAfterRegistration) {
279   DoTestFault(CLOSE_AFTER_REGISTRATION);
280 }
281 
TEST_F(CrashGenerationServerTest,ResponseBufferTooSmall)282 TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) {
283   DoTestFault(RESPONSE_BUFFER_TOO_SMALL);
284 }
285 
TEST_F(CrashGenerationServerTest,CloseAfterResponse)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.
TEST_F(CrashGenerationServerTest,SendInvalidAck)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