/thirdparty/breakpad/client/windows/unittests/crash_generation_server_test.cc

http://github.com/tomahawk-player/tomahawk · C++ · 306 lines · 208 code · 58 blank · 40 comment · 13 complexity · e7c45502248e35d16f9ee2b86c446570 MD5 · raw file

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