Skip to content

Commit

Permalink
Reland: Add some handle read/write helpers to mojo/common/test/test_u…
Browse files Browse the repository at this point in the history
…tils.h

This helps to refactor raw_channel_posix_unittest to run on multiple
platforms.

TEST=mojo_common_unittests,mojo_system_unittests
BUG=None
TBR=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/176063002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252822 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
yzshen@chromium.org committed Feb 22, 2014
1 parent 97a8178 commit b8e55f6
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 70 deletions.
60 changes: 10 additions & 50 deletions mojo/common/test/multiprocess_test_base_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,19 @@

#include "base/logging.h"
#include "build/build_config.h"
#include "mojo/common/test/test_utils.h"
#include "mojo/system/embedder/scoped_platform_handle.h"

#if defined(OS_POSIX)
#include <fcntl.h>
#include <unistd.h>

#include "base/posix/eintr_wrapper.h"
#endif

#if defined(OS_WIN)
#include <windows.h>

#include "base/win/windows_version.h"
#endif

namespace mojo {
namespace test {
namespace {

// Returns true and logs a warning on Windows prior to Vista.
Expand All @@ -46,57 +43,19 @@ bool IsNonBlocking(const embedder::PlatformHandle& handle) {
#endif
}

// Note: On POSIX, this method sets the handle to block.
bool WriteByte(const embedder::PlatformHandle& handle, char c) {
#if defined(OS_WIN)
DWORD num_bytes_written = 0;
OVERLAPPED overlapped = { 0 };

if (!WriteFile(handle.handle, &c, 1, &num_bytes_written, &overlapped)) {
if (GetLastError() != ERROR_IO_PENDING)
return false;

if (GetOverlappedResult(handle.handle, &overlapped, &num_bytes_written,
TRUE)) {
return num_bytes_written == 1;
}

return false;
}
return num_bytes_written == 1;
#else
// We're lazy. Set it to block.
PCHECK(fcntl(handle.fd, F_SETFL, 0) == 0);

return HANDLE_EINTR(write(handle.fd, &c, 1)) == 1;
#endif
size_t bytes_written = 0;
BlockingWrite(handle, &c, 1, &bytes_written);
return bytes_written == 1;
}

// Note: On POSIX, this method sets the handle to block.
bool ReadByte(const embedder::PlatformHandle& handle, char* c) {
#if defined(OS_WIN)
DWORD num_bytes_read = 0;
OVERLAPPED overlapped = { 0 };

if (!ReadFile(handle.handle, c, 1, &num_bytes_read, &overlapped)) {
if (GetLastError() != ERROR_IO_PENDING)
return false;

if (GetOverlappedResult(handle.handle, &overlapped, &num_bytes_read, TRUE))
return num_bytes_read == 1;

return false;
}
return num_bytes_read == 1;
#else
// We're lazy. Set it to block.
PCHECK(fcntl(handle.fd, F_SETFL, 0) == 0);

return HANDLE_EINTR(read(handle.fd, c, 1)) == 1;
#endif
size_t bytes_read = 0;
BlockingRead(handle, c, 1, &bytes_read);
return bytes_read == 1;
}

typedef test::MultiprocessTestBase MultiprocessTestBaseTest;
typedef MultiprocessTestBase MultiprocessTestBaseTest;

TEST_F(MultiprocessTestBaseTest, RunChild) {
if (SkipTest())
Expand Down Expand Up @@ -172,4 +131,5 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) {
}

} // namespace
} // namespace test
} // namespace mojo
44 changes: 44 additions & 0 deletions mojo/common/test/test_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2014 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.

#ifndef MOJO_COMMON_TEST_TEST_UTILS_H_
#define MOJO_COMMON_TEST_TEST_UTILS_H_

#include <stddef.h>

namespace mojo {

namespace embedder {
struct PlatformHandle;
}

namespace test {

// On success, |bytes_written| is updated to the number of bytes written;
// otherwise it is untouched.
bool BlockingWrite(const embedder::PlatformHandle& handle,
const void* buffer,
size_t bytes_to_write,
size_t* bytes_written);

// On success, |bytes_read| is updated to the number of bytes read; otherwise it
// is untouched.
bool BlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read);

// If the read is done successfully or would block, the function returns true
// and updates |bytes_read| to the number of bytes read (0 if the read would
// block); otherwise it returns false and leaves |bytes_read| untouched.
// |handle| must already be in non-blocking mode.
bool NonBlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read);

} // namespace test
} // namespace mojo

#endif // MOJO_COMMON_TEST_TEST_UTILS_H_
77 changes: 77 additions & 0 deletions mojo/common/test/test_utils_posix.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2014 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/common/test/test_utils.h"

#include <fcntl.h>
#include <unistd.h>

#include "base/posix/eintr_wrapper.h"
#include "mojo/system/embedder/platform_handle.h"

namespace mojo {
namespace test {

bool BlockingWrite(const embedder::PlatformHandle& handle,
const void* buffer,
size_t bytes_to_write,
size_t* bytes_written) {
int original_flags = fcntl(handle.fd, F_GETFL);
if (original_flags == -1 ||
fcntl(handle.fd, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) {
return false;
}

ssize_t result = HANDLE_EINTR(write(handle.fd, buffer, bytes_to_write));

fcntl(handle.fd, F_SETFL, original_flags);

if (result < 0)
return false;

*bytes_written = result;
return true;
}

bool BlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read) {
int original_flags = fcntl(handle.fd, F_GETFL);
if (original_flags == -1 ||
fcntl(handle.fd, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) {
return false;
}

ssize_t result = HANDLE_EINTR(read(handle.fd, buffer, buffer_size));

fcntl(handle.fd, F_SETFL, original_flags);

if (result < 0)
return false;

*bytes_read = result;
return true;
}

bool NonBlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read) {
ssize_t result = HANDLE_EINTR(read(handle.fd, buffer, buffer_size));

if (result < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK)
return false;

*bytes_read = 0;
} else {
*bytes_read = result;
}

return true;
}

} // namespace test
} // namespace mojo
80 changes: 80 additions & 0 deletions mojo/common/test/test_utils_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2014 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/common/test/test_utils.h"

