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

Side by Side Diff: third_party/crashpad/crashpad/util/mach/child_port_handshake_test.cc

Issue 1505213004: Copy Crashpad into the Chrome tree instead of importing it via DEPS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update Created 5 years 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
OLDNEW
(Empty)
1 // Copyright 2014 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 "util/mach/child_port_handshake.h"
16
17 #include "base/mac/scoped_mach_port.h"
18 #include "gtest/gtest.h"
19 #include "test/multiprocess.h"
20 #include "util/mach/child_port_types.h"
21 #include "util/mach/mach_extensions.h"
22
23 namespace crashpad {
24 namespace test {
25 namespace {
26
27 class ChildPortHandshakeTest : public Multiprocess {
28 public:
29 enum class ClientProcess {
30 // The child runs the client and the parent runs the server.
31 kChildClient = 0,
32
33 // The parent runs the client and the child runs the server.
34 kParentClient,
35 };
36
37 enum class TestType {
38 // The client checks in with the server, transferring a receive right.
39 kClientChecksIn_ReceiveRight = 0,
40
41 // In this test, the client checks in with the server normally. It sends a
42 // copy of its bootstrap port to the server, because both parent and child
43 // should have the same bootstrap port, allowing for verification.
44 kClientChecksIn_SendRight,
45
46 // The client checks in with the server, transferring a send-once right.
47 kClientChecksIn_SendOnceRight,
48
49 // In this test, the client reads from its pipe, and subsequently exits
50 // without checking in. This tests that the server properly detects that it
51 // has lost its client after sending instructions to it via the pipe, while
52 // waiting for a check-in message.
53 kClientDoesNotCheckIn,
54
55 // In this test, the client exits without checking in. This tests that the
56 // server properly detects that it has lost a client. Whether or not the
57 // client closes the pipe before the server writes to it is a race, and the
58 // server needs to be able to detect client loss in both cases, so the
59 // ClientDoesNotCheckIn_ReadsPipe and NoClient tests also exist to test
60 // these individual cases more deterministically.
61 kClientDoesNotCheckIn_ReadsPipe,
62
63 // In this test, the client checks in with the server with an incorrect
64 // token value and a copy of its own task port. The server should reject the
65 // message because of the invalid token, and return MACH_PORT_NULL to its
66 // caller.
67 kTokenIncorrect,
68
69 // In this test, the client checks in with the server with an incorrect
70 // token value and a copy of its own task port, and subsequently, the
71 // correct token value and a copy of its bootstrap port. The server should
72 // reject the first because of the invalid token, but it should continue
73 // waiting for a message with a valid token as long as the pipe remains
74 // open. It should wind wind up returning the bootstrap port, allowing for
75 // verification.
76 kTokenIncorrectThenCorrect,
77
78 // The server dies. The failure should be reported in the client. This test
79 // type is only compatible with ClientProcess::kParentClient.
80 kServerDies,
81 };
82
83 ChildPortHandshakeTest(ClientProcess client_process, TestType test_type)
84 : Multiprocess(),
85 child_port_handshake_(),
86 client_process_(client_process),
87 test_type_(test_type) {
88 }
89
90 ~ChildPortHandshakeTest() {
91 }
92
93 private:
94 void RunServer() {
95 if (test_type_ == TestType::kServerDies) {
96 return;
97 }
98
99 base::mac::ScopedMachReceiveRight receive_right;
100 base::mac::ScopedMachSendRight send_right;
101 if (test_type_ == TestType::kClientChecksIn_ReceiveRight) {
102 receive_right.reset(child_port_handshake_.RunServer(
103 ChildPortHandshake::PortRightType::kReceiveRight));
104 } else {
105 send_right.reset(child_port_handshake_.RunServer(
106 ChildPortHandshake::PortRightType::kSendRight));
107 }
108
109 switch (test_type_) {
110 case TestType::kClientChecksIn_ReceiveRight:
111 EXPECT_TRUE(receive_right.is_valid());
112 break;
113
114 case TestType::kClientChecksIn_SendRight:
115 case TestType::kTokenIncorrectThenCorrect:
116 EXPECT_EQ(bootstrap_port, send_right);
117 break;
118
119 case TestType::kClientChecksIn_SendOnceRight:
120 EXPECT_TRUE(send_right.is_valid());
121 EXPECT_NE(bootstrap_port, send_right);
122 break;
123
124 case TestType::kClientDoesNotCheckIn:
125 case TestType::kClientDoesNotCheckIn_ReadsPipe:
126 case TestType::kTokenIncorrect:
127 EXPECT_FALSE(send_right.is_valid());
128 break;
129
130 case TestType::kServerDies:
131 // This was special-cased as an early return above.
132 FAIL();
133 break;
134 }
135 }
136
137 void RunClient() {
138 switch (test_type_) {
139 case TestType::kClientChecksIn_SendRight: {
140 ASSERT_TRUE(child_port_handshake_.RunClient(bootstrap_port,
141 MACH_MSG_TYPE_COPY_SEND));
142 break;
143 }
144
145 case TestType::kClientChecksIn_ReceiveRight: {
146 mach_port_t receive_right = NewMachPort(MACH_PORT_RIGHT_RECEIVE);
147 ASSERT_TRUE(child_port_handshake_.RunClient(
148 receive_right, MACH_MSG_TYPE_MOVE_RECEIVE));
149 break;
150 }
151
152 case TestType::kClientChecksIn_SendOnceRight: {
153 base::mac::ScopedMachReceiveRight receive_right(
154 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
155 ASSERT_TRUE(child_port_handshake_.RunClient(
156 receive_right.get(), MACH_MSG_TYPE_MAKE_SEND_ONCE));
157 break;
158 }
159
160 case TestType::kClientDoesNotCheckIn: {
161 child_port_handshake_.ServerWriteFD().reset();
162 child_port_handshake_.ClientReadFD().reset();
163 break;
164 }
165
166 case TestType::kClientDoesNotCheckIn_ReadsPipe: {
167 // Don’t run the standard client routine. Instead, drain the pipe, which
168 // will get the parent to the point that it begins waiting for a
169 // check-in message. Then, exit. The pipe is drained using the same
170 // implementation that the real client would use.
171 child_port_handshake_.ServerWriteFD().reset();
172 base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
173 child_port_token_t token;
174 std::string service_name;
175 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
176 client_read_fd.get(), &token, &service_name));
177 break;
178 }
179
180 case TestType::kTokenIncorrect: {
181 // Don’t run the standard client routine. Instead, read the token and
182 // service name, mutate the token, and then check in with the bad token.
183 // The parent should reject the message.
184 child_port_handshake_.ServerWriteFD().reset();
185 base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
186 child_port_token_t token;
187 std::string service_name;
188 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
189 client_read_fd.get(), &token, &service_name));
190 child_port_token_t bad_token = ~token;
191 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
192 service_name,
193 bad_token,
194 mach_task_self(),
195 MACH_MSG_TYPE_COPY_SEND));
196 break;
197 }
198
199 case TestType::kTokenIncorrectThenCorrect: {
200 // Don’t run the standard client routine. Instead, read the token and
201 // service name. Mutate the token, and check in with the bad token,
202 // expecting the parent to reject the message. Then, check in with the
203 // correct token, expecting the parent to accept it.
204 child_port_handshake_.ServerWriteFD().reset();
205 base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
206 child_port_token_t token;
207 std::string service_name;
208 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
209 client_read_fd.release(), &token, &service_name));
210 child_port_token_t bad_token = ~token;
211 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
212 service_name,
213 bad_token,
214 mach_task_self(),
215 MACH_MSG_TYPE_COPY_SEND));
216 ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
217 service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND));
218 break;
219 }
220
221 case TestType::kServerDies: {
222 ASSERT_EQ(ClientProcess::kParentClient, client_process_);
223 ASSERT_FALSE(child_port_handshake_.RunClient(bootstrap_port,
224 MACH_MSG_TYPE_COPY_SEND));
225 break;
226 }
227 }
228 }
229
230 // Multiprocess:
231
232 void MultiprocessParent() override {
233 switch (client_process_) {
234 case ClientProcess::kChildClient:
235 RunServer();
236 break;
237 case ClientProcess::kParentClient:
238 RunClient();
239 break;
240 }
241 }
242
243 void MultiprocessChild() override {
244 switch (client_process_) {
245 case ClientProcess::kChildClient:
246 RunClient();
247 break;
248 case ClientProcess::kParentClient:
249 RunServer();
250 break;
251 }
252 }
253
254 private:
255 ChildPortHandshake child_port_handshake_;
256 ClientProcess client_process_;
257 TestType test_type_;
258
259 DISALLOW_COPY_AND_ASSIGN(ChildPortHandshakeTest);
260 };
261
262 TEST(ChildPortHandshake, ChildClientChecksIn_ReceiveRight) {
263 ChildPortHandshakeTest test(
264 ChildPortHandshakeTest::ClientProcess::kChildClient,
265 ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight);
266 test.Run();
267 }
268
269 TEST(ChildPortHandshake, ChildClientChecksIn_SendRight) {
270 ChildPortHandshakeTest test(
271 ChildPortHandshakeTest::ClientProcess::kChildClient,
272 ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight);
273 test.Run();
274 }
275
276 TEST(ChildPortHandshake, ChildClientChecksIn_SendOnceRight) {
277 ChildPortHandshakeTest test(
278 ChildPortHandshakeTest::ClientProcess::kChildClient,
279 ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight);
280 test.Run();
281 }
282
283 TEST(ChildPortHandshake, ChildClientDoesNotCheckIn) {
284 ChildPortHandshakeTest test(
285 ChildPortHandshakeTest::ClientProcess::kChildClient,
286 ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn);
287 test.Run();
288 }
289
290 TEST(ChildPortHandshake, ChildClientDoesNotCheckIn_ReadsPipe) {
291 ChildPortHandshakeTest test(
292 ChildPortHandshakeTest::ClientProcess::kChildClient,
293 ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe);
294 test.Run();
295 }
296
297 TEST(ChildPortHandshake, ChildClientTokenIncorrect) {
298 ChildPortHandshakeTest test(
299 ChildPortHandshakeTest::ClientProcess::kChildClient,
300 ChildPortHandshakeTest::TestType::kTokenIncorrect);
301 test.Run();
302 }
303
304 TEST(ChildPortHandshake, ChildClientTokenIncorrectThenCorrect) {
305 ChildPortHandshakeTest test(
306 ChildPortHandshakeTest::ClientProcess::kChildClient,
307 ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect);
308 test.Run();
309 }
310
311 TEST(ChildPortHandshake, ParentClientChecksIn_ReceiveRight) {
312 ChildPortHandshakeTest test(
313 ChildPortHandshakeTest::ClientProcess::kParentClient,
314 ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight);
315 test.Run();
316 }
317
318 TEST(ChildPortHandshake, ParentClientChecksIn_SendRight) {
319 ChildPortHandshakeTest test(
320 ChildPortHandshakeTest::ClientProcess::kParentClient,
321 ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight);
322 test.Run();
323 }
324
325 TEST(ChildPortHandshake, ParentClientChecksIn_SendOnceRight) {
326 ChildPortHandshakeTest test(
327 ChildPortHandshakeTest::ClientProcess::kParentClient,
328 ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight);
329 test.Run();
330 }
331
332 TEST(ChildPortHandshake, ParentClientDoesNotCheckIn) {
333 ChildPortHandshakeTest test(
334 ChildPortHandshakeTest::ClientProcess::kParentClient,
335 ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn);
336 test.Run();
337 }
338
339 TEST(ChildPortHandshake, ParentClientDoesNotCheckIn_ReadsPipe) {
340 ChildPortHandshakeTest test(
341 ChildPortHandshakeTest::ClientProcess::kParentClient,
342 ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe);
343 test.Run();
344 }
345
346 TEST(ChildPortHandshake, ParentClientTokenIncorrect) {
347 ChildPortHandshakeTest test(
348 ChildPortHandshakeTest::ClientProcess::kParentClient,
349 ChildPortHandshakeTest::TestType::kTokenIncorrect);
350 test.Run();
351 }
352
353 TEST(ChildPortHandshake, ParentClientTokenIncorrectThenCorrect) {
354 ChildPortHandshakeTest test(
355 ChildPortHandshakeTest::ClientProcess::kParentClient,
356 ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect);
357 test.Run();
358 }
359
360 TEST(ChildPortHandshake, ParentClientServerDies) {
361 ChildPortHandshakeTest test(
362 ChildPortHandshakeTest::ClientProcess::kParentClient,
363 ChildPortHandshakeTest::TestType::kServerDies);
364 test.Run();
365 }
366
367 TEST(ChildPortHandshake, NoClient) {
368 // In this test, the client never checks in with the server because it never
369 // even runs. This tests that the server properly detects that it has no
370 // client at all, and does not terminate execution with an error such as
371 // “broken pipe” when attempting to send instructions to the client. This test
372 // is similar to kClientDoesNotCheckIn, but because there’s no client at all,
373 // the server is guaranteed to see that its pipe partner is gone.
374 ChildPortHandshake child_port_handshake;
375 base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer(
376 ChildPortHandshake::PortRightType::kSendRight));
377 EXPECT_FALSE(child_port.is_valid());
378 }
379
380 } // namespace
381 } // namespace test
382 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698