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 "breakpad_googletest_includes.h"
32 #include "client/windows/crash_generation/crash_generation_server.h"
33 #include "client/windows/common/ipc_protocol.h"
34
35 using testing::_;
36
37 namespace {
38
39 const wchar_t kPipeName[] =
40 L"\\\\.\\pipe\\CrashGenerationServerTest\\TestCaseServer";
41
42 const DWORD kPipeDesiredAccess = FILE_READ_DATA |
43 FILE_WRITE_DATA |
44 FILE_WRITE_ATTRIBUTES;
45
46 const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
47 SECURITY_SQOS_PRESENT;
48
49 const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
50
51 #define arraysize(f) (sizeof(f) / sizeof(*f))
52 const google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
53 google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"),
54 google_breakpad::CustomInfoEntry(L"ver", L"1.0"),
55 };
56
57 class CrashGenerationServerTest : public ::testing::Test {
58 public:
CrashGenerationServerTest()59 CrashGenerationServerTest()
60 : crash_generation_server_(kPipeName,
61 NULL,
62 CallOnClientConnected, &mock_callbacks_,
63 CallOnClientDumpRequested, &mock_callbacks_,
64 CallOnClientExited, &mock_callbacks_,
65 CallOnClientUploadRequested, &mock_callbacks_,
66 false,
67 NULL),
68 thread_id_(0),
69 exception_pointers_(NULL) {
70 memset(&assert_info_, 0, sizeof(assert_info_));
71 }
72
73 protected:
74 class MockCrashGenerationServerCallbacks {
75 public:
76 MOCK_METHOD1(OnClientConnected,
77 void(const google_breakpad::ClientInfo* client_info));
78 MOCK_METHOD2(OnClientDumpRequested,
79 void(const google_breakpad::ClientInfo* client_info,
80 const std::wstring* file_path));
81 MOCK_METHOD1(OnClientExited,
82 void(const google_breakpad::ClientInfo* client_info));
83 MOCK_METHOD1(OnClientUploadRequested,
84 void(const DWORD crash_id));
85 };
86
87 enum ClientFault {
88 NO_FAULT,
89 CLOSE_AFTER_CONNECT,
90 SEND_INVALID_REGISTRATION,
91 TRUNCATE_REGISTRATION,
92 CLOSE_AFTER_REGISTRATION,
93 RESPONSE_BUFFER_TOO_SMALL,
94 CLOSE_AFTER_RESPONSE,
95 SEND_INVALID_ACK
96 };
97
SetUp()98 void SetUp() {
99 ASSERT_TRUE(crash_generation_server_.Start());
100 }
101
FaultyClient(ClientFault fault_type)102 void FaultyClient(ClientFault fault_type) {
103 HANDLE pipe = CreateFile(kPipeName,
104 kPipeDesiredAccess,
105 0,
106 NULL,
107 OPEN_EXISTING,
108 kPipeFlagsAndAttributes,
109 NULL);
110
111 if (pipe == INVALID_HANDLE_VALUE) {
112 ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError());
113
114 // Cannot continue retrying if wait on pipe fails.
115 ASSERT_TRUE(WaitNamedPipe(kPipeName, 500));
116
117 pipe = CreateFile(kPipeName,
118 kPipeDesiredAccess,
119 0,
120 NULL,
121 OPEN_EXISTING,
122 kPipeFlagsAndAttributes,
123 NULL);
124 }
125
126 ASSERT_NE(pipe, INVALID_HANDLE_VALUE);
127
128 DWORD mode = kPipeMode;
129 ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL));
130
131 DoFaultyClient(fault_type, pipe);
132
133 CloseHandle(pipe);
134 }
135
DoTestFault(ClientFault fault)136 void DoTestFault(ClientFault fault) {
137 EXPECT_CALL(mock_callbacks_, OnClientConnected(_)).Times(0);
138 ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
139 ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
140 ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
141
142 EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
143
144 ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
145
146 // Slight hack. The OnClientConnected is only invoked after the ack is
147 // received by the server. At that point, the FaultyClient call has already
148 // returned. The best way to wait until the server is done handling that is
149 // to send one more ping, whose processing will be blocked by delivery of
150 // the OnClientConnected message.
151 ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
152 }
153
154 MockCrashGenerationServerCallbacks mock_callbacks_;
155
156 private:
157 // Depends on the caller to successfully open the pipe before invocation and
158 // to close it immediately afterwards.
DoFaultyClient(ClientFault fault_type,HANDLE pipe)159 void DoFaultyClient(ClientFault fault_type, HANDLE pipe) {
160 if (fault_type == CLOSE_AFTER_CONNECT) {
161 return;
162 }
163
164 google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries,
165 arraysize(kCustomInfoEntries)};
166
167 google_breakpad::ProtocolMessage msg(
168 fault_type == SEND_INVALID_REGISTRATION ?
169 google_breakpad::MESSAGE_TAG_NONE :
170 google_breakpad::MESSAGE_TAG_REGISTRATION_REQUEST,
171 GetCurrentProcessId(),
172 MiniDumpNormal,
173 &thread_id_,
174 &exception_pointers_,
175 &assert_info_,
176 custom_info,
177 NULL,
178 NULL,
179 NULL);
180
181 DWORD bytes_count = 0;
182
183 ASSERT_TRUE(WriteFile(pipe,
184 &msg,
185 fault_type == TRUNCATE_REGISTRATION ?
186 sizeof(msg) / 2 : sizeof(msg),
187 &bytes_count,
188 NULL));
189
190 if (fault_type == CLOSE_AFTER_REGISTRATION) {
191 return;
192 }
193
194 google_breakpad::ProtocolMessage reply;
195
196 if (!ReadFile(pipe,
197 &reply,
198 fault_type == RESPONSE_BUFFER_TOO_SMALL ?
199 sizeof(google_breakpad::ProtocolMessage) / 2 :
200 sizeof(google_breakpad::ProtocolMessage),
201 &bytes_count,
202 NULL)) {
203 switch (fault_type) {
204 case TRUNCATE_REGISTRATION:
205 case RESPONSE_BUFFER_TOO_SMALL:
206 case SEND_INVALID_REGISTRATION:
207 return;
208
209 default:
210 FAIL() << "Unexpectedly failed to register.";
211 }
212 }
213
214 if (fault_type == CLOSE_AFTER_RESPONSE) {
215 return;
216 }
217
218 google_breakpad::ProtocolMessage ack_msg;
219 ack_msg.tag = google_breakpad::MESSAGE_TAG_REGISTRATION_ACK;
220
221 ASSERT_TRUE(WriteFile(pipe,
222 &ack_msg,
223 SEND_INVALID_ACK ?
224 sizeof(ack_msg) : sizeof(ack_msg) / 2,
225 &bytes_count,
226 NULL));
227
228 return;
229 }
230
CallOnClientConnected(void * context,const google_breakpad::ClientInfo * client_info)231 static void CallOnClientConnected(
232 void* context, const google_breakpad::ClientInfo* client_info) {
233 static_cast<MockCrashGenerationServerCallbacks*>(context)->
234 OnClientConnected(client_info);
235 }
236
CallOnClientDumpRequested(void * context,const google_breakpad::ClientInfo * client_info,const std::wstring * file_path)237 static void CallOnClientDumpRequested(
238 void* context,
239 const google_breakpad::ClientInfo* client_info,
240 const std::wstring* file_path) {
241 static_cast<MockCrashGenerationServerCallbacks*>(context)->
242 OnClientDumpRequested(client_info, file_path);
243 }
244
CallOnClientExited(void * context,const google_breakpad::ClientInfo * client_info)245 static void CallOnClientExited(
246 void* context, const google_breakpad::ClientInfo* client_info) {
247 static_cast<MockCrashGenerationServerCallbacks*>(context)->
248 OnClientExited(client_info);
249 }
250
CallOnClientUploadRequested(void * context,const DWORD crash_id)251 static void CallOnClientUploadRequested(void* context, const DWORD crash_id) {
252 static_cast<MockCrashGenerationServerCallbacks*>(context)->
253 OnClientUploadRequested(crash_id);
254 }
255
256 DWORD thread_id_;
257 EXCEPTION_POINTERS* exception_pointers_;
258 MDRawAssertionInfo assert_info_;
259
260 google_breakpad::CrashGenerationServer crash_generation_server_;
261 };
262
TEST_F(CrashGenerationServerTest,PingServerTest)263 TEST_F(CrashGenerationServerTest, PingServerTest) {
264 DoTestFault(CLOSE_AFTER_CONNECT);
265 }
266
TEST_F(CrashGenerationServerTest,InvalidRegistration)267 TEST_F(CrashGenerationServerTest, InvalidRegistration) {
268 DoTestFault(SEND_INVALID_REGISTRATION);
269 }
270
TEST_F(CrashGenerationServerTest,TruncateRegistration)271 TEST_F(CrashGenerationServerTest, TruncateRegistration) {
272 DoTestFault(TRUNCATE_REGISTRATION);
273 }
274
TEST_F(CrashGenerationServerTest,CloseAfterRegistration)275 TEST_F(CrashGenerationServerTest, CloseAfterRegistration) {
276 DoTestFault(CLOSE_AFTER_REGISTRATION);
277 }
278
TEST_F(CrashGenerationServerTest,ResponseBufferTooSmall)279 TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) {
280 DoTestFault(RESPONSE_BUFFER_TOO_SMALL);
281 }
282
TEST_F(CrashGenerationServerTest,CloseAfterResponse)283 TEST_F(CrashGenerationServerTest, CloseAfterResponse) {
284 DoTestFault(CLOSE_AFTER_RESPONSE);
285 }
286
287 // It turns out that, as long as you send one byte, the ACK is accepted and
288 // registration succeeds.
TEST_F(CrashGenerationServerTest,SendInvalidAck)289 TEST_F(CrashGenerationServerTest, SendInvalidAck) {
290 EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
291 ASSERT_NO_FATAL_FAILURE(FaultyClient(SEND_INVALID_ACK));
292
293 // See DoTestFault for an explanation of this line
294 ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
295
296 EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
297 ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
298
299 // See DoTestFault for an explanation of this line
300 ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
301 }
302
303 } // anonymous namespace
304