Chromium Code Reviews| Index: util/mach/child_port_handshake_test.cc |
| diff --git a/util/mach/child_port_handshake_test.cc b/util/mach/child_port_handshake_test.cc |
| index 12ca424c54cc20b269d3cb5417cac4a79a80d7b3..63fe392d6712b357fc05c2fe8ea4dba3f8af1f70 100644 |
| --- a/util/mach/child_port_handshake_test.cc |
| +++ b/util/mach/child_port_handshake_test.cc |
| @@ -26,161 +26,328 @@ namespace { |
| class ChildPortHandshakeTest : public Multiprocess { |
| public: |
| - enum TestType { |
| - kTestTypeChildChecksIn = 0, |
| - kTestTypeChildDoesNotCheckIn_ReadsPipe, |
| - kTestTypeChildDoesNotCheckIn, |
| - kTestTypeTokenIncorrect, |
| - kTestTypeTokenIncorrectThenCorrect, |
| + enum class ClientProcess { |
| + // The child runs the client and the parent runs the server. |
| + kChildClient = 0, |
| + |
| + // The parent runs the client and the child runs the server. |
| + kParentClient, |
| }; |
| - explicit ChildPortHandshakeTest(TestType test_type) |
| - : Multiprocess(), child_port_handshake_(), test_type_(test_type) {} |
| - ~ChildPortHandshakeTest() {} |
| + enum class TestType { |
| + // The client checks in with the server, transferring a receive right. |
| + kClientChecksIn_ReceiveRight = 0, |
| + |
| + // In this test, the client checks in with the server normally. It sends a |
| + // copy of its bootstrap port to the server, because both parent and child |
| + // should have the same bootstrap port, allowing for verification. |
| + kClientChecksIn_SendRight, |
| + |
| + // The client checks in with the server, transferring a send-once right. |
| + kClientChecksIn_SendOnceRight, |
| + |
| + // In this test, the client reads from its pipe, and subsequently exits |
| + // without checking in. This tests that the server properly detects that it |
| + // has lost its client after sending instructions to it via the pipe, while |
| + // waiting for a check-in message. |
| + kClientDoesNotCheckIn, |
|
Robert Sesek
2015/10/28 21:40:03
Worth having a test for if the server dies and the
|
| + |
| + // In this test, the client exits without checking in. This tests that the |
| + // server properly detects that it has lost a client. Whether or not the |
| + // client closes the pipe before the server writes to it is a race, and the |
| + // server needs to be able to detect client loss in both cases, so the |
| + // ClientDoesNotCheckIn_ReadsPipe and NoClient tests also exist to test |
| + // these individual cases more deterministically. |
| + kClientDoesNotCheckIn_ReadsPipe, |
| + |
| + // In this test, the client checks in with the server with an incorrect |
| + // token value and a copy of its own task port. The server should reject the |
| + // message because of the invalid token, and return MACH_PORT_NULL to its |
| + // caller. |
| + kTokenIncorrect, |
| + |
| + // In this test, the client checks in with the server with an incorrect |
| + // token value and a copy of its own task port, and subsequently, the |
| + // correct token value and a copy of its bootstrap port. The server should |
| + // reject the first because of the invalid token, but it should continue |
| + // waiting for a message with a valid token as long as the pipe remains |
| + // open. It should wind wind up returning the bootstrap port, allowing for |
| + // verification. |
| + kTokenIncorrectThenCorrect, |
| + }; |
| + |
| + ChildPortHandshakeTest(ClientProcess client_process, TestType test_type) |
| + : Multiprocess(), |
| + child_port_handshake_(), |
| + client_process_(client_process), |
| + test_type_(test_type) { |
| + } |
| + |
| + ~ChildPortHandshakeTest() { |
| + } |
| private: |
| - // Multiprocess: |
| + void RunServer() { |
| + base::mac::ScopedMachReceiveRight receive_right; |
| + base::mac::ScopedMachSendRight send_right; |
| + if (test_type_ == TestType::kClientChecksIn_ReceiveRight) { |
| + receive_right.reset(child_port_handshake_.RunServer( |
| + ChildPortHandshake::PortRightType::kReceiveRight)); |
| + } else { |
| + send_right.reset(child_port_handshake_.RunServer( |
| + ChildPortHandshake::PortRightType::kSendRight)); |
| + } |
| - void MultiprocessParent() override { |
| - base::mac::ScopedMachSendRight child_port( |
| - child_port_handshake_.RunServer()); |
| switch (test_type_) { |
| - case kTestTypeChildChecksIn: |
| - case kTestTypeTokenIncorrectThenCorrect: |
| - EXPECT_EQ(bootstrap_port, child_port); |
| + case TestType::kClientChecksIn_ReceiveRight: |
| + EXPECT_TRUE(receive_right.is_valid()); |
| + break; |
| + |
| + case TestType::kClientChecksIn_SendRight: |
| + case TestType::kTokenIncorrectThenCorrect: |
| + EXPECT_EQ(bootstrap_port, send_right); |
| + break; |
| + |
| + case TestType::kClientChecksIn_SendOnceRight: |
| + EXPECT_TRUE(send_right.is_valid()); |
| + EXPECT_NE(bootstrap_port, send_right); |
| break; |
| - case kTestTypeChildDoesNotCheckIn_ReadsPipe: |
| - case kTestTypeChildDoesNotCheckIn: |
| - case kTestTypeTokenIncorrect: |
| - EXPECT_EQ(kMachPortNull, child_port); |
| + case TestType::kClientDoesNotCheckIn: |
| + case TestType::kClientDoesNotCheckIn_ReadsPipe: |
| + case TestType::kTokenIncorrect: |
| + EXPECT_FALSE(send_right.is_valid()); |
| break; |
| } |
| } |
| - void MultiprocessChild() override { |
| - int read_pipe = child_port_handshake_.ReadPipeFD(); |
| + void RunClient() { |
| switch (test_type_) { |
| - case kTestTypeChildChecksIn: |
| - ChildPortHandshake::RunClient( |
| - read_pipe, bootstrap_port, MACH_MSG_TYPE_COPY_SEND); |
| + case TestType::kClientChecksIn_SendRight: { |
| + ASSERT_TRUE(child_port_handshake_.RunClient(bootstrap_port, |
| + MACH_MSG_TYPE_COPY_SEND)); |
| + break; |
| + } |
| + |
| + case TestType::kClientChecksIn_ReceiveRight: { |
| + mach_port_t receive_right = NewMachPort(MACH_PORT_RIGHT_RECEIVE); |
| + ASSERT_TRUE(child_port_handshake_.RunClient( |
| + receive_right, MACH_MSG_TYPE_MOVE_RECEIVE)); |
| + break; |
| + } |
| + |
| + case TestType::kClientChecksIn_SendOnceRight: { |
| + base::mac::ScopedMachReceiveRight receive_right( |
| + NewMachPort(MACH_PORT_RIGHT_RECEIVE)); |
| + ASSERT_TRUE(child_port_handshake_.RunClient( |
| + receive_right.get(), MACH_MSG_TYPE_MAKE_SEND_ONCE)); |
| break; |
| + } |
| - case kTestTypeChildDoesNotCheckIn_ReadsPipe: { |
| + case TestType::kClientDoesNotCheckIn: { |
| + child_port_handshake_.ServerWriteFD().reset(); |
| + child_port_handshake_.ClientReadFD().reset(); |
| + break; |
| + } |
| + |
| + case TestType::kClientDoesNotCheckIn_ReadsPipe: { |
| // Don’t run the standard client routine. Instead, drain the pipe, which |
| // will get the parent to the point that it begins waiting for a |
| // check-in message. Then, exit. The pipe is drained using the same |
| // implementation that the real client would use. |
| + child_port_handshake_.ServerWriteFD().reset(); |
| + base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD(); |
| child_port_token_t token; |
| std::string service_name; |
| - ChildPortHandshake::RunClientInternal_ReadPipe( |
| - read_pipe, &token, &service_name); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe( |
| + client_read_fd.get(), &token, &service_name)); |
| break; |
| } |
| - case kTestTypeChildDoesNotCheckIn: |
| - break; |
| - |
| - case kTestTypeTokenIncorrect: { |
| + case TestType::kTokenIncorrect: { |
| // Don’t run the standard client routine. Instead, read the token and |
| // service name, mutate the token, and then check in with the bad token. |
| // The parent should reject the message. |
| + child_port_handshake_.ServerWriteFD().reset(); |
| + base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD(); |
| child_port_token_t token; |
| std::string service_name; |
| - ChildPortHandshake::RunClientInternal_ReadPipe( |
| - read_pipe, &token, &service_name); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe( |
| + client_read_fd.get(), &token, &service_name)); |
| child_port_token_t bad_token = ~token; |
| - ChildPortHandshake::RunClientInternal_SendCheckIn( |
| - service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn( |
| + service_name, |
| + bad_token, |
| + mach_task_self(), |
| + MACH_MSG_TYPE_COPY_SEND)); |
| break; |
| } |
| - case kTestTypeTokenIncorrectThenCorrect: { |
| + case TestType::kTokenIncorrectThenCorrect: { |
| // Don’t run the standard client routine. Instead, read the token and |
| // service name. Mutate the token, and check in with the bad token, |
| // expecting the parent to reject the message. Then, check in with the |
| // correct token, expecting the parent to accept it. |
| + child_port_handshake_.ServerWriteFD().reset(); |
| + base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD(); |
| child_port_token_t token; |
| std::string service_name; |
| - ChildPortHandshake::RunClientInternal_ReadPipe( |
| - read_pipe, &token, &service_name); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe( |
| + client_read_fd.release(), &token, &service_name)); |
| child_port_token_t bad_token = ~token; |
| - ChildPortHandshake::RunClientInternal_SendCheckIn( |
| - service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND); |
| - ChildPortHandshake::RunClientInternal_SendCheckIn( |
| - service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn( |
| + service_name, |
| + bad_token, |
| + mach_task_self(), |
| + MACH_MSG_TYPE_COPY_SEND)); |
| + ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn( |
| + service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND)); |
| break; |
| } |
| } |
| } |
| + // Multiprocess: |
| + |
| + void MultiprocessParent() override { |
| + switch (client_process_) { |
| + case ClientProcess::kChildClient: |
| + RunServer(); |
| + break; |
| + case ClientProcess::kParentClient: |
| + RunClient(); |
| + break; |
| + } |
| + } |
| + |
| + void MultiprocessChild() override { |
| + switch (client_process_) { |
| + case ClientProcess::kChildClient: |
| + RunClient(); |
| + break; |
| + case ClientProcess::kParentClient: |
| + RunServer(); |
| + break; |
| + } |
| + } |
| + |
| private: |
| ChildPortHandshake child_port_handshake_; |
| + ClientProcess client_process_; |
| TestType test_type_; |
| DISALLOW_COPY_AND_ASSIGN(ChildPortHandshakeTest); |
| }; |
| -TEST(ChildPortHandshake, ChildChecksIn) { |
| - // In this test, the client checks in with the server normally. It sends a |
| - // copy of its bootstrap port to the server, because both parent and child |
| - // should have the same bootstrap port, allowing for verification. |
| - ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeChildChecksIn); |
| +TEST(ChildPortHandshake, ChildClientChecksIn_ReceiveRight) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ChildClientChecksIn_SendRight) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ChildClientChecksIn_SendOnceRight) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ChildClientDoesNotCheckIn) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ChildClientDoesNotCheckIn_ReadsPipe) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ChildClientTokenIncorrect) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kTokenIncorrect); |
| test.Run(); |
| } |
| -TEST(ChildPortHandshake, ChildDoesNotCheckIn) { |
| - // In this test, the client exits without checking in. This tests that the |
| - // server properly detects that it has lost a client. Whether or not the |
| - // client closes the pipe before the server writes to it is a race, and the |
| - // server needs to be able to detect client loss in both cases, so the |
| - // ChildDoesNotCheckIn_ReadsPipe and NoChild tests also exist to test these |
| - // individual cases more deterministically. |
| +TEST(ChildPortHandshake, ChildClientTokenIncorrectThenCorrect) { |
| ChildPortHandshakeTest test( |
| - ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn); |
| + ChildPortHandshakeTest::ClientProcess::kChildClient, |
| + ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect); |
| test.Run(); |
| } |
| -TEST(ChildPortHandshake, ChildDoesNotCheckIn_ReadsPipe) { |
| - // In this test, the client reads from its pipe, and subsequently exits |
| - // without checking in. This tests that the server properly detects that it |
| - // has lost its client after sending instructions to it via the pipe, while |
| - // waiting for a check-in message. |
| +TEST(ChildPortHandshake, ParentClientChecksIn_ReceiveRight) { |
| ChildPortHandshakeTest test( |
| - ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn_ReadsPipe); |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight); |
| test.Run(); |
| } |
| -TEST(ChildPortHandshake, TokenIncorrect) { |
| - // In this test, the client checks in with the server with an incorrect token |
| - // value and a copy of its own task port. The server should reject the message |
| - // because of the invalid token, and return MACH_PORT_NULL to its caller. |
| - ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeTokenIncorrect); |
| +TEST(ChildPortHandshake, ParentClientChecksIn_SendRight) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ParentClientChecksIn_SendOnceRight) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ParentClientDoesNotCheckIn) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ParentClientDoesNotCheckIn_ReadsPipe) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe); |
| + test.Run(); |
| +} |
| + |
| +TEST(ChildPortHandshake, ParentClientTokenIncorrect) { |
| + ChildPortHandshakeTest test( |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kTokenIncorrect); |
| test.Run(); |
| } |
| -TEST(ChildPortHandshake, TokenIncorrectThenCorrect) { |
| - // In this test, the client checks in with the server with an incorrect token |
| - // value and a copy of its own task port, and subsequently, the correct token |
| - // value and a copy of its bootstrap port. The server should reject the first |
| - // because of the invalid token, but it should continue waiting for a message |
| - // with a valid token as long as the pipe remains open. It should wind wind up |
| - // returning the bootstrap port, allowing for verification. |
| +TEST(ChildPortHandshake, ParentClientTokenIncorrectThenCorrect) { |
| ChildPortHandshakeTest test( |
| - ChildPortHandshakeTest::kTestTypeTokenIncorrectThenCorrect); |
| + ChildPortHandshakeTest::ClientProcess::kParentClient, |
| + ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect); |
| test.Run(); |
| } |
| -TEST(ChildPortHandshake, NoChild) { |
| - // In this test, the client never checks in with the parent because the child |
| - // never even runs. This tests that the server properly detects that it has |
| - // no client at all, and does not terminate execution with an error such as |
| +TEST(ChildPortHandshake, NoClient) { |
| + // In this test, the client never checks in with the server because it never |
| + // even runs. This tests that the server properly detects that it has no |
| + // client at all, and does not terminate execution with an error such as |
| // “broken pipe” when attempting to send instructions to the client. This test |
| - // is similar to ChildDoesNotCheckIn, but because there’s no child at all, the |
| - // server is guaranteed to see that its pipe partner is gone. |
| + // is similar to kClientDoesNotCheckIn, but because there’s no client at all, |
| + // the server is guaranteed to see that its pipe partner is gone. |
| ChildPortHandshake child_port_handshake; |
| - base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer()); |
| - EXPECT_EQ(kMachPortNull, child_port); |
| + base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer( |
| + ChildPortHandshake::PortRightType::kSendRight)); |
| + EXPECT_FALSE(child_port.is_valid()); |
| } |
| } // namespace |