Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: handler/win/registrar_test.cc

Issue 1213723004: Implement a Windows crash client registrar. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@child_process
Patch Set: More self-review. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« handler/win/registrar.cc ('K') | « handler/win/registrar.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "handler/win/registrar.h"
16
17 #include <windows.h>
18
19 #include <vector>
20
21 #include "base/basictypes.h"
22 #include "base/logging.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "gtest/gtest.h"
25 #include "test/win/win_child_process.h"
26 #include "util/win/scoped_handle.h"
27
28 namespace crashpad {
29 namespace test {
30 namespace {
31
32 // Reads a `HANDLE` value from |handle|. Assume sender has same bitness as
33 // reader. CHECKs upon failure.
34 ScopedKernelHANDLE ReadHandle(HANDLE handle) {
35 HANDLE value = nullptr;
36 DWORD bytes_read = 0;
scottmg 2015/06/29 20:29:05 Replace 36-38 with CheckReadFile() from util/file/
37 CHECK(::ReadFile(handle, &value, sizeof(value), &bytes_read, nullptr));
38 CHECK_EQ(sizeof(value), bytes_read);
39 return ScopedKernelHANDLE(value);
40 }
41
42 // Writes |value| to |handle|. Logs a GTest failure upon failure.
43 void WriteHandle(HANDLE handle, HANDLE value) {
44 DWORD bytes_written = 0;
scottmg 2015/06/29 20:29:05 And CheckedWriteFile here.
45 EXPECT_TRUE(
46 ::WriteFile(handle, &value, sizeof(value), &bytes_written, nullptr));
47 EXPECT_EQ(sizeof(value), bytes_written);
48 }
49
50 // Implements a client process that may be registered. Reads the handle pair
51 // from its parent and proceeds to request a dump. After receiving notice that
52 // the dump completed, exits with 0.
53 class ClientProcess : public test::WinChildProcess {
54 public:
55 ClientProcess() {}
56
57 private:
58 int Run() override {
59 // In the worst case, this process will exit due to a broken pipe if the
60 // parent process disappears.
61 ScopedKernelHANDLE request_report_event = ReadHandle(ReadPipeHandle());
62 ScopedKernelHANDLE report_complete_event = ReadHandle(ReadPipeHandle());
63 PCHECK(SetEvent(request_report_event.get()));
64 CHECK_EQ(WAIT_OBJECT_0,
65 WaitForSingleObject(report_complete_event.get(), INFINITE));
66 return 0;
67 }
68
69 DISALLOW_COPY_AND_ASSIGN(ClientProcess);
70 };
71
72 // Handles crash dump requests, logging the requesting client's PID.
73 class MockDelegate : Registrar::Delegate {
74 public:
75 // Instantiates a Registrar::Delegate that logs requesting clients' PIDs to
76 // |process_ids|.
77 explicit MockDelegate(std::vector<DWORD>* process_ids)
78 : process_ids_(process_ids) {}
79
80 // Registrar::Delegate:
81 void GenerateReportForClient(HANDLE client_process) override {
82 process_ids_->push_back(GetProcessId(client_process));
83 }
84
85 private:
86 std::vector<DWORD>* process_ids_;
87
88 DISALLOW_COPY_AND_ASSIGN(MockDelegate);
89 };
90
91 // Duplicates |handle| with PROCESS_ALL_ACCESS. Logs a GTest failure upon
92 // failure.
93 ScopedKernelHANDLE DuplicateProcessHandleWithAllAccess(HANDLE handle) {
94 HANDLE result = nullptr;
95 if (!DuplicateHandle(GetCurrentProcess(),
96 handle,
97 GetCurrentProcess(),
98 &result,
99 PROCESS_ALL_ACCESS,
100 false,
101 0)) {
102 PLOG(ERROR) << "DuplicateHandle";
103 ADD_FAILURE() << "DuplicateHandle";
104 return ScopedKernelHANDLE();
105 }
106 return ScopedKernelHANDLE(result);
107 }
108
109 class RegistrarTest : public testing::Test {
110 public:
111 RegistrarTest()
112 : registrar_(
113 scoped_ptr<Registrar::Delegate>(new MockDelegate(&process_ids_))) {}
114
115 protected:
116 Registrar& registrar() { return registrar_; }
117 std::vector<DWORD>& triggered_process_ids() { return process_ids_; }
118
119 private:
120 std::vector<DWORD> process_ids_;
121 Registrar registrar_;
122
123 DISALLOW_COPY_AND_ASSIGN(RegistrarTest);
124 };
125
126 // Exercises registration, report request handling, and process termination.
127 TEST_F(RegistrarTest, RegisterProcess) {
128 test::WinChildProcess::EntryPoint<ClientProcess>();
129
130 struct ProcessState {
131 scoped_ptr<test::WinChildProcess::Handles> child_handles;
132 HANDLE request_handle;
133 HANDLE done_handle;
134 } process_states[3];
135
136 for (int i = 0; i < arraysize(process_states); ++i) {
137 process_states[i].child_handles = test::WinChildProcess::Launch();
138 ASSERT_TRUE(registrar().RegisterProcess(
139 DuplicateProcessHandleWithAllAccess(
140 process_states[i].child_handles->process.get()),
141 &process_states[i].request_handle,
142 &process_states[i].done_handle));
143 }
144
145 // Kill a process. This should not cause any hiccups for the Registrar.
146 ASSERT_TRUE(
147 TerminateProcess(process_states[0].child_handles->process.get(), 0));
148
149 // Send the event pairs over to each of the child processes, and verify that
150 // they are able to trigger a report request, that the request is handed to
151 // our delegate, and that the "report complete" event is triggered and may be
152 // detected by the client.
153 for (int i = 1; i < arraysize(process_states); ++i) {
154 triggered_process_ids().clear();
155
156 // Verify that the child process is still running.
157 ASSERT_EQ(
158 WAIT_TIMEOUT,
159 WaitForSingleObject(process_states[i].child_handles->process.get(), 0));
160
161 // Send the handle pair along to the child, which will proceed to request a
162 // dump and wait for the "dump complete" signal.
163 WriteHandle(process_states[i].child_handles->write.get(),
164 process_states[i].request_handle);
165 WriteHandle(process_states[i].child_handles->write.get(),
166 process_states[i].done_handle);
167
168 // Wait for the process to exit with code 0 (which indicates that the "dump
169 // complete" signal was received).
170 ASSERT_EQ(WAIT_OBJECT_0,
171 WaitForSingleObject(
172 process_states[i].child_handles->process.get(), INFINITE));
173 DWORD exit_code = 0;
174 ASSERT_TRUE(GetExitCodeProcess(
175 process_states[i].child_handles->process.get(), &exit_code));
176 ASSERT_EQ(0, exit_code);
177
178 // Verify that our delegate was invoked, with the correct process handle.
179 ASSERT_EQ(1, triggered_process_ids().size());
180 ASSERT_EQ(GetProcessId(process_states[i].child_handles->process.get()),
181 triggered_process_ids()[0]);
182 }
183 }
184
185 } // namespace
186 } // namespace test
187 } // namespace crashpad
188
OLDNEW
« handler/win/registrar.cc ('K') | « handler/win/registrar.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698