summaryrefslogtreecommitdiffstats
path: root/chromium/mojo/system/channel_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/mojo/system/channel_unittest.cc')
-rw-r--r--chromium/mojo/system/channel_unittest.cc329
1 files changed, 329 insertions, 0 deletions
diff --git a/chromium/mojo/system/channel_unittest.cc b/chromium/mojo/system/channel_unittest.cc
new file mode 100644
index 00000000000..1c40d024796
--- /dev/null
+++ b/chromium/mojo/system/channel_unittest.cc
@@ -0,0 +1,329 @@
+// 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/system/channel.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/embedder/platform_channel_pair.h"
+#include "mojo/system/local_message_pipe_endpoint.h"
+#include "mojo/system/message_in_transit.h"
+#include "mojo/system/message_pipe.h"
+#include "mojo/system/proxy_message_pipe_endpoint.h"
+#include "mojo/system/raw_channel.h"
+#include "mojo/system/test_utils.h"
+#include "mojo/system/waiter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace system {
+namespace {
+
+enum Tristate {
+ TRISTATE_UNKNOWN = -1,
+ TRISTATE_FALSE = 0,
+ TRISTATE_TRUE = 1
+};
+
+Tristate BoolToTristate(bool b) {
+ return b ? TRISTATE_TRUE : TRISTATE_FALSE;
+}
+
+class ChannelTest : public testing::Test {
+ public:
+ ChannelTest()
+ : io_thread_(test::TestIOThread::kAutoStart),
+ init_result_(TRISTATE_UNKNOWN) {}
+ virtual ~ChannelTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ io_thread_.PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::SetUpOnIOThread, base::Unretained(this)));
+ }
+
+ void CreateChannelOnIOThread() {
+ CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
+ channel_ = new Channel();
+ }
+
+ void InitChannelOnIOThread() {
+ CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
+
+ CHECK(raw_channel_);
+ CHECK(channel_);
+ CHECK_EQ(init_result_, TRISTATE_UNKNOWN);
+
+ init_result_ = BoolToTristate(channel_->Init(raw_channel_.Pass()));
+ }
+
+ void ShutdownChannelOnIOThread() {
+ CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
+
+ CHECK(channel_);
+ channel_->Shutdown();
+ }
+
+ test::TestIOThread* io_thread() { return &io_thread_; }
+ RawChannel* raw_channel() { return raw_channel_.get(); }
+ scoped_ptr<RawChannel>* mutable_raw_channel() { return &raw_channel_; }
+ Channel* channel() { return channel_.get(); }
+ scoped_refptr<Channel>* mutable_channel() { return &channel_; }
+ Tristate init_result() const { return init_result_; }
+
+ private:
+ void SetUpOnIOThread() {
+ CHECK_EQ(base::MessageLoop::current(), io_thread()->message_loop());
+
+ embedder::PlatformChannelPair channel_pair;
+ raw_channel_ = RawChannel::Create(channel_pair.PassServerHandle()).Pass();
+ other_platform_handle_ = channel_pair.PassClientHandle();
+ }
+
+ test::TestIOThread io_thread_;
+ scoped_ptr<RawChannel> raw_channel_;
+ embedder::ScopedPlatformHandle other_platform_handle_;
+ scoped_refptr<Channel> channel_;
+
+ Tristate init_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelTest);
+};
+
+// ChannelTest.InitShutdown ----------------------------------------------------
+
+TEST_F(ChannelTest, InitShutdown) {
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::CreateChannelOnIOThread,
+ base::Unretained(this)));
+ ASSERT_TRUE(channel());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::InitChannelOnIOThread,
+ base::Unretained(this)));
+ EXPECT_EQ(TRISTATE_TRUE, init_result());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
+ base::Unretained(this)));
+
+ // Okay to destroy |Channel| on not-the-I/O-thread.
+ EXPECT_TRUE(channel()->HasOneRef());
+ *mutable_channel() = NULL;
+}
+
+// ChannelTest.InitFails -------------------------------------------------------
+
+class MockRawChannelOnInitFails : public RawChannel {
+ public:
+ MockRawChannelOnInitFails() : on_init_called_(false) {}
+ virtual ~MockRawChannelOnInitFails() {}
+
+ // |RawChannel| public methods:
+ virtual size_t GetSerializedPlatformHandleSize() const OVERRIDE {
+ return 0;
+ }
+
+ private:
+ // |RawChannel| protected methods:
+ virtual IOResult Read(size_t*) OVERRIDE {
+ CHECK(false);
+ return IO_FAILED;
+ }
+ virtual IOResult ScheduleRead() OVERRIDE {
+ CHECK(false);
+ return IO_FAILED;
+ }
+ virtual embedder::ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
+ size_t, const void*) OVERRIDE {
+ CHECK(false);
+ return embedder::ScopedPlatformHandleVectorPtr();
+ }
+ virtual IOResult WriteNoLock(size_t*, size_t*) OVERRIDE {
+ CHECK(false);
+ return IO_FAILED;
+ }
+ virtual IOResult ScheduleWriteNoLock() OVERRIDE {
+ CHECK(false);
+ return IO_FAILED;
+ }
+ virtual bool OnInit() OVERRIDE {
+ EXPECT_FALSE(on_init_called_);
+ on_init_called_ = true;
+ return false;
+ }
+ virtual void OnShutdownNoLock(scoped_ptr<ReadBuffer>,
+ scoped_ptr<WriteBuffer>) OVERRIDE {
+ CHECK(false);
+ }
+
+ bool on_init_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockRawChannelOnInitFails);
+};
+
+TEST_F(ChannelTest, InitFails) {
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::CreateChannelOnIOThread,
+ base::Unretained(this)));
+ ASSERT_TRUE(channel());
+
+ ASSERT_TRUE(raw_channel());
+ mutable_raw_channel()->reset(new MockRawChannelOnInitFails());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::InitChannelOnIOThread,
+ base::Unretained(this)));
+ EXPECT_EQ(TRISTATE_FALSE, init_result());
+
+ // Should destroy |Channel| with no |Shutdown()| (on not-the-I/O-thread).
+ EXPECT_TRUE(channel()->HasOneRef());
+ *mutable_channel() = NULL;
+}
+
+// ChannelTest.CloseBeforeRun --------------------------------------------------
+
+TEST_F(ChannelTest, CloseBeforeRun) {
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::CreateChannelOnIOThread,
+ base::Unretained(this)));
+ ASSERT_TRUE(channel());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::InitChannelOnIOThread,
+ base::Unretained(this)));
+ EXPECT_EQ(TRISTATE_TRUE, init_result());
+
+ scoped_refptr<MessagePipe> mp(new MessagePipe(
+ scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
+ scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
+
+ MessageInTransit::EndpointId local_id =
+ channel()->AttachMessagePipeEndpoint(mp, 1);
+ EXPECT_EQ(Channel::kBootstrapEndpointId, local_id);
+
+ mp->Close(0);
+
+ // TODO(vtl): Currently, the |Close()| above won't detach (since it thinks
+ // we're still expecting a "run" message from the other side), so the
+ // |RunMessagePipeEndpoint()| below will return true. We need to refactor
+ // |AttachMessagePipeEndpoint()| to indicate whether |Run...()| will
+ // necessarily be called or not. (Then, in the case that it may not be called,
+ // this will return false.)
+ EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id,
+ Channel::kBootstrapEndpointId));
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
+ base::Unretained(this)));
+
+ EXPECT_TRUE(channel()->HasOneRef());
+}
+
+// ChannelTest.ShutdownAfterAttachAndRun ---------------------------------------
+
+TEST_F(ChannelTest, ShutdownAfterAttach) {
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::CreateChannelOnIOThread,
+ base::Unretained(this)));
+ ASSERT_TRUE(channel());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::InitChannelOnIOThread,
+ base::Unretained(this)));
+ EXPECT_EQ(TRISTATE_TRUE, init_result());
+
+ scoped_refptr<MessagePipe> mp(new MessagePipe(
+ scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
+ scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
+
+ MessageInTransit::EndpointId local_id =
+ channel()->AttachMessagePipeEndpoint(mp, 1);
+ EXPECT_EQ(Channel::kBootstrapEndpointId, local_id);
+
+ // TODO(vtl): Currently, we always "expect" a |RunMessagePipeEndpoint()| after
+ // an |AttachMessagePipeEndpoint()| (which is actually incorrect). We need to
+ // refactor |AttachMessagePipeEndpoint()| to indicate whether |Run...()| will
+ // necessarily be called or not. (Then, in the case that it may not be called,
+ // we should test a |Shutdown()| without the |Run...()|.)
+ EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id,
+ Channel::kBootstrapEndpointId));
+
+ Waiter waiter;
+ waiter.Init();
+ EXPECT_EQ(MOJO_RESULT_OK,
+ mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123));
+
+ // Don't wait for the shutdown to run ...
+ io_thread()->PostTask(FROM_HERE,
+ base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
+ base::Unretained(this)));
+
+ // ... since this |Wait()| should fail once the channel is shut down.
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ waiter.Wait(MOJO_DEADLINE_INDEFINITE, NULL));
+ mp->RemoveWaiter(0, &waiter);
+
+ mp->Close(0);
+
+ EXPECT_TRUE(channel()->HasOneRef());
+}
+
+// ChannelTest.WaitAfterAttachRunAndShutdown -----------------------------------
+
+TEST_F(ChannelTest, WaitAfterAttachRunAndShutdown) {
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::CreateChannelOnIOThread,
+ base::Unretained(this)));
+ ASSERT_TRUE(channel());
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::InitChannelOnIOThread,
+ base::Unretained(this)));
+ EXPECT_EQ(TRISTATE_TRUE, init_result());
+
+ scoped_refptr<MessagePipe> mp(new MessagePipe(
+ scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
+ scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
+
+ MessageInTransit::EndpointId local_id =
+ channel()->AttachMessagePipeEndpoint(mp, 1);
+ EXPECT_EQ(Channel::kBootstrapEndpointId, local_id);
+
+ EXPECT_TRUE(channel()->RunMessagePipeEndpoint(local_id,
+ Channel::kBootstrapEndpointId));
+
+ io_thread()->PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
+ base::Unretained(this)));
+
+ Waiter waiter;
+ waiter.Init();
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123));
+
+ mp->Close(0);
+
+ EXPECT_TRUE(channel()->HasOneRef());
+}
+
+// TODO(vtl): More. ------------------------------------------------------------
+
+} // namespace
+} // namespace system
+} // namespace mojo