| Index: util/mach/composite_mach_message_server_test.cc
|
| diff --git a/util/mach/composite_mach_message_server_test.cc b/util/mach/composite_mach_message_server_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f1ec963ce0fccb1f21f3038b5757ca03080a1687
|
| --- /dev/null
|
| +++ b/util/mach/composite_mach_message_server_test.cc
|
| @@ -0,0 +1,303 @@
|
| +// Copyright 2014 The Crashpad Authors. All rights reserved.
|
| +//
|
| +// Licensed under the Apache License, Version 2.0 (the "License");
|
| +// you may not use this file except in compliance with the License.
|
| +// You may obtain a copy of the License at
|
| +//
|
| +// http://www.apache.org/licenses/LICENSE-2.0
|
| +//
|
| +// Unless required by applicable law or agreed to in writing, software
|
| +// distributed under the License is distributed on an "AS IS" BASIS,
|
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +// See the License for the specific language governing permissions and
|
| +// limitations under the License.
|
| +
|
| +#include "util/mach/composite_mach_message_server.h"
|
| +
|
| +#include "base/strings/stringprintf.h"
|
| +#include "gtest/gtest.h"
|
| +#include "util/mach/mach_message.h"
|
| +
|
| +namespace crashpad {
|
| +namespace test {
|
| +namespace {
|
| +
|
| +TEST(CompositeMachMessageServer, Empty) {
|
| + CompositeMachMessageServer server;
|
| +
|
| + EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
|
| +
|
| + mach_msg_empty_rcv_t request = {};
|
| + EXPECT_EQ(sizeof(request.header), server.MachMessageServerRequestSize());
|
| +
|
| + mig_reply_error_t reply = {};
|
| + EXPECT_EQ(sizeof(reply), server.MachMessageServerReplySize());
|
| +
|
| + bool destroy_complex_request = false;
|
| + EXPECT_FALSE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
|
| +}
|
| +
|
| +class TestMachMessageHandler : public MachMessageServer::Interface {
|
| + public:
|
| + TestMachMessageHandler()
|
| + : MachMessageServer::Interface(),
|
| + request_ids_(),
|
| + request_size_(0),
|
| + reply_size_(0),
|
| + return_code_(KERN_FAILURE),
|
| + return_value_(false),
|
| + destroy_complex_request_(false) {
|
| + }
|
| +
|
| + ~TestMachMessageHandler() {
|
| + }
|
| +
|
| + void SetReturnCodes(bool return_value,
|
| + kern_return_t return_code,
|
| + bool destroy_complex_request) {
|
| + return_value_ = return_value;
|
| + return_code_ = return_code;
|
| + destroy_complex_request_ = destroy_complex_request;
|
| + }
|
| +
|
| + void AddRequestID(mach_msg_id_t request_id) {
|
| + request_ids_.insert(request_id);
|
| + }
|
| +
|
| + void SetRequestSize(mach_msg_size_t request_size) {
|
| + request_size_ = request_size;
|
| + }
|
| +
|
| + void SetReplySize(mach_msg_size_t reply_size) {
|
| + reply_size_ = reply_size;
|
| + }
|
| +
|
| + // MachMessageServer::Interface:
|
| +
|
| + bool MachMessageServerFunction(const mach_msg_header_t* in,
|
| + mach_msg_header_t* out,
|
| + bool* destroy_complex_request) override {
|
| + EXPECT_NE(request_ids_.end(), request_ids_.find(in->msgh_id));
|
| +
|
| + *destroy_complex_request = destroy_complex_request_;
|
| + PrepareMIGReplyFromRequest(in, out);
|
| + SetMIGReplyError(out, return_code_);
|
| + return return_value_;
|
| + }
|
| +
|
| + std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
|
| + return request_ids_;
|
| + }
|
| +
|
| + mach_msg_size_t MachMessageServerRequestSize() override {
|
| + return request_size_;
|
| + }
|
| +
|
| + mach_msg_size_t MachMessageServerReplySize() override {
|
| + return reply_size_;
|
| + }
|
| +
|
| + private:
|
| + std::set<mach_msg_id_t> request_ids_;
|
| + mach_msg_size_t request_size_;
|
| + mach_msg_size_t reply_size_;
|
| + kern_return_t return_code_;
|
| + bool return_value_;
|
| + bool destroy_complex_request_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestMachMessageHandler);
|
| +};
|
| +
|
| +TEST(CompositeMachMessageServer, HandlerDoesNotHandle) {
|
| + TestMachMessageHandler handler;
|
| +
|
| + CompositeMachMessageServer server;
|
| + server.AddHandler(&handler);
|
| +
|
| + EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
|
| +
|
| + mach_msg_empty_rcv_t request = {};
|
| + EXPECT_EQ(sizeof(request.header), server.MachMessageServerRequestSize());
|
| +
|
| + mig_reply_error_t reply = {};
|
| + EXPECT_EQ(sizeof(reply), server.MachMessageServerReplySize());
|
| +
|
| + bool destroy_complex_request = false;
|
| + EXPECT_FALSE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
|
| + EXPECT_FALSE(destroy_complex_request);
|
| +}
|
| +
|
| +TEST(CompositeMachMessageServer, OneHandler) {
|
| + const mach_msg_id_t kRequestID = 100;
|
| + const mach_msg_size_t kRequestSize = 256;
|
| + const mach_msg_size_t kReplySize = 128;
|
| + const kern_return_t kReturnCode = KERN_SUCCESS;
|
| +
|
| + TestMachMessageHandler handler;
|
| + handler.AddRequestID(kRequestID);
|
| + handler.SetRequestSize(kRequestSize);
|
| + handler.SetReplySize(kReplySize);
|
| + handler.SetReturnCodes(true, kReturnCode, true);
|
| +
|
| + CompositeMachMessageServer server;
|
| +
|
| + // The chosen request and reply sizes must be larger than the defaults for
|
| + // that portion fo the test to be valid.
|
| + EXPECT_GT(kRequestSize, server.MachMessageServerRequestSize());
|
| + EXPECT_GT(kReplySize, server.MachMessageServerReplySize());
|
| +
|
| + server.AddHandler(&handler);
|
| +
|
| + std::set<mach_msg_id_t> expect_request_ids;
|
| + expect_request_ids.insert(kRequestID);
|
| + EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
|
| +
|
| + EXPECT_EQ(kRequestSize, server.MachMessageServerRequestSize());
|
| + EXPECT_EQ(kReplySize, server.MachMessageServerReplySize());
|
| +
|
| + mach_msg_empty_rcv_t request = {};
|
| + mig_reply_error_t reply = {};
|
| +
|
| + // Send a message with an unknown request ID.
|
| + request.header.msgh_id = 0;
|
| + bool destroy_complex_request = false;
|
| + EXPECT_FALSE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
|
| + EXPECT_FALSE(destroy_complex_request);
|
| +
|
| + // Send a message with a known request ID.
|
| + request.header.msgh_id = kRequestID;
|
| + EXPECT_TRUE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(kReturnCode, reply.RetCode);
|
| + EXPECT_TRUE(destroy_complex_request);
|
| +}
|
| +
|
| +TEST(CompositeMachMessageServer, ThreeHandlers) {
|
| + const mach_msg_id_t kRequestIDs0[] = {5};
|
| + const kern_return_t kReturnCode0 = KERN_SUCCESS;
|
| +
|
| + const mach_msg_id_t kRequestIDs1[] = {4, 7};
|
| + const kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE;
|
| +
|
| + const mach_msg_id_t kRequestIDs2[] = {10, 0, 20};
|
| + const mach_msg_size_t kRequestSize2 = 6144;
|
| + const mach_msg_size_t kReplySize2 = 16384;
|
| + const kern_return_t kReturnCode2 = KERN_NOT_RECEIVER;
|
| +
|
| + TestMachMessageHandler handlers[3];
|
| + std::set<mach_msg_id_t> expect_request_ids;
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) {
|
| + const mach_msg_id_t request_id = kRequestIDs0[index];
|
| + handlers[0].AddRequestID(request_id);
|
| + expect_request_ids.insert(request_id);
|
| + }
|
| + handlers[0].SetRequestSize(sizeof(mach_msg_header_t));
|
| + handlers[0].SetReplySize(sizeof(mig_reply_error_t));
|
| + handlers[0].SetReturnCodes(true, kReturnCode0, false);
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) {
|
| + const mach_msg_id_t request_id = kRequestIDs1[index];
|
| + handlers[1].AddRequestID(request_id);
|
| + expect_request_ids.insert(request_id);
|
| + }
|
| + handlers[1].SetRequestSize(100);
|
| + handlers[1].SetReplySize(200);
|
| + handlers[1].SetReturnCodes(false, kReturnCode1, true);
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) {
|
| + const mach_msg_id_t request_id = kRequestIDs2[index];
|
| + handlers[2].AddRequestID(request_id);
|
| + expect_request_ids.insert(request_id);
|
| + }
|
| + handlers[2].SetRequestSize(kRequestSize2);
|
| + handlers[2].SetReplySize(kReplySize2);
|
| + handlers[2].SetReturnCodes(true, kReturnCode2, true);
|
| +
|
| + CompositeMachMessageServer server;
|
| +
|
| + // The chosen request and reply sizes must be larger than the defaults for
|
| + // that portion fo the test to be valid.
|
| + EXPECT_GT(kRequestSize2, server.MachMessageServerRequestSize());
|
| + EXPECT_GT(kReplySize2, server.MachMessageServerReplySize());
|
| +
|
| + server.AddHandler(&handlers[0]);
|
| + server.AddHandler(&handlers[1]);
|
| + server.AddHandler(&handlers[2]);
|
| +
|
| + EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
|
| +
|
| + EXPECT_EQ(kRequestSize2, server.MachMessageServerRequestSize());
|
| + EXPECT_EQ(kReplySize2, server.MachMessageServerReplySize());
|
| +
|
| + mach_msg_empty_rcv_t request = {};
|
| + mig_reply_error_t reply = {};
|
| +
|
| + // Send a message with an unknown request ID.
|
| + request.header.msgh_id = 100;
|
| + bool destroy_complex_request = false;
|
| + EXPECT_FALSE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
|
| + EXPECT_FALSE(destroy_complex_request);
|
| +
|
| + // Send messages with known request IDs.
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) {
|
| + request.header.msgh_id = kRequestIDs0[index];
|
| + SCOPED_TRACE(base::StringPrintf(
|
| + "handler 0, index %zu, id %d", index, request.header.msgh_id));
|
| +
|
| + EXPECT_TRUE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(kReturnCode0, reply.RetCode);
|
| + EXPECT_FALSE(destroy_complex_request);
|
| + }
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) {
|
| + request.header.msgh_id = kRequestIDs1[index];
|
| + SCOPED_TRACE(base::StringPrintf(
|
| + "handler 1, index %zu, id %d", index, request.header.msgh_id));
|
| +
|
| + EXPECT_FALSE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(kReturnCode1, reply.RetCode);
|
| + EXPECT_TRUE(destroy_complex_request);
|
| + }
|
| +
|
| + for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) {
|
| + request.header.msgh_id = kRequestIDs2[index];
|
| + SCOPED_TRACE(base::StringPrintf(
|
| + "handler 2, index %zu, id %d", index, request.header.msgh_id));
|
| +
|
| + EXPECT_TRUE(server.MachMessageServerFunction(
|
| + &request.header, &reply.Head, &destroy_complex_request));
|
| + EXPECT_EQ(kReturnCode2, reply.RetCode);
|
| + EXPECT_TRUE(destroy_complex_request);
|
| + }
|
| +}
|
| +
|
| +// CompositeMachMessageServer can’t deal with two handlers that want to handle
|
| +// the same request ID.
|
| +TEST(CompositeMachMessageServerDeathTest, DuplicateRequestID) {
|
| + const mach_msg_id_t kRequestID = 400;
|
| +
|
| + TestMachMessageHandler handlers[2];
|
| + handlers[0].AddRequestID(kRequestID);
|
| + handlers[1].AddRequestID(kRequestID);
|
| +
|
| + CompositeMachMessageServer server;
|
| +
|
| + server.AddHandler(&handlers[0]);
|
| + EXPECT_DEATH(server.AddHandler(&handlers[1]), "duplicate request ID");
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace test
|
| +} // namespace crashpad
|
|
|