Componentize ShortcutsBackend
[chromium-blink-merge.git] / sandbox / mac / xpc_message_server_unittest.cc
blob4c4fcf9c9412c28ff682209b93ce5bec04c0b521
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 #if defined(MAC_OS_X_VERSION_10_7) && \
22 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
23 // Redeclare methods that only exist on 10.7+ to suppress
24 // -Wpartial-availability warnings.
25 extern "C" {
26 XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL int64_t
27 xpc_dictionary_get_int64(xpc_object_t xdict, const char* key);
29 XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL uint64_t
30 xpc_dictionary_get_uint64(xpc_object_t xdict, const char* key);
32 XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
33 xpc_dictionary_set_uint64(xpc_object_t xdict, const char* key, uint64_t value);
35 XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT xpc_object_t
36 xpc_dictionary_create(const char* const* keys,
37 const xpc_object_t* values,
38 size_t count);
39 } // extern "C"
40 #endif
42 namespace sandbox {
44 class XPCMessageServerTest : public testing::Test {
45 public:
46 void SetUp() override {
47 if (!RunXPCTest())
48 return;
49 ASSERT_TRUE(InitializeXPC());
52 bool RunXPCTest() {
53 return base::mac::IsOSMountainLionOrLater();
57 // A MessageDemuxer that manages a test server and executes a block for every
58 // message.
59 class BlockDemuxer : public MessageDemuxer {
60 public:
61 BlockDemuxer()
62 : demux_block_(NULL),
63 server_(this, MACH_PORT_NULL),
64 pipe_(NULL) {
67 ~BlockDemuxer() override {
68 if (pipe_)
69 xpc_release(pipe_);
70 if (demux_block_)
71 Block_release(demux_block_);
74 // Starts running the server, given a block to handle incoming IPC messages.
75 bool Initialize(void (^demux_block)(IPCMessage request)) {
76 if (!server_.Initialize())
77 return false;
79 // Create a send right on the port so that the XPC pipe can be created.
80 if (mach_port_insert_right(mach_task_self(), server_.GetServerPort(),
81 server_.GetServerPort(), MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
82 return false;
84 scoped_send_right_.reset(server_.GetServerPort());
86 demux_block_ = Block_copy(demux_block);
87 pipe_ = xpc_pipe_create_from_port(server_.GetServerPort(), 0);
89 return true;
92 void DemuxMessage(IPCMessage request) override {
93 demux_block_(request);
96 xpc_pipe_t pipe() { return pipe_; }
98 XPCMessageServer* server() { return &server_; }
100 private:
101 void (^demux_block_)(IPCMessage request);
103 XPCMessageServer server_;
105 base::mac::ScopedMachSendRight scoped_send_right_;
107 xpc_pipe_t pipe_;
110 #define XPC_TEST_F(name) TEST_F(XPCMessageServerTest, name) { \
111 if (!RunXPCTest()) \
112 return; \
114 XPC_TEST_F(ReceiveMessage) // {
115 BlockDemuxer fixture;
116 XPCMessageServer* server = fixture.server();
118 uint64_t __block value = 0;
119 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
120 value = xpc_dictionary_get_uint64(request.xpc, "test_value");
121 server->SendReply(server->CreateReply(request));
122 }));
124 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
125 xpc_dictionary_set_uint64(request, "test_value", 42);
127 xpc_object_t reply;
128 EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
130 EXPECT_EQ(42u, value);
132 xpc_release(request);
133 xpc_release(reply);
136 XPC_TEST_F(RejectMessage) // {
137 BlockDemuxer fixture;
138 XPCMessageServer* server = fixture.server();
139 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
140 server->RejectMessage(request, EPERM);
141 }));
143 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
144 xpc_object_t reply;
145 EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
147 EXPECT_EQ(EPERM, xpc_dictionary_get_int64(reply, "error"));
149 xpc_release(request);
150 xpc_release(reply);
153 char kGetSenderPID[] = "org.chromium.sandbox.test.GetSenderPID";
155 XPC_TEST_F(GetSenderPID) // {
156 BlockDemuxer fixture;
157 XPCMessageServer* server = fixture.server();
159 pid_t __block sender_pid = 0;
160 int64_t __block child_pid = 0;
161 ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
162 sender_pid = server->GetMessageSenderPID(request);
163 child_pid = xpc_dictionary_get_int64(request.xpc, "child_pid");
164 }));
166 #pragma GCC diagnostic push
167 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
168 kern_return_t kr = bootstrap_register(bootstrap_port, kGetSenderPID,
169 server->GetServerPort());
170 #pragma GCC diagnostic pop
171 ASSERT_EQ(KERN_SUCCESS, kr);
173 base::Process child = base::SpawnMultiProcessTestChild(
174 "GetSenderPID",
175 base::GetMultiProcessTestChildBaseCommandLine(),
176 base::LaunchOptions());
177 ASSERT_TRUE(child.IsValid());
179 int exit_code = -1;
180 ASSERT_TRUE(child.WaitForExit(&exit_code));
181 EXPECT_EQ(0, exit_code);
183 EXPECT_EQ(child.Pid(), sender_pid);
184 EXPECT_EQ(child.Pid(), child_pid);
185 EXPECT_EQ(sender_pid, child_pid);
188 MULTIPROCESS_TEST_MAIN(GetSenderPID) {
189 CHECK(sandbox::InitializeXPC());
191 mach_port_t port = MACH_PORT_NULL;
192 CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, kGetSenderPID,
193 &port));
194 base::mac::ScopedMachSendRight scoped_port(port);
196 xpc_pipe_t pipe = xpc_pipe_create_from_port(port, 0);
198 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
199 xpc_dictionary_set_int64(message, "child_pid", getpid());
200 CHECK_EQ(0, xpc_pipe_simpleroutine(pipe, message));
202 xpc_release(message);
203 xpc_release(pipe);
205 return 0;
208 XPC_TEST_F(ForwardMessage) // {
209 BlockDemuxer first;
210 XPCMessageServer* first_server = first.server();
212 BlockDemuxer second;
213 XPCMessageServer* second_server = second.server();
215 ASSERT_TRUE(first.Initialize(^(IPCMessage request) {
216 xpc_dictionary_set_int64(request.xpc, "seen_by_first", 1);
217 first_server->ForwardMessage(request, second_server->GetServerPort());
218 }));
219 ASSERT_TRUE(second.Initialize(^(IPCMessage request) {
220 IPCMessage reply = second_server->CreateReply(request);
221 xpc_dictionary_set_int64(reply.xpc, "seen_by_first",
222 xpc_dictionary_get_int64(request.xpc, "seen_by_first"));
223 xpc_dictionary_set_int64(reply.xpc, "seen_by_second", 2);
224 second_server->SendReply(reply);
225 }));
227 xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
228 xpc_object_t reply;
229 ASSERT_EQ(0, xpc_pipe_routine(first.pipe(), request, &reply));
231 EXPECT_EQ(1, xpc_dictionary_get_int64(reply, "seen_by_first"));
232 EXPECT_EQ(2, xpc_dictionary_get_int64(reply, "seen_by_second"));
234 xpc_release(request);
235 xpc_release(reply);
238 } // namespace sandbox