| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/edk/system/channel_manager.h" | 5 #include "mojo/edk/system/channel_manager.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| 11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 12 #include "base/task_runner.h" | 12 #include "base/task_runner.h" |
| 13 #include "base/test/test_timeouts.h" | |
| 14 #include "base/threading/platform_thread.h" | |
| 15 #include "base/threading/simple_thread.h" | 13 #include "base/threading/simple_thread.h" |
| 16 #include "base/time/time.h" | |
| 17 #include "mojo/edk/embedder/platform_channel_pair.h" | 14 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 18 #include "mojo/edk/embedder/simple_platform_support.h" | 15 #include "mojo/edk/embedder/simple_platform_support.h" |
| 19 #include "mojo/edk/system/channel.h" | 16 #include "mojo/edk/system/channel.h" |
| 20 #include "mojo/edk/system/channel_endpoint.h" | 17 #include "mojo/edk/system/channel_endpoint.h" |
| 21 #include "mojo/edk/system/message_pipe_dispatcher.h" | 18 #include "mojo/edk/system/message_pipe_dispatcher.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 20 |
| 24 namespace mojo { | 21 namespace mojo { |
| 25 namespace system { | 22 namespace system { |
| 26 namespace { | 23 namespace { |
| 27 | 24 |
| 28 class ChannelManagerTest : public testing::Test { | 25 class ChannelManagerTest : public testing::Test { |
| 29 public: | 26 public: |
| 30 ChannelManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {} | 27 ChannelManagerTest() |
| 28 : message_loop_(base::MessageLoop::TYPE_IO), |
| 29 channel_manager_(&platform_support_, |
| 30 message_loop_.task_runner(), |
| 31 nullptr) {} |
| 31 ~ChannelManagerTest() override {} | 32 ~ChannelManagerTest() override {} |
| 32 | 33 |
| 33 protected: | 34 protected: |
| 34 embedder::SimplePlatformSupport* platform_support() { | 35 ChannelManager& channel_manager() { return channel_manager_; } |
| 35 return &platform_support_; | |
| 36 } | |
| 37 base::MessageLoop* message_loop() { return &message_loop_; } | |
| 38 | 36 |
| 39 private: | 37 private: |
| 40 embedder::SimplePlatformSupport platform_support_; | 38 embedder::SimplePlatformSupport platform_support_; |
| 41 base::MessageLoop message_loop_; | 39 base::MessageLoop message_loop_; |
| 40 // Note: This should be *after* the above, since they must be initialized |
| 41 // before it (and should outlive it). |
| 42 ChannelManager channel_manager_; |
| 42 | 43 |
| 43 DISALLOW_COPY_AND_ASSIGN(ChannelManagerTest); | 44 DISALLOW_COPY_AND_ASSIGN(ChannelManagerTest); |
| 44 }; | 45 }; |
| 45 | 46 |
| 46 TEST_F(ChannelManagerTest, Basic) { | 47 TEST_F(ChannelManagerTest, Basic) { |
| 47 ChannelManager cm(platform_support()); | |
| 48 | |
| 49 embedder::PlatformChannelPair channel_pair; | 48 embedder::PlatformChannelPair channel_pair; |
| 50 | 49 |
| 51 const ChannelId id = 1; | 50 const ChannelId id = 1; |
| 52 scoped_refptr<MessagePipeDispatcher> d = | 51 scoped_refptr<MessagePipeDispatcher> d = |
| 53 cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); | 52 channel_manager().CreateChannelOnIOThread( |
| 53 id, channel_pair.PassServerHandle()); |
| 54 | 54 |
| 55 scoped_refptr<Channel> ch = cm.GetChannel(id); | 55 scoped_refptr<Channel> ch = channel_manager().GetChannel(id); |
| 56 EXPECT_TRUE(ch); | 56 EXPECT_TRUE(ch); |
| 57 // |ChannelManager| should have a ref. | 57 // |ChannelManager| should have a ref. |
| 58 EXPECT_FALSE(ch->HasOneRef()); | 58 EXPECT_FALSE(ch->HasOneRef()); |
| 59 | 59 |
| 60 cm.WillShutdownChannel(id); | 60 channel_manager().WillShutdownChannel(id); |
| 61 // |ChannelManager| should still have a ref. | 61 // |ChannelManager| should still have a ref. |
| 62 EXPECT_FALSE(ch->HasOneRef()); | 62 EXPECT_FALSE(ch->HasOneRef()); |
| 63 | 63 |
| 64 cm.ShutdownChannel(id); | 64 channel_manager().ShutdownChannelOnIOThread(id); |
| 65 // On the "I/O" thread, so shutdown should happen synchronously. | |
| 66 // |ChannelManager| should have given up its ref. | 65 // |ChannelManager| should have given up its ref. |
| 67 EXPECT_TRUE(ch->HasOneRef()); | 66 EXPECT_TRUE(ch->HasOneRef()); |
| 68 | 67 |
| 69 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | 68 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); |
| 70 } | 69 } |
| 71 | 70 |
| 72 TEST_F(ChannelManagerTest, TwoChannels) { | 71 TEST_F(ChannelManagerTest, TwoChannels) { |
| 73 ChannelManager cm(platform_support()); | |
| 74 | |
| 75 embedder::PlatformChannelPair channel_pair; | 72 embedder::PlatformChannelPair channel_pair; |
| 76 | 73 |
| 77 const ChannelId id1 = 1; | 74 const ChannelId id1 = 1; |
| 78 scoped_refptr<MessagePipeDispatcher> d1 = | 75 scoped_refptr<MessagePipeDispatcher> d1 = |
| 79 cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle()); | 76 channel_manager().CreateChannelOnIOThread( |
| 77 id1, channel_pair.PassServerHandle()); |
| 80 | 78 |
| 81 const ChannelId id2 = 2; | 79 const ChannelId id2 = 2; |
| 82 scoped_refptr<MessagePipeDispatcher> d2 = | 80 scoped_refptr<MessagePipeDispatcher> d2 = |
| 83 cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle()); | 81 channel_manager().CreateChannelOnIOThread( |
| 82 id2, channel_pair.PassClientHandle()); |
| 84 | 83 |
| 85 scoped_refptr<Channel> ch1 = cm.GetChannel(id1); | 84 scoped_refptr<Channel> ch1 = channel_manager().GetChannel(id1); |
| 86 EXPECT_TRUE(ch1); | 85 EXPECT_TRUE(ch1); |
| 87 | 86 |
| 88 scoped_refptr<Channel> ch2 = cm.GetChannel(id2); | 87 scoped_refptr<Channel> ch2 = channel_manager().GetChannel(id2); |
| 89 EXPECT_TRUE(ch2); | 88 EXPECT_TRUE(ch2); |
| 90 | 89 |
| 91 // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. | 90 // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. |
| 92 cm.WillShutdownChannel(id1); | 91 channel_manager().WillShutdownChannel(id1); |
| 93 cm.WillShutdownChannel(id1); | 92 channel_manager().WillShutdownChannel(id1); |
| 94 EXPECT_FALSE(ch1->HasOneRef()); | 93 EXPECT_FALSE(ch1->HasOneRef()); |
| 95 // Not calling |WillShutdownChannel()| (on |id2|) is okay too. | 94 // Not calling |WillShutdownChannel()| (on |id2|) is okay too. |
| 96 | 95 |
| 97 cm.ShutdownChannel(id1); | 96 channel_manager().ShutdownChannelOnIOThread(id1); |
| 98 EXPECT_TRUE(ch1->HasOneRef()); | 97 EXPECT_TRUE(ch1->HasOneRef()); |
| 99 cm.ShutdownChannel(id2); | 98 channel_manager().ShutdownChannelOnIOThread(id2); |
| 100 EXPECT_TRUE(ch2->HasOneRef()); | 99 EXPECT_TRUE(ch2->HasOneRef()); |
| 101 | 100 |
| 102 EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); | 101 EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
| 103 EXPECT_EQ(MOJO_RESULT_OK, d2->Close()); | 102 EXPECT_EQ(MOJO_RESULT_OK, d2->Close()); |
| 104 } | 103 } |
| 105 | 104 |
| 106 class OtherThread : public base::SimpleThread { | 105 class OtherThread : public base::SimpleThread { |
| 107 public: | 106 public: |
| 108 // Note: There should be no other refs to the channel identified by | 107 // Note: There should be no other refs to the channel identified by |
| 109 // |channel_id| outside the channel manager. | 108 // |channel_id| outside the channel manager. |
| 110 OtherThread(scoped_refptr<base::TaskRunner> task_runner, | 109 OtherThread(scoped_refptr<base::TaskRunner> task_runner, |
| 111 ChannelManager* channel_manager, | 110 ChannelManager* channel_manager, |
| 112 ChannelId channel_id, | 111 ChannelId channel_id, |
| 113 base::Closure quit_closure) | 112 const base::Closure& quit_closure) |
| 114 : base::SimpleThread("other_thread"), | 113 : base::SimpleThread("other_thread"), |
| 115 task_runner_(task_runner), | 114 task_runner_(task_runner), |
| 116 channel_manager_(channel_manager), | 115 channel_manager_(channel_manager), |
| 117 channel_id_(channel_id), | 116 channel_id_(channel_id), |
| 118 quit_closure_(quit_closure) {} | 117 quit_closure_(quit_closure) {} |
| 119 ~OtherThread() override {} | 118 ~OtherThread() override {} |
| 120 | 119 |
| 121 private: | 120 private: |
| 122 void Run() override { | 121 void Run() override { |
| 123 // TODO(vtl): Once we have a way of creating a channel from off the I/O | 122 // TODO(vtl): Once we have a way of creating a channel from off the I/O |
| 124 // thread, do that here instead. | 123 // thread, do that here instead. |
| 125 | 124 |
| 126 // You can use any unique, nonzero value as the ID. | 125 // You can use any unique, nonzero value as the ID. |
| 127 scoped_refptr<Channel> ch = channel_manager_->GetChannel(channel_id_); | 126 scoped_refptr<Channel> ch = channel_manager_->GetChannel(channel_id_); |
| 128 // |ChannelManager| should have a ref. | 127 // |ChannelManager| should have a ref. |
| 129 EXPECT_FALSE(ch->HasOneRef()); | 128 EXPECT_FALSE(ch->HasOneRef()); |
| 130 | 129 |
| 131 channel_manager_->WillShutdownChannel(channel_id_); | 130 channel_manager_->WillShutdownChannel(channel_id_); |
| 132 // |ChannelManager| should still have a ref. | 131 // |ChannelManager| should still have a ref. |
| 133 EXPECT_FALSE(ch->HasOneRef()); | 132 EXPECT_FALSE(ch->HasOneRef()); |
| 134 | 133 |
| 135 channel_manager_->ShutdownChannel(channel_id_); | 134 { |
| 136 // This doesn't happen synchronously, so we "wait" until it does. | 135 base::MessageLoop message_loop; |
| 137 // TODO(vtl): Probably |Channel| should provide some notification of being | 136 base::RunLoop run_loop; |
| 138 // shut down. | 137 channel_manager_->ShutdownChannel(channel_id_, run_loop.QuitClosure(), |
| 139 base::TimeTicks start_time(base::TimeTicks::Now()); | 138 message_loop.task_runner()); |
| 140 for (;;) { | 139 run_loop.Run(); |
| 141 if (ch->HasOneRef()) | |
| 142 break; | |
| 143 | |
| 144 // Check, instead of assert, since if things go wrong, dying is more | |
| 145 // reliable than tearing down. | |
| 146 CHECK_LT(base::TimeTicks::Now() - start_time, | |
| 147 TestTimeouts::action_timeout()); | |
| 148 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); | |
| 149 } | 140 } |
| 150 | 141 |
| 151 CHECK(task_runner_->PostTask(FROM_HERE, quit_closure_)); | 142 CHECK(task_runner_->PostTask(FROM_HERE, quit_closure_)); |
| 152 } | 143 } |
| 153 | 144 |
| 154 scoped_refptr<base::TaskRunner> task_runner_; | 145 scoped_refptr<base::TaskRunner> task_runner_; |
| 155 ChannelManager* channel_manager_; | 146 ChannelManager* channel_manager_; |
| 156 ChannelId channel_id_; | 147 ChannelId channel_id_; |
| 157 base::Closure quit_closure_; | 148 base::Closure quit_closure_; |
| 158 | 149 |
| 159 DISALLOW_COPY_AND_ASSIGN(OtherThread); | 150 DISALLOW_COPY_AND_ASSIGN(OtherThread); |
| 160 }; | 151 }; |
| 161 | 152 |
| 162 TEST_F(ChannelManagerTest, CallsFromOtherThread) { | 153 TEST_F(ChannelManagerTest, CallsFromOtherThread) { |
| 163 ChannelManager cm(platform_support()); | |
| 164 | |
| 165 embedder::PlatformChannelPair channel_pair; | 154 embedder::PlatformChannelPair channel_pair; |
| 166 | 155 |
| 167 const ChannelId id = 1; | 156 const ChannelId id = 1; |
| 168 scoped_refptr<MessagePipeDispatcher> d = | 157 scoped_refptr<MessagePipeDispatcher> d = |
| 169 cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle()); | 158 channel_manager().CreateChannelOnIOThread( |
| 159 id, channel_pair.PassServerHandle()); |
| 170 | 160 |
| 171 base::RunLoop run_loop; | 161 base::RunLoop run_loop; |
| 172 OtherThread thread(base::MessageLoopProxy::current(), &cm, id, | 162 OtherThread thread(base::MessageLoopProxy::current(), &channel_manager(), id, |
| 173 run_loop.QuitClosure()); | 163 run_loop.QuitClosure()); |
| 174 thread.Start(); | 164 thread.Start(); |
| 175 run_loop.Run(); | 165 run_loop.Run(); |
| 176 thread.Join(); | 166 thread.Join(); |
| 177 | 167 |
| 178 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | 168 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); |
| 179 } | 169 } |
| 180 | 170 |
| 181 } // namespace | 171 } // namespace |
| 182 } // namespace system | 172 } // namespace system |
| 183 } // namespace mojo | 173 } // namespace mojo |
| OLD | NEW |