Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / embedder / platform_channel_pair_posix_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 "mojo/embedder/platform_channel_pair.h"
6
7 #include <errno.h>
8 #include <poll.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
15
16 #include <deque>
17
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/files/scoped_file.h"
21 #include "base/files/scoped_temp_dir.h"
22 #include "base/logging.h"
23 #include "base/macros.h"
24 #include "mojo/common/test/test_utils.h"
25 #include "mojo/embedder/platform_channel_utils_posix.h"
26 #include "mojo/embedder/platform_handle.h"
27 #include "mojo/embedder/platform_handle_vector.h"
28 #include "mojo/embedder/scoped_platform_handle.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 namespace mojo {
32 namespace embedder {
33 namespace {
34
35 void WaitReadable(PlatformHandle h) {
36   struct pollfd pfds = {};
37   pfds.fd = h.fd;
38   pfds.events = POLLIN;
39   CHECK_EQ(poll(&pfds, 1, -1), 1);
40 }
41
42 class PlatformChannelPairPosixTest : public testing::Test {
43  public:
44   PlatformChannelPairPosixTest() {}
45   virtual ~PlatformChannelPairPosixTest() {}
46
47   virtual void SetUp() OVERRIDE {
48     // Make sure |SIGPIPE| isn't being ignored.
49     struct sigaction action = {};
50     action.sa_handler = SIG_DFL;
51     ASSERT_EQ(0, sigaction(SIGPIPE, &action, &old_action_));
52   }
53
54   virtual void TearDown() OVERRIDE {
55     // Restore the |SIGPIPE| handler.
56     ASSERT_EQ(0, sigaction(SIGPIPE, &old_action_, nullptr));
57   }
58
59  private:
60   struct sigaction old_action_;
61
62   DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest);
63 };
64
65 TEST_F(PlatformChannelPairPosixTest, NoSigPipe) {
66   PlatformChannelPair channel_pair;
67   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
68   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
69
70   // Write to the client.
71   static const char kHello[] = "hello";
72   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
73             write(client_handle.get().fd, kHello, sizeof(kHello)));
74
75   // Close the client.
76   client_handle.reset();
77
78   // Read from the server; this should be okay.
79   char buffer[100] = {};
80   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
81             read(server_handle.get().fd, buffer, sizeof(buffer)));
82   EXPECT_STREQ(kHello, buffer);
83
84   // Try reading again.
85   ssize_t result = read(server_handle.get().fd, buffer, sizeof(buffer));
86   // We should probably get zero (for "end of file"), but -1 would also be okay.
87   EXPECT_TRUE(result == 0 || result == -1);
88   if (result == -1)
89     PLOG(WARNING) << "read (expected 0 for EOF)";
90
91   // Test our replacement for |write()|/|send()|.
92   result = PlatformChannelWrite(server_handle.get(), kHello, sizeof(kHello));
93   EXPECT_EQ(-1, result);
94   if (errno != EPIPE)
95     PLOG(WARNING) << "write (expected EPIPE)";
96
97   // Test our replacement for |writev()|/|sendv()|.
98   struct iovec iov[2] = {{const_cast<char*>(kHello), sizeof(kHello)},
99                          {const_cast<char*>(kHello), sizeof(kHello)}};
100   result = PlatformChannelWritev(server_handle.get(), iov, 2);
101   EXPECT_EQ(-1, result);
102   if (errno != EPIPE)
103     PLOG(WARNING) << "write (expected EPIPE)";
104 }
105
106 TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
107   PlatformChannelPair channel_pair;
108   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
109   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
110
111   for (size_t i = 0; i < 10; i++) {
112     std::string send_string(1 << i, 'A' + i);
113
114     EXPECT_EQ(static_cast<ssize_t>(send_string.size()),
115               PlatformChannelWrite(
116                   server_handle.get(), send_string.data(), send_string.size()));
117
118     WaitReadable(client_handle.get());
119
120     char buf[10000] = {};
121     std::deque<PlatformHandle> received_handles;
122     ssize_t result = PlatformChannelRecvmsg(
123         client_handle.get(), buf, sizeof(buf), &received_handles);
124     EXPECT_EQ(static_cast<ssize_t>(send_string.size()), result);
125     EXPECT_EQ(send_string, std::string(buf, static_cast<size_t>(result)));
126     EXPECT_TRUE(received_handles.empty());
127   }
128 }
129
130 TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
131   base::ScopedTempDir temp_dir;
132   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
133
134   static const char kHello[] = "hello";
135
136   PlatformChannelPair channel_pair;
137   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
138   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
139
140   for (size_t i = 1; i < kPlatformChannelMaxNumHandles; i++) {
141     // Make |i| files, with the j-th file consisting of j copies of the digit i.
142     PlatformHandleVector platform_handles;
143     for (size_t j = 1; j <= i; j++) {
144       base::FilePath unused;
145       base::ScopedFILE fp(
146           base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
147       ASSERT_TRUE(fp);
148       ASSERT_EQ(j, fwrite(std::string(j, '0' + i).data(), 1, j, fp.get()));
149       platform_handles.push_back(
150           test::PlatformHandleFromFILE(fp.Pass()).release());
151       ASSERT_TRUE(platform_handles.back().is_valid());
152     }
153
154     // Send the FDs (+ "hello").
155     struct iovec iov = {const_cast<char*>(kHello), sizeof(kHello)};
156     // We assume that the |sendmsg()| actually sends all the data.
157     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
158               PlatformChannelSendmsgWithHandles(server_handle.get(),
159                                                 &iov,
160                                                 1,
161                                                 &platform_handles[0],
162                                                 platform_handles.size()));
163
164     WaitReadable(client_handle.get());
165
166     char buf[100] = {};
167     std::deque<PlatformHandle> received_handles;
168     // We assume that the |recvmsg()| actually reads all the data.
169     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
170               PlatformChannelRecvmsg(
171                   client_handle.get(), buf, sizeof(buf), &received_handles));
172     EXPECT_STREQ(kHello, buf);
173     EXPECT_EQ(i, received_handles.size());
174
175     for (size_t j = 0; !received_handles.empty(); j++) {
176       base::ScopedFILE fp(test::FILEFromPlatformHandle(
177           ScopedPlatformHandle(received_handles.front()), "rb"));
178       received_handles.pop_front();
179       ASSERT_TRUE(fp);
180       rewind(fp.get());
181       char read_buf[100];
182       size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
183       EXPECT_EQ(j + 1, bytes_read);
184       EXPECT_EQ(std::string(j + 1, '0' + i), std::string(read_buf, bytes_read));
185     }
186   }
187 }
188
189 TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
190   base::ScopedTempDir temp_dir;
191   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
192
193   static const char kHello[] = "hello";
194
195   PlatformChannelPair channel_pair;
196   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
197   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
198
199   const std::string file_contents("hello world");
200
201   {
202     base::FilePath unused;
203     base::ScopedFILE fp(
204         base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused));
205     ASSERT_TRUE(fp);
206     ASSERT_EQ(file_contents.size(),
207               fwrite(file_contents.data(), 1, file_contents.size(), fp.get()));
208     PlatformHandleVector platform_handles;
209     platform_handles.push_back(
210         test::PlatformHandleFromFILE(fp.Pass()).release());
211     ASSERT_TRUE(platform_handles.back().is_valid());
212
213     // Send the FD (+ "hello").
214     struct iovec iov = {const_cast<char*>(kHello), sizeof(kHello)};
215     // We assume that the |sendmsg()| actually sends all the data.
216     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
217               PlatformChannelSendmsgWithHandles(server_handle.get(),
218                                                 &iov,
219                                                 1,
220                                                 &platform_handles[0],
221                                                 platform_handles.size()));
222   }
223
224   WaitReadable(client_handle.get());
225
226   // Start with an invalid handle in the deque.
227   std::deque<PlatformHandle> received_handles;
228   received_handles.push_back(PlatformHandle());
229
230   char buf[100] = {};
231   // We assume that the |recvmsg()| actually reads all the data.
232   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
233             PlatformChannelRecvmsg(
234                 client_handle.get(), buf, sizeof(buf), &received_handles));
235   EXPECT_STREQ(kHello, buf);
236   ASSERT_EQ(2u, received_handles.size());
237   EXPECT_FALSE(received_handles[0].is_valid());
238   EXPECT_TRUE(received_handles[1].is_valid());
239
240   {
241     base::ScopedFILE fp(test::FILEFromPlatformHandle(
242         ScopedPlatformHandle(received_handles[1]), "rb"));
243     received_handles[1] = PlatformHandle();
244     ASSERT_TRUE(fp);
245     rewind(fp.get());
246     char read_buf[100];
247     size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
248     EXPECT_EQ(file_contents.size(), bytes_read);
249     EXPECT_EQ(file_contents, std::string(read_buf, bytes_read));
250   }
251 }
252
253 }  // namespace
254 }  // namespace embedder
255 }  // namespace mojo