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