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/services/view_manager/view_manager_connection.h" | |
6 | |
7 #include <string> | 5 #include <string> |
8 #include <vector> | 6 #include <vector> |
9 | 7 |
10 #include "base/bind.h" | 8 #include "base/bind.h" |
11 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
12 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
13 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
14 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
15 #include "mojo/public/cpp/bindings/allocation_scope.h" | 13 #include "mojo/public/cpp/bindings/allocation_scope.h" |
16 #include "mojo/public/cpp/environment/environment.h" | 14 #include "mojo/public/cpp/environment/environment.h" |
17 #include "mojo/services/view_manager/root_node_manager.h" | 15 #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" |
| 16 #include "mojo/shell/shell_test_helper.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
19 | 18 |
20 namespace mojo { | 19 namespace mojo { |
21 namespace services { | 20 namespace services { |
22 namespace view_manager { | 21 namespace view_manager { |
23 | 22 |
24 namespace { | 23 namespace { |
25 | 24 |
26 base::RunLoop* current_run_loop = NULL; | 25 base::RunLoop* current_run_loop = NULL; |
27 | 26 |
| 27 // TODO(sky): remove and include a common header. |
| 28 typedef uint32_t ChangeId; |
| 29 |
| 30 uint16_t FirstIdFromTransportId(uint32_t id) { |
| 31 return static_cast<uint16_t>((id >> 16) & 0xFFFF); |
| 32 } |
| 33 |
| 34 uint16_t SecondIdFromTransportId(uint32_t id) { |
| 35 return static_cast<uint16_t>(id & 0xFFFF); |
| 36 } |
| 37 |
28 // Sets |current_run_loop| and runs it. It is expected that someone else quits | 38 // Sets |current_run_loop| and runs it. It is expected that someone else quits |
29 // the loop. | 39 // the loop. |
30 void DoRunLoop() { | 40 void DoRunLoop() { |
31 base::RunLoop run_loop; | 41 base::RunLoop run_loop; |
32 current_run_loop = &run_loop; | 42 current_run_loop = &run_loop; |
33 current_run_loop->Run(); | 43 current_run_loop->Run(); |
34 current_run_loop = NULL; | 44 current_run_loop = NULL; |
35 } | 45 } |
36 | 46 |
37 // Converts |id| into a string. | 47 // Converts |id| into a string. |
38 std::string NodeIdToString(uint32_t id) { | 48 std::string NodeIdToString(uint32_t id) { |
39 return (id == 0) ? "null" : | 49 return (id == 0) ? "null" : |
40 base::StringPrintf("%d,%d", FirstIdFromTransportId(id), | 50 base::StringPrintf("%d,%d", FirstIdFromTransportId(id), |
41 SecondIdFromTransportId(id)); | 51 SecondIdFromTransportId(id)); |
42 } | 52 } |
43 | 53 |
44 // Boolean callback. Sets |result_cache| to the value of |result| and quits | 54 // Boolean callback. Sets |result_cache| to the value of |result| and quits |
45 // the run loop. | 55 // the run loop. |
46 void BooleanCallback(bool* result_cache, bool result) { | 56 void BooleanCallback(bool* result_cache, bool result) { |
47 *result_cache = result; | 57 *result_cache = result; |
48 current_run_loop->Quit(); | 58 current_run_loop->Quit(); |
49 } | 59 } |
50 | 60 |
51 // Creates an id used for transport from the specified parameters. | 61 // Creates an id used for transport from the specified parameters. |
52 uint32_t CreateNodeId(uint16_t connection_id, uint16_t node_id) { | 62 uint32_t CreateNodeId(uint16_t connection_id, uint16_t node_id) { |
53 return NodeIdToTransportId(NodeId(connection_id, node_id)); | 63 return (connection_id << 16) | node_id; |
54 } | 64 } |
55 | 65 |
56 // Creates an id used for transport from the specified parameters. | 66 // Creates an id used for transport from the specified parameters. |
57 uint32_t CreateViewId(uint16_t connection_id, uint16_t view_id) { | 67 uint32_t CreateViewId(uint16_t connection_id, uint16_t view_id) { |
58 return ViewIdToTransportId(ViewId(connection_id, view_id)); | 68 return (connection_id << 16) | view_id; |
59 } | 69 } |
60 | 70 |
61 // Creates a node with the specified id. Returns true on success. Blocks until | 71 // Creates a node with the specified id. Returns true on success. Blocks until |
62 // we get back result from server. | 72 // we get back result from server. |
63 bool CreateNode(ViewManager* view_manager, uint16_t id) { | 73 bool CreateNode(ViewManager* view_manager, uint16_t id) { |
64 bool result = false; | 74 bool result = false; |
65 view_manager->CreateNode(id, base::Bind(&BooleanCallback, &result)); | 75 view_manager->CreateNode(id, base::Bind(&BooleanCallback, &result)); |
66 DoRunLoop(); | 76 DoRunLoop(); |
67 return result; | 77 return result; |
68 } | 78 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 } | 136 } |
127 | 137 |
128 } // namespace | 138 } // namespace |
129 | 139 |
130 typedef std::vector<std::string> Changes; | 140 typedef std::vector<std::string> Changes; |
131 | 141 |
132 class ViewManagerClientImpl : public ViewManagerClient { | 142 class ViewManagerClientImpl : public ViewManagerClient { |
133 public: | 143 public: |
134 ViewManagerClientImpl() : id_(0), quit_count_(0) {} | 144 ViewManagerClientImpl() : id_(0), quit_count_(0) {} |
135 | 145 |
136 void set_quit_count(int count) { quit_count_ = count; } | |
137 | |
138 uint16_t id() const { return id_; } | 146 uint16_t id() const { return id_; } |
139 | 147 |
140 Changes GetAndClearChanges() { | 148 Changes GetAndClearChanges() { |
141 Changes changes; | 149 Changes changes; |
142 changes.swap(changes_); | 150 changes.swap(changes_); |
143 return changes; | 151 return changes; |
144 } | 152 } |
145 | 153 |
| 154 void WaitForId() { |
| 155 if (id_ == 0) |
| 156 DoRunLoop(); |
| 157 } |
| 158 |
| 159 void DoRunLoopUntilChangesCount(size_t count) { |
| 160 if (changes_.size() >= count) |
| 161 return; |
| 162 quit_count_ = count - changes_.size(); |
| 163 DoRunLoop(); |
| 164 } |
| 165 |
146 private: | 166 private: |
147 // ViewManagerClient overrides: | 167 // ViewManagerClient overrides: |
148 virtual void OnConnectionEstablished(uint16_t connection_id) OVERRIDE { | 168 virtual void OnConnectionEstablished(uint16_t connection_id) OVERRIDE { |
149 id_ = connection_id; | 169 id_ = connection_id; |
150 current_run_loop->Quit(); | 170 if (current_run_loop) |
| 171 current_run_loop->Quit(); |
151 } | 172 } |
152 virtual void OnNodeHierarchyChanged(uint32_t node, | 173 virtual void OnNodeHierarchyChanged(uint32_t node, |
153 uint32_t new_parent, | 174 uint32_t new_parent, |
154 uint32_t old_parent, | 175 uint32_t old_parent, |
155 ChangeId change_id) OVERRIDE { | 176 ChangeId change_id) OVERRIDE { |
156 changes_.push_back( | 177 changes_.push_back( |
157 base::StringPrintf( | 178 base::StringPrintf( |
158 "change_id=%d node=%s new_parent=%s old_parent=%s", | 179 "change_id=%d node=%s new_parent=%s old_parent=%s", |
159 static_cast<int>(change_id), NodeIdToString(node).c_str(), | 180 static_cast<int>(change_id), NodeIdToString(node).c_str(), |
160 NodeIdToString(new_parent).c_str(), | 181 NodeIdToString(new_parent).c_str(), |
(...skipping 14 matching lines...) Expand all Loading... |
175 } | 196 } |
176 | 197 |
177 void QuitIfNecessary() { | 198 void QuitIfNecessary() { |
178 if (quit_count_ > 0 && --quit_count_ == 0) | 199 if (quit_count_ > 0 && --quit_count_ == 0) |
179 current_run_loop->Quit(); | 200 current_run_loop->Quit(); |
180 } | 201 } |
181 | 202 |
182 uint16_t id_; | 203 uint16_t id_; |
183 | 204 |
184 // Used to determine when/if to quit the run loop. | 205 // Used to determine when/if to quit the run loop. |
185 int quit_count_; | 206 size_t quit_count_; |
186 | 207 |
187 Changes changes_; | 208 Changes changes_; |
188 | 209 |
189 DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); | 210 DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); |
190 }; | 211 }; |
191 | 212 |
192 class ViewManagerConnectionTest : public testing::Test { | 213 class ViewManagerConnectionTest : public testing::Test { |
193 public: | 214 public: |
194 ViewManagerConnectionTest() : service_factory_(&root_node_manager_) {} | 215 ViewManagerConnectionTest() {} |
195 | 216 |
196 virtual void SetUp() OVERRIDE { | 217 virtual void SetUp() OVERRIDE { |
197 InterfacePipe<ViewManagerClient, ViewManager> pipe; | 218 AllocationScope allocation_scope; |
198 view_manager_.reset(pipe.handle_to_peer.Pass(), &client_); | 219 |
199 connection_.Initialize( | 220 test_helper_.Init(); |
200 &service_factory_, | 221 |
201 ScopedMessagePipeHandle::From(pipe.handle_to_self.Pass())); | 222 InterfacePipe<ViewManager, AnyInterface> pipe; |
202 // Wait for the id. | 223 test_helper_.shell()->Connect("mojo:mojo_view_manager", |
203 DoRunLoop(); | 224 pipe.handle_to_peer.Pass()); |
| 225 view_manager_.reset(pipe.handle_to_self.Pass(), &client_); |
| 226 |
| 227 client_.WaitForId(); |
204 } | 228 } |
205 | 229 |
206 protected: | 230 protected: |
207 // Creates a second connection to the viewmanager. | 231 // Creates a second connection to the viewmanager. |
208 void EstablishSecondConnection() { | 232 void EstablishSecondConnection() { |
209 connection2_.reset(new ViewManagerConnection); | 233 AllocationScope allocation_scope; |
210 InterfacePipe<ViewManagerClient, ViewManager> pipe; | 234 InterfacePipe<ViewManager, AnyInterface> pipe; |
211 view_manager2_.reset(pipe.handle_to_peer.Pass(), &client2_); | 235 test_helper_.shell()->Connect("mojo:mojo_view_manager", |
212 connection2_->Initialize( | 236 pipe.handle_to_peer.Pass()); |
213 &service_factory_, | 237 view_manager2_.reset(pipe.handle_to_self.Pass(), &client2_); |
214 ScopedMessagePipeHandle::From(pipe.handle_to_self.Pass())); | 238 |
215 // Wait for the id. | 239 client2_.WaitForId(); |
216 DoRunLoop(); | |
217 } | 240 } |
218 | 241 |
219 void DestroySecondConnection() { | 242 void DestroySecondConnection() { |
220 connection2_.reset(); | |
221 view_manager2_.reset(); | 243 view_manager2_.reset(); |
222 } | 244 } |
223 | 245 |
224 Environment env_; | |
225 base::MessageLoop loop_; | 246 base::MessageLoop loop_; |
226 RootNodeManager root_node_manager_; | 247 shell::ShellTestHelper test_helper_; |
227 ServiceConnector<ViewManagerConnection, RootNodeManager> service_factory_; | 248 |
228 ViewManagerConnection connection_; | |
229 ViewManagerClientImpl client_; | 249 ViewManagerClientImpl client_; |
230 RemotePtr<ViewManager> view_manager_; | 250 RemotePtr<ViewManager> view_manager_; |
231 | 251 |
232 ViewManagerClientImpl client2_; | 252 ViewManagerClientImpl client2_; |
233 RemotePtr<ViewManager> view_manager2_; | 253 RemotePtr<ViewManager> view_manager2_; |
234 scoped_ptr<ViewManagerConnection> connection2_; | |
235 | 254 |
236 DISALLOW_COPY_AND_ASSIGN(ViewManagerConnectionTest); | 255 DISALLOW_COPY_AND_ASSIGN(ViewManagerConnectionTest); |
237 }; | 256 }; |
238 | 257 |
239 // Verifies client gets a valid id. | 258 // Verifies client gets a valid id. |
240 TEST_F(ViewManagerConnectionTest, ValidId) { | 259 TEST_F(ViewManagerConnectionTest, ValidId) { |
241 // All these tests assume 1 for the client id. The only real assertion here is | 260 // All these tests assume 1 for the client id. The only real assertion here is |
242 // the client id is not zero, but adding this as rest of code here assumes 1. | 261 // the client id is not zero, but adding this as rest of code here assumes 1. |
243 EXPECT_EQ(1, client_.id()); | 262 EXPECT_EQ(1, client_.id()); |
244 } | 263 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 CreateNodeId(client_.id(), 2), | 329 CreateNodeId(client_.id(), 2), |
311 11)); | 330 11)); |
312 Changes changes(client_.GetAndClearChanges()); | 331 Changes changes(client_.GetAndClearChanges()); |
313 ASSERT_EQ(1u, changes.size()); | 332 ASSERT_EQ(1u, changes.size()); |
314 EXPECT_EQ("change_id=11 node=1,2 new_parent=1,1 old_parent=null", | 333 EXPECT_EQ("change_id=11 node=1,2 new_parent=1,1 old_parent=null", |
315 changes[0]); | 334 changes[0]); |
316 } | 335 } |
317 | 336 |
318 // Second client should also have received the change. | 337 // Second client should also have received the change. |
319 { | 338 { |
| 339 client2_.DoRunLoopUntilChangesCount(1); |
320 Changes changes(client2_.GetAndClearChanges()); | 340 Changes changes(client2_.GetAndClearChanges()); |
321 if (changes.empty()) { | |
322 client2_.set_quit_count(1); | |
323 DoRunLoop(); | |
324 changes = client2_.GetAndClearChanges(); | |
325 } | |
326 ASSERT_EQ(1u, changes.size()); | 341 ASSERT_EQ(1u, changes.size()); |
327 EXPECT_EQ("change_id=0 node=1,2 new_parent=1,1 old_parent=null", | 342 EXPECT_EQ("change_id=0 node=1,2 new_parent=1,1 old_parent=null", |
328 changes[0]); | 343 changes[0]); |
329 } | 344 } |
330 } | 345 } |
331 | 346 |
332 // Verifies adding to root sends right notifications. | 347 // Verifies adding to root sends right notifications. |
333 TEST_F(ViewManagerConnectionTest, AddToRoot) { | 348 TEST_F(ViewManagerConnectionTest, AddToRoot) { |
334 ASSERT_TRUE(CreateNode(view_manager_.get(), 21)); | 349 ASSERT_TRUE(CreateNode(view_manager_.get(), 21)); |
335 ASSERT_TRUE(CreateNode(view_manager_.get(), 3)); | 350 ASSERT_TRUE(CreateNode(view_manager_.get(), 3)); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 | 508 |
494 // Create a view in the second connection. | 509 // Create a view in the second connection. |
495 ASSERT_TRUE(CreateView(view_manager2_.get(), 51)); | 510 ASSERT_TRUE(CreateView(view_manager2_.get(), 51)); |
496 | 511 |
497 // Attach view to node 1 in the first connection. | 512 // Attach view to node 1 in the first connection. |
498 { | 513 { |
499 ASSERT_TRUE(SetView(view_manager2_.get(), | 514 ASSERT_TRUE(SetView(view_manager2_.get(), |
500 CreateNodeId(client_.id(), 1), | 515 CreateNodeId(client_.id(), 1), |
501 CreateViewId(client2_.id(), 51), | 516 CreateViewId(client2_.id(), 51), |
502 22)); | 517 22)); |
| 518 client_.DoRunLoopUntilChangesCount(1); |
503 Changes changes(client_.GetAndClearChanges()); | 519 Changes changes(client_.GetAndClearChanges()); |
504 ASSERT_EQ(1u, changes.size()); | 520 ASSERT_EQ(1u, changes.size()); |
505 EXPECT_EQ("change_id=0 node=1,1 new_view=2,51 old_view=null", changes[0]); | 521 EXPECT_EQ("change_id=0 node=1,1 new_view=2,51 old_view=null", changes[0]); |
506 | 522 |
| 523 client2_.DoRunLoopUntilChangesCount(1); |
507 changes = client2_.GetAndClearChanges(); | 524 changes = client2_.GetAndClearChanges(); |
508 ASSERT_EQ(1u, changes.size()); | 525 ASSERT_EQ(1u, changes.size()); |
509 EXPECT_EQ("change_id=22 node=1,1 new_view=2,51 old_view=null", changes[0]); | 526 EXPECT_EQ("change_id=22 node=1,1 new_view=2,51 old_view=null", changes[0]); |
510 } | 527 } |
511 | 528 |
512 // Shutdown the second connection and verify view is removed. | 529 // Shutdown the second connection and verify view is removed. |
513 { | 530 { |
514 DestroySecondConnection(); | 531 DestroySecondConnection(); |
515 client_.set_quit_count(1); | 532 client_.DoRunLoopUntilChangesCount(1); |
516 DoRunLoop(); | |
517 | 533 |
518 Changes changes(client_.GetAndClearChanges()); | 534 Changes changes(client_.GetAndClearChanges()); |
519 ASSERT_EQ(1u, changes.size()); | 535 ASSERT_EQ(1u, changes.size()); |
520 EXPECT_EQ("change_id=0 node=1,1 new_view=null old_view=2,51", changes[0]); | 536 EXPECT_EQ("change_id=0 node=1,1 new_view=null old_view=2,51", changes[0]); |
521 } | 537 } |
522 } | 538 } |
523 | 539 |
524 } // namespace view_manager | 540 } // namespace view_manager |
525 } // namespace services | 541 } // namespace services |
526 } // namespace mojo | 542 } // namespace mojo |
OLD | NEW |