Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / sandbox / mac / xpc_message_server_unittest.cc
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.
4
5 #include "sandbox/mac/xpc_message_server.h"
6
7 #include <Block.h>
8 #include <mach/mach.h>
9 #include <servers/bootstrap.h>
10
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"
20
21 namespace sandbox {
22
23 class XPCMessageServerTest : public testing::Test {
24  public:
25   virtual void SetUp() OVERRIDE {
26     if (!RunXPCTest())
27       return;
28     ASSERT_TRUE(InitializeXPC());
29   }
30
31   bool RunXPCTest() {
32     return base::mac::IsOSMountainLionOrLater();
33   }
34 };
35
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) {
44   }
45
46   virtual ~BlockDemuxer() {
47     if (pipe_)
48       xpc_release(pipe_);
49     if (demux_block_)
50       Block_release(demux_block_);
51   }
52
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;
57
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;
62     }
63     scoped_send_right_.reset(server_.GetServerPort());
64
65     demux_block_ = Block_copy(demux_block);
66     pipe_ = xpc_pipe_create_from_port(server_.GetServerPort(), 0);
67
68     return true;
69   }
70
71   virtual void DemuxMessage(IPCMessage request) OVERRIDE {
72     demux_block_(request);
73   }
74
75   xpc_pipe_t pipe() { return pipe_; }
76
77   XPCMessageServer* server() { return &server_; }
78
79  private:
80   void (^demux_block_)(IPCMessage request);
81
82   XPCMessageServer server_;
83
84   base::mac::ScopedMachSendRight scoped_send_right_;
85
86   xpc_pipe_t pipe_;
87 };
88
89 #define XPC_TEST_F(name) TEST_F(XPCMessageServerTest, name) { \
90     if (!RunXPCTest()) \
91       return; \
92
93 XPC_TEST_F(ReceiveMessage)  // {
94   BlockDemuxer fixture;
95   XPCMessageServer* server = fixture.server();
96
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   }));
102
103   xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
104   xpc_dictionary_set_uint64(request, "test_value", 42);
105
106   xpc_object_t reply;
107   EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
108
109   EXPECT_EQ(42u, value);
110
111   xpc_release(request);
112   xpc_release(reply);
113 }
114
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   }));
121
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));
125
126   EXPECT_EQ(EPERM, xpc_dictionary_get_int64(reply, "error"));
127
128   xpc_release(request);
129   xpc_release(reply);
130 }
131
132 char kGetSenderPID[] = "org.chromium.sandbox.test.GetSenderPID";
133
134 XPC_TEST_F(GetSenderPID)  // {
135   BlockDemuxer fixture;
136   XPCMessageServer* server = fixture.server();
137
138   pid_t __block sender_pid = 0;
139   int64_t __block child_pid = 0;
140   ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
141       sender_pid = server->GetMessageSenderPID(request);
142       child_pid = xpc_dictionary_get_int64(request.xpc, "child_pid");
143   }));
144
145 #pragma GCC diagnostic push
146 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
147   kern_return_t kr = bootstrap_register(bootstrap_port, kGetSenderPID,
148       server->GetServerPort());
149 #pragma GCC diagnostic pop
150   ASSERT_EQ(KERN_SUCCESS, kr);
151
152   base::ProcessHandle child_handle = base::SpawnMultiProcessTestChild(
153       "GetSenderPID",
154       base::GetMultiProcessTestChildBaseCommandLine(),
155       base::LaunchOptions());
156   ASSERT_NE(base::kNullProcessHandle, child_handle);
157
158   int exit_code = -1;
159   ASSERT_TRUE(base::WaitForExitCode(child_handle, &exit_code));
160   EXPECT_EQ(0, exit_code);
161
162   EXPECT_EQ(base::GetProcId(child_handle), sender_pid);
163   EXPECT_EQ(base::GetProcId(child_handle), child_pid);
164   EXPECT_EQ(sender_pid, child_pid);
165
166   base::CloseProcessHandle(child_handle);
167 }
168
169 MULTIPROCESS_TEST_MAIN(GetSenderPID) {
170   CHECK(sandbox::InitializeXPC());
171
172   mach_port_t port = MACH_PORT_NULL;
173   CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, kGetSenderPID,
174       &port));
175   base::mac::ScopedMachSendRight scoped_port(port);
176
177   xpc_pipe_t pipe = xpc_pipe_create_from_port(port, 0);
178
179   xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
180   xpc_dictionary_set_int64(message, "child_pid", getpid());
181   CHECK_EQ(0, xpc_pipe_simpleroutine(pipe, message));
182
183   xpc_release(message);
184   xpc_release(pipe);
185
186   return 0;
187 }
188
189 XPC_TEST_F(ForwardMessage)  // {
190   BlockDemuxer first;
191   XPCMessageServer* first_server = first.server();
192
193   BlockDemuxer second;
194   XPCMessageServer* second_server = second.server();
195
196   ASSERT_TRUE(first.Initialize(^(IPCMessage request) {
197       xpc_dictionary_set_int64(request.xpc, "seen_by_first", 1);
198       first_server->ForwardMessage(request, second_server->GetServerPort());
199   }));
200   ASSERT_TRUE(second.Initialize(^(IPCMessage request) {
201       IPCMessage reply = second_server->CreateReply(request);
202       xpc_dictionary_set_int64(reply.xpc, "seen_by_first",
203           xpc_dictionary_get_int64(request.xpc, "seen_by_first"));
204       xpc_dictionary_set_int64(reply.xpc, "seen_by_second", 2);
205       second_server->SendReply(reply);
206   }));
207
208   xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
209   xpc_object_t reply;
210   ASSERT_EQ(0, xpc_pipe_routine(first.pipe(), request, &reply));
211
212   EXPECT_EQ(1, xpc_dictionary_get_int64(reply, "seen_by_first"));
213   EXPECT_EQ(2, xpc_dictionary_get_int64(reply, "seen_by_second"));
214
215   xpc_release(request);
216   xpc_release(reply);
217 }
218
219 }  // namespace sandbox