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 |