diff options
Diffstat (limited to 'mojo/edk/system/raw_channel_unittest.cc')
-rw-r--r-- | mojo/edk/system/raw_channel_unittest.cc | 805 |
1 files changed, 0 insertions, 805 deletions
diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc deleted file mode 100644 index a8cbcba..0000000 --- a/mojo/edk/system/raw_channel_unittest.cc +++ /dev/null @@ -1,805 +0,0 @@ -// 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/edk/system/raw_channel.h" - -#include <stdint.h> -#include <stdio.h> - -#include <vector> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" -#include "base/rand_util.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/test_io_thread.h" -#include "base/threading/platform_thread.h" // For |Sleep()|. -#include "base/threading/simple_thread.h" -#include "base/time/time.h" -#include "build/build_config.h" // TODO(vtl): Remove this. -#include "mojo/edk/embedder/platform_channel_pair.h" -#include "mojo/edk/embedder/platform_handle.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" -#include "mojo/edk/system/message_in_transit.h" -#include "mojo/edk/system/test_utils.h" -#include "mojo/edk/system/transport_data.h" -#include "mojo/edk/test/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace system { -namespace { - -scoped_ptr<MessageInTransit> MakeTestMessage(uint32_t num_bytes) { - std::vector<unsigned char> bytes(num_bytes, 0); - for (size_t i = 0; i < num_bytes; i++) - bytes[i] = static_cast<unsigned char>(i + num_bytes); - return make_scoped_ptr(new MessageInTransit( - MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, - num_bytes, bytes.empty() ? nullptr : &bytes[0])); -} - -bool CheckMessageData(const void* bytes, uint32_t num_bytes) { - const unsigned char* b = static_cast<const unsigned char*>(bytes); - for (uint32_t i = 0; i < num_bytes; i++) { - if (b[i] != static_cast<unsigned char>(i + num_bytes)) - return false; - } - return true; -} - -void InitOnIOThread(RawChannel* raw_channel, RawChannel::Delegate* delegate) { - raw_channel->Init(delegate); -} - -bool WriteTestMessageToHandle(const embedder::PlatformHandle& handle, - uint32_t num_bytes) { - scoped_ptr<MessageInTransit> message(MakeTestMessage(num_bytes)); - - 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(); -} - -// ----------------------------------------------------------------------------- - -class RawChannelTest : public testing::Test { - public: - RawChannelTest() : io_thread_(base::TestIOThread::kManualStart) {} - ~RawChannelTest() override {} - - void SetUp() override { - embedder::PlatformChannelPair channel_pair; - handles[0] = channel_pair.PassServerHandle(); - handles[1] = channel_pair.PassClientHandle(); - io_thread_.Start(); - } - - void TearDown() override { - io_thread_.Stop(); - handles[0].reset(); - handles[1].reset(); - } - - protected: - base::TestIOThread* io_thread() { return &io_thread_; } - - embedder::ScopedPlatformHandle handles[2]; - - private: - base::TestIOThread io_thread_; - - DISALLOW_COPY_AND_ASSIGN(RawChannelTest); -}; - -// RawChannelTest.WriteMessage ------------------------------------------------- - -class WriteOnlyRawChannelDelegate : public RawChannel::Delegate { - public: - WriteOnlyRawChannelDelegate() {} - ~WriteOnlyRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation: - void OnReadMessage( - const MessageInTransit::View& /*message_view*/, - embedder::ScopedPlatformHandleVectorPtr /*platform_handles*/) override { - CHECK(false); // Should not get called. - } - void OnError(Error error) override { - // We'll get a read (shutdown) error when the connection is closed. - CHECK_EQ(error, ERROR_READ_SHUTDOWN); - } - - private: - DISALLOW_COPY_AND_ASSIGN(WriteOnlyRawChannelDelegate); -}; - -static const int64_t kMessageReaderSleepMs = 1; -static const size_t kMessageReaderMaxPollIterations = 3000; - -class TestMessageReaderAndChecker { - public: - explicit TestMessageReaderAndChecker(embedder::PlatformHandle handle) - : handle_(handle) {} - ~TestMessageReaderAndChecker() { CHECK(bytes_.empty()); } - - bool ReadAndCheckNextMessage(uint32_t expected_size) { - unsigned char buffer[4096]; - - for (size_t i = 0; i < kMessageReaderMaxPollIterations;) { - 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); - - // If we have the header.... - size_t message_size; - if (MessageInTransit::GetNextMessageSize( - bytes_.empty() ? nullptr : &bytes_[0], bytes_.size(), - &message_size)) { - // If we've read the whole message.... - if (bytes_.size() >= message_size) { - bool rv = true; - MessageInTransit::View message_view(message_size, &bytes_[0]); - CHECK_EQ(message_view.main_buffer_size(), message_size); - - if (message_view.num_bytes() != expected_size) { - LOG(ERROR) << "Wrong size: " << message_size << " instead of " - << expected_size << " bytes."; - rv = false; - } else if (!CheckMessageData(message_view.bytes(), - message_view.num_bytes())) { - LOG(ERROR) << "Incorrect message bytes."; - rv = false; - } - - // Erase message data. - bytes_.erase(bytes_.begin(), - bytes_.begin() + message_view.main_buffer_size()); - return rv; - } - } - - if (static_cast<size_t>(read_size) < sizeof(buffer)) { - i++; - base::PlatformThread::Sleep( - base::TimeDelta::FromMilliseconds(kMessageReaderSleepMs)); - } - } - - LOG(ERROR) << "Too many iterations."; - return false; - } - - private: - const embedder::PlatformHandle handle_; - - // The start of the received data should always be on a message boundary. - std::vector<unsigned char> bytes_; - - DISALLOW_COPY_AND_ASSIGN(TestMessageReaderAndChecker); -}; - -// Tests writing (and verifies reading using our own custom reader). -TEST_F(RawChannelTest, WriteMessage) { - WriteOnlyRawChannelDelegate delegate; - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - TestMessageReaderAndChecker checker(handles[1].get()); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Write and read, for a variety of sizes. - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) { - EXPECT_TRUE(rc->WriteMessage(MakeTestMessage(size))); - EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size; - } - - // Write/queue and read afterwards, for a variety of sizes. - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) - EXPECT_TRUE(rc->WriteMessage(MakeTestMessage(size))); - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) - EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size; - - io_thread()->PostTaskAndWait( - FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); -} - -// RawChannelTest.OnReadMessage ------------------------------------------------ - -class ReadCheckerRawChannelDelegate : public RawChannel::Delegate { - public: - ReadCheckerRawChannelDelegate() : done_event_(false, false), position_(0) {} - ~ReadCheckerRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation (called on the I/O thread): - void OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) override { - EXPECT_FALSE(platform_handles); - - size_t position; - size_t expected_size; - bool should_signal = false; - { - base::AutoLock locker(lock_); - CHECK_LT(position_, expected_sizes_.size()); - position = position_; - expected_size = expected_sizes_[position]; - position_++; - if (position_ >= expected_sizes_.size()) - should_signal = true; - } - - EXPECT_EQ(expected_size, message_view.num_bytes()) << position; - if (message_view.num_bytes() == expected_size) { - EXPECT_TRUE( - CheckMessageData(message_view.bytes(), message_view.num_bytes())) - << position; - } - - if (should_signal) - done_event_.Signal(); - } - void OnError(Error error) override { - // We'll get a read (shutdown) error when the connection is closed. - CHECK_EQ(error, ERROR_READ_SHUTDOWN); - } - - // Waits for all the messages (of sizes |expected_sizes_|) to be seen. - void Wait() { done_event_.Wait(); } - - void SetExpectedSizes(const std::vector<uint32_t>& expected_sizes) { - base::AutoLock locker(lock_); - CHECK_EQ(position_, expected_sizes_.size()); - expected_sizes_ = expected_sizes; - position_ = 0; - } - - private: - base::WaitableEvent done_event_; - - base::Lock lock_; // Protects the following members. - std::vector<uint32_t> expected_sizes_; - size_t position_; - - DISALLOW_COPY_AND_ASSIGN(ReadCheckerRawChannelDelegate); -}; - -// Tests reading (writing using our own custom writer). -TEST_F(RawChannelTest, OnReadMessage) { - ReadCheckerRawChannelDelegate delegate; - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Write and read, for a variety of sizes. - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) { - delegate.SetExpectedSizes(std::vector<uint32_t>(1, size)); - - EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size)); - - delegate.Wait(); - } - - // Set up reader and write as fast as we can. - // Write/queue and read afterwards, for a variety of sizes. - std::vector<uint32_t> expected_sizes; - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) - expected_sizes.push_back(size); - delegate.SetExpectedSizes(expected_sizes); - for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) - EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size)); - delegate.Wait(); - - io_thread()->PostTaskAndWait( - FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); -} - -// RawChannelTest.WriteMessageAndOnReadMessage --------------------------------- - -class RawChannelWriterThread : public base::SimpleThread { - public: - RawChannelWriterThread(RawChannel* raw_channel, size_t write_count) - : base::SimpleThread("raw_channel_writer_thread"), - raw_channel_(raw_channel), - left_to_write_(write_count) {} - - ~RawChannelWriterThread() override { Join(); } - - private: - void Run() override { - static const int kMaxRandomMessageSize = 25000; - - while (left_to_write_-- > 0) { - EXPECT_TRUE(raw_channel_->WriteMessage(MakeTestMessage( - static_cast<uint32_t>(base::RandInt(1, kMaxRandomMessageSize))))); - } - } - - RawChannel* const raw_channel_; - size_t left_to_write_; - - DISALLOW_COPY_AND_ASSIGN(RawChannelWriterThread); -}; - -class ReadCountdownRawChannelDelegate : public RawChannel::Delegate { - public: - explicit ReadCountdownRawChannelDelegate(size_t expected_count) - : done_event_(false, false), expected_count_(expected_count), count_(0) {} - ~ReadCountdownRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation (called on the I/O thread): - void OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) override { - EXPECT_FALSE(platform_handles); - - EXPECT_LT(count_, expected_count_); - count_++; - - EXPECT_TRUE( - CheckMessageData(message_view.bytes(), message_view.num_bytes())); - - if (count_ >= expected_count_) - done_event_.Signal(); - } - void OnError(Error error) override { - // We'll get a read (shutdown) error when the connection is closed. - CHECK_EQ(error, ERROR_READ_SHUTDOWN); - } - - // Waits for all the messages to have been seen. - void Wait() { done_event_.Wait(); } - - private: - base::WaitableEvent done_event_; - size_t expected_count_; - size_t count_; - - DISALLOW_COPY_AND_ASSIGN(ReadCountdownRawChannelDelegate); -}; - -TEST_F(RawChannelTest, WriteMessageAndOnReadMessage) { - static const size_t kNumWriterThreads = 10; - static const size_t kNumWriteMessagesPerThread = 4000; - - WriteOnlyRawChannelDelegate writer_delegate; - scoped_ptr<RawChannel> writer_rc(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait(FROM_HERE, - base::Bind(&InitOnIOThread, writer_rc.get(), - base::Unretained(&writer_delegate))); - - ReadCountdownRawChannelDelegate reader_delegate(kNumWriterThreads * - kNumWriteMessagesPerThread); - scoped_ptr<RawChannel> reader_rc(RawChannel::Create(handles[1].Pass())); - io_thread()->PostTaskAndWait(FROM_HERE, - base::Bind(&InitOnIOThread, reader_rc.get(), - base::Unretained(&reader_delegate))); - - { - ScopedVector<RawChannelWriterThread> writer_threads; - for (size_t i = 0; i < kNumWriterThreads; i++) { - writer_threads.push_back(new RawChannelWriterThread( - writer_rc.get(), kNumWriteMessagesPerThread)); - } - for (size_t i = 0; i < writer_threads.size(); i++) - writer_threads[i]->Start(); - } // Joins all the writer threads. - - // Sleep a bit, to let any extraneous reads be processed. (There shouldn't be - // any, but we want to know about them.) - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); - - // Wait for reading to finish. - reader_delegate.Wait(); - - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&RawChannel::Shutdown, base::Unretained(reader_rc.get()))); - - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&RawChannel::Shutdown, base::Unretained(writer_rc.get()))); -} - -// RawChannelTest.OnError ------------------------------------------------------ - -class ErrorRecordingRawChannelDelegate - : public ReadCountdownRawChannelDelegate { - public: - ErrorRecordingRawChannelDelegate(size_t expected_read_count, - bool expect_read_error, - bool expect_write_error) - : ReadCountdownRawChannelDelegate(expected_read_count), - got_read_error_event_(false, false), - got_write_error_event_(false, false), - expecting_read_error_(expect_read_error), - expecting_write_error_(expect_write_error) {} - - ~ErrorRecordingRawChannelDelegate() override {} - - void OnError(Error error) override { - switch (error) { - case ERROR_READ_SHUTDOWN: - ASSERT_TRUE(expecting_read_error_); - expecting_read_error_ = false; - got_read_error_event_.Signal(); - break; - case ERROR_READ_BROKEN: - // TODO(vtl): Test broken connections. - CHECK(false); - break; - case ERROR_READ_BAD_MESSAGE: - // TODO(vtl): Test reception/detection of bad messages. - CHECK(false); - break; - case ERROR_READ_UNKNOWN: - // TODO(vtl): Test however it is we might get here. - CHECK(false); - break; - case ERROR_WRITE: - ASSERT_TRUE(expecting_write_error_); - expecting_write_error_ = false; - got_write_error_event_.Signal(); - break; - } - } - - void WaitForReadError() { got_read_error_event_.Wait(); } - void WaitForWriteError() { got_write_error_event_.Wait(); } - - private: - base::WaitableEvent got_read_error_event_; - base::WaitableEvent got_write_error_event_; - - bool expecting_read_error_; - bool expecting_write_error_; - - DISALLOW_COPY_AND_ASSIGN(ErrorRecordingRawChannelDelegate); -}; - -// Tests (fatal) errors. -TEST_F(RawChannelTest, OnError) { - ErrorRecordingRawChannelDelegate delegate(0, true, true); - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Close the handle of the other end, which should make writing fail. - handles[1].reset(); - - EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); - - // We should get a write error. - delegate.WaitForWriteError(); - - // We should also get a read error. - delegate.WaitForReadError(); - - EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(2))); - - // Sleep a bit, to make sure we don't get another |OnError()| - // notification. (If we actually get another one, |OnError()| crashes.) - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); - - io_thread()->PostTaskAndWait( - FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); -} - -// RawChannelTest.ReadUnaffectedByWriteError ----------------------------------- - -TEST_F(RawChannelTest, ReadUnaffectedByWriteError) { - const size_t kMessageCount = 5; - - // Write a few messages into the other end. - uint32_t message_size = 1; - for (size_t i = 0; i < kMessageCount; - i++, message_size += message_size / 2 + 1) - EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), message_size)); - - // Close the other end, which should make writing fail. - handles[1].reset(); - - // Only start up reading here. The system buffer should still contain the - // messages that were written. - ErrorRecordingRawChannelDelegate delegate(kMessageCount, true, true); - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); - - // We should definitely get a write error. - delegate.WaitForWriteError(); - - // Wait for reading to finish. A writing failure shouldn't affect reading. - delegate.Wait(); - - // And then we should get a read error. - delegate.WaitForReadError(); - - io_thread()->PostTaskAndWait( - FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); -} - -// RawChannelTest.WriteMessageAfterShutdown ------------------------------------ - -// Makes sure that calling |WriteMessage()| after |Shutdown()| behaves -// correctly. -TEST_F(RawChannelTest, WriteMessageAfterShutdown) { - WriteOnlyRawChannelDelegate delegate; - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - io_thread()->PostTaskAndWait( - FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); - - EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); -} - -// RawChannelTest.ShutdownOnReadMessage ---------------------------------------- - -class ShutdownOnReadMessageRawChannelDelegate : public RawChannel::Delegate { - public: - explicit ShutdownOnReadMessageRawChannelDelegate(RawChannel* raw_channel) - : raw_channel_(raw_channel), - done_event_(false, false), - did_shutdown_(false) {} - ~ShutdownOnReadMessageRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation (called on the I/O thread): - void OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) override { - EXPECT_FALSE(platform_handles); - EXPECT_FALSE(did_shutdown_); - EXPECT_TRUE( - CheckMessageData(message_view.bytes(), message_view.num_bytes())); - raw_channel_->Shutdown(); - did_shutdown_ = true; - done_event_.Signal(); - } - void OnError(Error /*error*/) override { - CHECK(false); // Should not get called. - } - - // Waits for shutdown. - void Wait() { - done_event_.Wait(); - EXPECT_TRUE(did_shutdown_); - } - - private: - RawChannel* const raw_channel_; - base::WaitableEvent done_event_; - bool did_shutdown_; - - DISALLOW_COPY_AND_ASSIGN(ShutdownOnReadMessageRawChannelDelegate); -}; - -TEST_F(RawChannelTest, ShutdownOnReadMessage) { - // Write a few messages into the other end. - for (size_t count = 0; count < 5; count++) - EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), 10)); - - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - ShutdownOnReadMessageRawChannelDelegate delegate(rc.get()); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Wait for the delegate, which will shut the |RawChannel| down. - delegate.Wait(); -} - -// RawChannelTest.ShutdownOnError{Read, Write} --------------------------------- - -class ShutdownOnErrorRawChannelDelegate : public RawChannel::Delegate { - public: - ShutdownOnErrorRawChannelDelegate(RawChannel* raw_channel, - Error shutdown_on_error_type) - : raw_channel_(raw_channel), - shutdown_on_error_type_(shutdown_on_error_type), - done_event_(false, false), - did_shutdown_(false) {} - ~ShutdownOnErrorRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation (called on the I/O thread): - void OnReadMessage( - const MessageInTransit::View& /*message_view*/, - embedder::ScopedPlatformHandleVectorPtr /*platform_handles*/) override { - CHECK(false); // Should not get called. - } - void OnError(Error error) override { - EXPECT_FALSE(did_shutdown_); - if (error != shutdown_on_error_type_) - return; - raw_channel_->Shutdown(); - did_shutdown_ = true; - done_event_.Signal(); - } - - // Waits for shutdown. - void Wait() { - done_event_.Wait(); - EXPECT_TRUE(did_shutdown_); - } - - private: - RawChannel* const raw_channel_; - const Error shutdown_on_error_type_; - base::WaitableEvent done_event_; - bool did_shutdown_; - - DISALLOW_COPY_AND_ASSIGN(ShutdownOnErrorRawChannelDelegate); -}; - -TEST_F(RawChannelTest, ShutdownOnErrorRead) { - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - ShutdownOnErrorRawChannelDelegate delegate( - rc.get(), RawChannel::Delegate::ERROR_READ_SHUTDOWN); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Close the handle of the other end, which should stuff fail. - handles[1].reset(); - - // Wait for the delegate, which will shut the |RawChannel| down. - delegate.Wait(); -} - -TEST_F(RawChannelTest, ShutdownOnErrorWrite) { - scoped_ptr<RawChannel> rc(RawChannel::Create(handles[0].Pass())); - ShutdownOnErrorRawChannelDelegate delegate(rc.get(), - RawChannel::Delegate::ERROR_WRITE); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&InitOnIOThread, rc.get(), base::Unretained(&delegate))); - - // Close the handle of the other end, which should stuff fail. - handles[1].reset(); - - EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); - - // Wait for the delegate, which will shut the |RawChannel| down. - delegate.Wait(); -} - -// RawChannelTest.ReadWritePlatformHandles ------------------------------------- - -class ReadPlatformHandlesCheckerRawChannelDelegate - : public RawChannel::Delegate { - public: - ReadPlatformHandlesCheckerRawChannelDelegate() : done_event_(false, false) {} - ~ReadPlatformHandlesCheckerRawChannelDelegate() override {} - - // |RawChannel::Delegate| implementation (called on the I/O thread): - void OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) override { - const char kHello[] = "hello"; - - EXPECT_EQ(sizeof(kHello), message_view.num_bytes()); - EXPECT_STREQ(kHello, static_cast<const char*>(message_view.bytes())); - - ASSERT_TRUE(platform_handles); - ASSERT_EQ(2u, platform_handles->size()); - embedder::ScopedPlatformHandle h1(platform_handles->at(0)); - EXPECT_TRUE(h1.is_valid()); - embedder::ScopedPlatformHandle h2(platform_handles->at(1)); - EXPECT_TRUE(h2.is_valid()); - platform_handles->clear(); - - { - char buffer[100] = {}; - - base::ScopedFILE fp(mojo::test::FILEFromPlatformHandle(h1.Pass(), "rb")); - EXPECT_TRUE(fp); - rewind(fp.get()); - EXPECT_EQ(1u, fread(buffer, 1, sizeof(buffer), fp.get())); - EXPECT_EQ('1', buffer[0]); - } - - { - char buffer[100] = {}; - base::ScopedFILE fp(mojo::test::FILEFromPlatformHandle(h2.Pass(), "rb")); - EXPECT_TRUE(fp); - rewind(fp.get()); - EXPECT_EQ(1u, fread(buffer, 1, sizeof(buffer), fp.get())); - EXPECT_EQ('2', buffer[0]); - } - - done_event_.Signal(); - } - void OnError(Error error) override { - // We'll get a read (shutdown) error when the connection is closed. - CHECK_EQ(error, ERROR_READ_SHUTDOWN); - } - - void Wait() { done_event_.Wait(); } - - private: - base::WaitableEvent done_event_; - - DISALLOW_COPY_AND_ASSIGN(ReadPlatformHandlesCheckerRawChannelDelegate); -}; - -#if defined(OS_POSIX) -#define MAYBE_ReadWritePlatformHandles ReadWritePlatformHandles -#else -// Not yet implemented (on Windows). -#define MAYBE_ReadWritePlatformHandles DISABLED_ReadWritePlatformHandles -#endif -TEST_F(RawChannelTest, MAYBE_ReadWritePlatformHandles) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - WriteOnlyRawChannelDelegate write_delegate; - scoped_ptr<RawChannel> rc_write(RawChannel::Create(handles[0].Pass())); - io_thread()->PostTaskAndWait(FROM_HERE, - base::Bind(&InitOnIOThread, rc_write.get(), - base::Unretained(&write_delegate))); - - ReadPlatformHandlesCheckerRawChannelDelegate read_delegate; - scoped_ptr<RawChannel> rc_read(RawChannel::Create(handles[1].Pass())); - io_thread()->PostTaskAndWait(FROM_HERE, - base::Bind(&InitOnIOThread, rc_read.get(), - base::Unretained(&read_delegate))); - - base::FilePath unused; - base::ScopedFILE fp1( - base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); - EXPECT_EQ(1u, fwrite("1", 1, 1, fp1.get())); - base::ScopedFILE fp2( - base::CreateAndOpenTemporaryFileInDir(temp_dir.path(), &unused)); - EXPECT_EQ(1u, fwrite("2", 1, 1, fp2.get())); - - { - const char kHello[] = "hello"; - embedder::ScopedPlatformHandleVectorPtr platform_handles( - new embedder::PlatformHandleVector()); - platform_handles->push_back( - mojo::test::PlatformHandleFromFILE(fp1.Pass()).release()); - platform_handles->push_back( - mojo::test::PlatformHandleFromFILE(fp2.Pass()).release()); - - scoped_ptr<MessageInTransit> message(new MessageInTransit( - MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, - sizeof(kHello), kHello)); - message->SetTransportData( - make_scoped_ptr(new TransportData(platform_handles.Pass()))); - EXPECT_TRUE(rc_write->WriteMessage(message.Pass())); - } - - read_delegate.Wait(); - - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&RawChannel::Shutdown, base::Unretained(rc_read.get()))); - io_thread()->PostTaskAndWait( - FROM_HERE, - base::Bind(&RawChannel::Shutdown, base::Unretained(rc_write.get()))); -} - -} // namespace -} // namespace system -} // namespace mojo |