Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / sandbox / mac / xpc_message_server_unittest.cc
blob26e4ad0dcc484584f4de8c82b4e69a145b542af9
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/mac/xpc_message_server.h"
7 #include <Block.h>
8 #include <mach/mach.h>
9 #include <servers/bootstrap.h>
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_mach_port.h"
15 #include "base/process/kill.h"
16 #include "base/test/multiprocess_test.h"
17 #include "sandbox/mac/xpc.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/multiprocess_func_list.h"
21 namespace sandbox {
23 class XPCMessageServerTest : public testing::Test {
24 public:
25 void SetUp() override {
26 if (!RunXPCTest())
27 return;
28 ASSERT_TRUE(InitializeXPC());
31 bool RunXPCTest() {
32 return base::mac::IsOSMountainLionOrLater();
36 // A MessageDemuxer that manages a test server and executes a block for every
37 // message.
38 class BlockDemuxer : public MessageDemuxer {
39 public:
40 BlockDemuxer()
41 : demux_block_(NULL),
42 server_(this, MACH_PORT_NULL),
43 pipe_(NULL) {
46 ~BlockDemuxer() override {
47 if (pipe_)
48 xpc_release(pipe_);
49 if (demux_block_)
50 Block_release(demux_block_);
53 // Starts running the server, given a block to handle incoming IPC messages.
54 bool Initialize(void (^demux_block)(IPCMessage request)) {
55 if (!server_.Initialize())
56 return false;
58 // Create a send right on the port so that the XPC pipe can be created.
59 if (mach_port_insert_right(mach_task_self(), server_.GetServerPort(),
60 server_.GetServerPort(), MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
61 return false;
63 scoped_send_right_.reset(server_.GetServerPort());
65 demux_block_ = Block_copy(demux_block);
66 pipe_ = xpc_pipe_create_from_port(server_.GetServerPort(), 0);
68 return true;
71 void DemuxMessage(IPCMessage request) override {
72 demux_block_(request);
75 xpc_pipe_t pipe() { return pipe_; }
77 XPCMessageServer* server() { return &server_; }
79 private:
80 void (^demux_block_)(IPCMessage request);
82 XPCMessageServer server_;
84 base::mac::ScopedMachSendRight scoped_send_right_;
86 xpc_pipe_t pipe_;
89 #define XPC_TEST_F(name) TEST_F(XPCMessageServerTest, name) { \
90 if (!RunXPCTest()) \
91 return; \
93 XPC_TEST_F(ReceiveMessage) // {
94 BlockDemuxer fixture;
95 XPCMessageServer* server = fixture.server();
97 uint64_t __block value = 0;
98 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
99 value = xpc_dictionary_get_uint64(request.xpc, "test_value");
100 server->SendReply(server->CreateReply(request));
101 }));
103 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
104 xpc_dictionary_set_uint64(request, "test_value", 42);
106 xpc_object_t reply;
107 EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
109 EXPECT_EQ(42u, value);
111 xpc_release(request);
112 xpc_release(reply);
115 XPC_TEST_F(RejectMessage) // {
116 BlockDemuxer fixture;
117 XPCMessageServer* server = fixture.server();
118 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
119 server->RejectMessage(request, EPERM);
120 }));
122 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
123 xpc_object_t reply;
124 EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
126 EXPECT_EQ(EPERM, xpc_dictionary_get_int64(reply, "error"));
128 xpc_release(request);
129 xpc_release(reply);
132 XPC_TEST_F(RejectMessageSimpleRoutine) // {
133 BlockDemuxer fixture;
134 XPCMessageServer* server = fixture.server();
135 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
136 server->RejectMessage(request, -99);
137 }));
139 // Create a message that is not expecting a reply.
140 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
141 EXPECT_EQ(0, xpc_pipe_simpleroutine(fixture.pipe(), request));
143 xpc_release(request);
146 char kGetSenderPID[] = "org.chromium.sandbox.test.GetSenderPID";
148 XPC_TEST_F(GetSenderPID) // {
149 BlockDemuxer fixture;
150 XPCMessageServer* server = fixture.server();
152 pid_t __block sender_pid = 0;
153 int64_t __block child_pid = 0;
154 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
155 sender_pid = server->GetMessageSenderPID(request);
156 child_pid = xpc_dictionary_get_int64(request.xpc, "child_pid");
157 }));
159 #pragma GCC diagnostic push
160 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
161 kern_return_t kr = bootstrap_register(bootstrap_port, kGetSenderPID,
162 server->GetServerPort());
163 #pragma GCC diagnostic pop
164 ASSERT_EQ(KERN_SUCCESS, kr);
166 base::Process child = base::SpawnMultiProcessTestChild(
167 "GetSenderPID",
168 base::GetMultiProcessTestChildBaseCommandLine(),
169 base::LaunchOptions());
170 ASSERT_TRUE(child.IsValid());
172 int exit_code = -1;
173 ASSERT_TRUE(child.WaitForExit(&exit_code));
174 EXPECT_EQ(0, exit_code);
176 EXPECT_EQ(child.Pid(), sender_pid);
177 EXPECT_EQ(child.Pid(), child_pid);
178 EXPECT_EQ(sender_pid, child_pid);
181 MULTIPROCESS_TEST_MAIN(GetSenderPID) {
182 CHECK(sandbox::InitializeXPC());
184 mach_port_t port = MACH_PORT_NULL;
185 CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, kGetSenderPID,
186 &port));
187 base::mac::ScopedMachSendRight scoped_port(port);
189 xpc_pipe_t pipe = xpc_pipe_create_from_port(port, 0);
191 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
192 xpc_dictionary_set_int64(message, "child_pid", getpid());
193 CHECK_EQ(0, xpc_pipe_simpleroutine(pipe, message));
195 xpc_release(message);
196 xpc_release(pipe);
198 return 0;
201 XPC_TEST_F(ForwardMessage) // {
202 BlockDemuxer first;
203 XPCMessageServer* first_server = first.server();
205 BlockDemuxer second;
206 XPCMessageServer* second_server = second.server();
208 ASSERT_TRUE(first.Initialize(^(IPCMessage request) {
209 xpc_dictionary_set_int64(request.xpc, "seen_by_first", 1);
210 first_server->ForwardMessage(request, second_server->GetServerPort());
211 }));
212 ASSERT_TRUE(second.Initialize(^(IPCMessage request) {
213 IPCMessage reply = second_server->CreateReply(request);
214 xpc_dictionary_set_int64(reply.xpc, "seen_by_first",
215 xpc_dictionary_get_int64(request.xpc, "seen_by_first"));
216 xpc_dictionary_set_int64(reply.xpc, "seen_by_second", 2);
217 second_server->SendReply(reply);
218 }));
220 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
221 xpc_object_t reply;
222 ASSERT_EQ(0, xpc_pipe_routine(first.pipe(), request, &reply));
224 EXPECT_EQ(1, xpc_dictionary_get_int64(reply, "seen_by_first"));
225 EXPECT_EQ(2, xpc_dictionary_get_int64(reply, "seen_by_second"));
227 xpc_release(request);
228 xpc_release(reply);
231 } // namespace sandbox