1 // Copyright 2013 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/edk/test/multiprocess_test_helper.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "mojo/edk/embedder/scoped_platform_handle.h"
14 #include "mojo/edk/system/test_utils.h"
15 #include "mojo/edk/test/test_utils.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 #if defined(OS_POSIX)
19 #include <fcntl.h>
20 #endif
21
22 namespace mojo {
23 namespace edk {
24 namespace test {
25 namespace {
26
IsNonBlocking(const PlatformHandle & handle)27 bool IsNonBlocking(const PlatformHandle& handle) {
28 #if defined(OS_WIN)
29 // Haven't figured out a way to query whether a HANDLE was created with
30 // FILE_FLAG_OVERLAPPED.
31 return true;
32 #else
33 return fcntl(handle.handle, F_GETFL) & O_NONBLOCK;
34 #endif
35 }
36
WriteByte(const PlatformHandle & handle,char c)37 bool WriteByte(const PlatformHandle& handle, char c) {
38 size_t bytes_written = 0;
39 BlockingWrite(handle, &c, 1, &bytes_written);
40 return bytes_written == 1;
41 }
42
ReadByte(const PlatformHandle & handle,char * c)43 bool ReadByte(const PlatformHandle& handle, char* c) {
44 size_t bytes_read = 0;
45 BlockingRead(handle, c, 1, &bytes_read);
46 return bytes_read == 1;
47 }
48
49 using MultiprocessTestHelperTest = testing::Test;
50
TEST_F(MultiprocessTestHelperTest,RunChild)51 TEST_F(MultiprocessTestHelperTest, RunChild) {
52 MultiprocessTestHelper helper;
53 EXPECT_TRUE(helper.server_platform_handle.is_valid());
54
55 helper.StartChild("RunChild");
56 EXPECT_EQ(123, helper.WaitForChildShutdown());
57 }
58
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild)59 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) {
60 CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
61 return 123;
62 }
63
TEST_F(MultiprocessTestHelperTest,TestChildMainNotFound)64 TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) {
65 MultiprocessTestHelper helper;
66 helper.StartChild("NoSuchTestChildMain");
67 int result = helper.WaitForChildShutdown();
68 EXPECT_FALSE(result >= 0 && result <= 127);
69 }
70
TEST_F(MultiprocessTestHelperTest,PassedChannel)71 TEST_F(MultiprocessTestHelperTest, PassedChannel) {
72 MultiprocessTestHelper helper;
73 EXPECT_TRUE(helper.server_platform_handle.is_valid());
74 helper.StartChild("PassedChannel");
75
76 // Take ownership of the handle.
77 ScopedPlatformHandle handle = std::move(helper.server_platform_handle);
78
79 // The handle should be non-blocking.
80 EXPECT_TRUE(IsNonBlocking(handle.get()));
81
82 // Write a byte.
83 const char c = 'X';
84 EXPECT_TRUE(WriteByte(handle.get(), c));
85
86 // It'll echo it back to us, incremented.
87 char d = 0;
88 EXPECT_TRUE(ReadByte(handle.get(), &d));
89 EXPECT_EQ(c + 1, d);
90
91 // And return it, incremented again.
92 EXPECT_EQ(c + 2, helper.WaitForChildShutdown());
93 }
94
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel)95 MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) {
96 CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
97
98 // Take ownership of the handle.
99 ScopedPlatformHandle handle =
100 std::move(MultiprocessTestHelper::client_platform_handle);
101
102 // The handle should be non-blocking.
103 EXPECT_TRUE(IsNonBlocking(handle.get()));
104
105 // Read a byte.
106 char c = 0;
107 EXPECT_TRUE(ReadByte(handle.get(), &c));
108
109 // Write it back, incremented.
110 c++;
111 EXPECT_TRUE(WriteByte(handle.get(), c));
112
113 // And return it, incremented again.
114 c++;
115 return static_cast<int>(c);
116 }
117
TEST_F(MultiprocessTestHelperTest,ChildTestPasses)118 TEST_F(MultiprocessTestHelperTest, ChildTestPasses) {
119 MultiprocessTestHelper helper;
120 EXPECT_TRUE(helper.server_platform_handle.is_valid());
121 helper.StartChild("ChildTestPasses");
122 EXPECT_TRUE(helper.WaitForChildTestShutdown());
123 }
124
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses)125 MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses) {
126 ASSERT_TRUE(MultiprocessTestHelper::client_platform_handle.is_valid());
127 EXPECT_TRUE(
128 IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()));
129 }
130
TEST_F(MultiprocessTestHelperTest,ChildTestFailsAssert)131 TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) {
132 MultiprocessTestHelper helper;
133 EXPECT_TRUE(helper.server_platform_handle.is_valid());
134 helper.StartChild("ChildTestFailsAssert");
135 EXPECT_FALSE(helper.WaitForChildTestShutdown());
136 }
137
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert)138 MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert) {
139 ASSERT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
140 << "DISREGARD: Expected failure in child process";
141 ASSERT_FALSE(
142 IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
143 << "Not reached";
144 CHECK(false) << "Not reached";
145 }
146
TEST_F(MultiprocessTestHelperTest,ChildTestFailsExpect)147 TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) {
148 MultiprocessTestHelper helper;
149 EXPECT_TRUE(helper.server_platform_handle.is_valid());
150 helper.StartChild("ChildTestFailsExpect");
151 EXPECT_FALSE(helper.WaitForChildTestShutdown());
152 }
153
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsExpect)154 MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsExpect) {
155 EXPECT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
156 << "DISREGARD: Expected failure #1 in child process";
157 EXPECT_FALSE(
158 IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
159 << "DISREGARD: Expected failure #2 in child process";
160 }
161
162 } // namespace
163 } // namespace test
164 } // namespace edk
165 } // namespace mojo
166