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