#include <windows.h>

#include "mojo/system/embedder/platform_handle.h"

namespace mojo {
namespace test {

bool BlockingWrite(const embedder::PlatformHandle& handle,
const void* buffer,
size_t bytes_to_write,
size_t* bytes_written) {
OVERLAPPED overlapped = { 0 };
DWORD bytes_written_dword = 0;

if (!WriteFile(handle.handle, buffer, static_cast<DWORD>(bytes_to_write),
&bytes_written_dword, &overlapped)) {
if (GetLastError() != ERROR_IO_PENDING ||
!GetOverlappedResult(handle.handle, &overlapped, &bytes_written_dword,
TRUE)) {
return false;
}
}

*bytes_written = bytes_written_dword;
return true;
}

bool BlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read) {
OVERLAPPED overlapped = { 0 };
DWORD bytes_read_dword = 0;

if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size),
&bytes_read_dword, &overlapped)) {
if (GetLastError() != ERROR_IO_PENDING ||
!GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword,
TRUE)) {
return false;
}
}

*bytes_read = bytes_read_dword;
return true;
}

bool NonBlockingRead(const embedder::PlatformHandle& handle,
void* buffer,
size_t buffer_size,
size_t* bytes_read) {
OVERLAPPED overlapped = { 0 };
DWORD bytes_read_dword = 0;

if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size),
&bytes_read_dword, &overlapped)) {
if (GetLastError() != ERROR_IO_PENDING)
return false;

CancelIo(handle.handle);

if (!GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword,
TRUE)) {
*bytes_read = 0;
return true;
}
}

*bytes_read = bytes_read_dword;
return true;
}

} // namespace test
} // namespace mojo
3 changes: 3 additions & 0 deletions mojo/mojo.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@
'sources': [
'common/test/multiprocess_test_base.cc',
'common/test/multiprocess_test_base.h',
'common/test/test_utils.h',
'common/test/test_utils_posix.cc',
'common/test/test_utils_win.cc',
],
},
{
Expand Down
28 changes: 8 additions & 20 deletions mojo/system/raw_channel_posix_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

#include "mojo/system/raw_channel.h"

#include <fcntl.h>
#include <stdint.h>
#include <sys/socket.h>
#include <unistd.h>

#include <vector>

Expand All @@ -22,13 +19,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h" // For |Sleep()|.
#include "base/threading/simple_thread.h"
#include "base/time/time.h"
#include "mojo/common/test/test_utils.h"
#include "mojo/system/embedder/platform_channel_pair.h"
#include "mojo/system/embedder/platform_handle.h"
#include "mojo/system/embedder/scoped_platform_handle.h"
Expand Down Expand Up @@ -67,10 +64,10 @@ bool WriteTestMessageToHandle(const embedder::PlatformHandle& handle,
uint32_t num_bytes) {
scoped_ptr<MessageInTransit> message(MakeTestMessage(num_bytes));

ssize_t write_size = HANDLE_EINTR(
write(handle.fd, message->main_buffer(), message->main_buffer_size()));
bool result = write_size == static_cast<ssize_t>(message->main_buffer_size());
return result;
size_t write_size = 0;
mojo::test::BlockingWrite(
handle, message->main_buffer(), message->main_buffer_size(), &write_size);
return write_size == message->main_buffer_size();
}

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -134,12 +131,9 @@ class TestMessageReaderAndChecker {
unsigned char buffer[4096];

for (size_t i = 0; i < kMessageReaderMaxPollIterations;) {
ssize_t read_size = HANDLE_EINTR(
read(handle_.fd, buffer, sizeof(buffer)));
if (read_size < 0) {
PCHECK(errno == EAGAIN || errno == EWOULDBLOCK);
read_size = 0;
}
size_t read_size = 0;
CHECK(mojo::test::NonBlockingRead(handle_, buffer, sizeof(buffer),
&read_size));

// Append newly-read data to |bytes_|.
bytes_.insert(bytes_.end(), buffer, buffer + read_size);
Expand Down Expand Up @@ -285,9 +279,6 @@ class ReadCheckerRawChannelDelegate : public RawChannel::Delegate {

// Tests reading (writing using our own custom writer).
TEST_F(RawChannelPosixTest, OnReadMessage) {
// We're going to write to |fd(1)|. We'll do so in a blocking manner.
PCHECK(fcntl(handles[1].get().fd, F_SETFL, 0) == 0);

ReadCheckerRawChannelDelegate delegate;
scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass(),
&delegate,
Expand Down Expand Up @@ -481,9 +472,6 @@ class FatalErrorRecordingRawChannelDelegate
TEST_F(RawChannelPosixTest, OnFatalError) {
const size_t kMessageCount = 5;

// We're going to write to |fd(1)|. We'll do so in a blocking manner.
PCHECK(fcntl(handles[1].get().fd, F_SETFL, 0) == 0);

FatalErrorRecordingRawChannelDelegate delegate(2 * kMessageCount);
scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass(),
&delegate,
Expand Down

0 comments on commit b8e55f6

Please sign in to comment.