// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/edk/test/multiprocess_test_helper.h"
#include <stddef.h>
#include <utility>
#include "base/logging.h"
#include "build/build_config.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/test_utils.h"
#include "mojo/edk/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_POSIX)
#include <fcntl.h>
#endif
namespace mojo {
namespace edk {
namespace test {
namespace {
bool IsNonBlocking(const PlatformHandle& handle) {
#if defined(OS_WIN)
// Haven't figured out a way to query whether a HANDLE was created with
// FILE_FLAG_OVERLAPPED.
return true;
#else
return fcntl(handle.handle, F_GETFL) & O_NONBLOCK;
#endif
}
bool WriteByte(const PlatformHandle& handle, char c) {
size_t bytes_written = 0;
BlockingWrite(handle, &c, 1, &bytes_written);
return bytes_written == 1;
}
bool ReadByte(const PlatformHandle& handle, char* c) {
size_t bytes_read = 0;
BlockingRead(handle, c, 1, &bytes_read);
return bytes_read == 1;
}
using MultiprocessTestHelperTest = testing::Test;
TEST_F(MultiprocessTestHelperTest, RunChild) {
MultiprocessTestHelper helper;
EXPECT_TRUE(helper.server_platform_handle.is_valid());
helper.StartChild("RunChild");
EXPECT_EQ(123, helper.WaitForChildShutdown());
}
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) {
CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
return 123;
}
TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) {
MultiprocessTestHelper helper;
helper.StartChild("NoSuchTestChildMain");
int result = helper.WaitForChildShutdown();
EXPECT_FALSE(result >= 0 && result <= 127);
}
TEST_F(MultiprocessTestHelperTest, PassedChannel) {
MultiprocessTestHelper helper;
EXPECT_TRUE(helper.server_platform_handle.is_valid());
helper.StartChild("PassedChannel");
// Take ownership of the handle.
ScopedPlatformHandle handle = std::move(helper.server_platform_handle);
// The handle should be non-blocking.
EXPECT_TRUE(IsNonBlocking(handle.get()));
// Write a byte.
const char c = 'X';
EXPECT_TRUE(WriteByte(handle.get(), c));
// It'll echo it back to us, incremented.
char d = 0;
EXPECT_TRUE(ReadByte(handle.get(), &d));
EXPECT_EQ(c + 1, d);
// And return it, incremented again.
EXPECT_EQ(c + 2, helper.WaitForChildShutdown());
}
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) {
CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
// Take ownership of the handle.
ScopedPlatformHandle handle =
std::move(MultiprocessTestHelper::client_platform_handle);
// The handle should be non-blocking.
EXPECT_TRUE(IsNonBlocking(handle.get()));
// Read a byte.
char c = 0;
EXPECT_TRUE(ReadByte(handle.get(), &c));
// Write it back, incremented.
c++;
EXPECT_TRUE(WriteByte(handle.get(), c));
// And return it, incremented again.
c++;
return static_cast<int>(c);
}
TEST_F(MultiprocessTestHelperTest, ChildTestPasses) {
MultiprocessTestHelper helper;
EXPECT_TRUE(helper.server_platform_handle.is_valid());
helper.StartChild("ChildTestPasses");
EXPECT_TRUE(helper.WaitForChildTestShutdown());
}
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses) {
ASSERT_TRUE(MultiprocessTestHelper::client_platform_handle.is_valid());
EXPECT_TRUE(
IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()));
}
TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) {
MultiprocessTestHelper helper;
EXPECT_TRUE(helper.server_platform_handle.is_valid());
helper.StartChild("ChildTestFailsAssert");
EXPECT_FALSE(helper.WaitForChildTestShutdown());
}
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert) {
ASSERT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
<< "DISREGARD: Expected failure in child process";
ASSERT_FALSE(
IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
<< "Not reached";
CHECK(false) << "Not reached";
}
TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) {
MultiprocessTestHelper helper;
EXPECT_TRUE(helper.server_platform_handle.is_valid());
helper.StartChild("ChildTestFailsExpect");
EXPECT_FALSE(helper.WaitForChildTestShutdown());
}
MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsExpect) {
EXPECT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
<< "DISREGARD: Expected failure #1 in child process";
EXPECT_FALSE(
IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
<< "DISREGARD: Expected failure #2 in child process";
}
} // namespace
} // namespace test
} // namespace edk
} // namespace mojo