Ignore title parameter for navigator.registerProtocolHandler
[chromium-blink-merge.git] / mojo / services / view_manager / view_manager_connection_unittest.cc
blob6c71f39de2c3608410169bcc174f6610b3b90139
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
3 // found in the LICENSE file.
5 #include <string>
6 #include <vector>
8 #include "base/bind.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "mojo/public/cpp/bindings/allocation_scope.h"
14 #include "mojo/public/cpp/environment/environment.h"
15 #include "mojo/public/cpp/shell/service.h"
16 #include "mojo/services/public/cpp/view_manager/util.h"
17 #include "mojo/services/public/cpp/view_manager/view_manager_types.h"
18 #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h"
19 #include "mojo/shell/shell_test_helper.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace mojo {
23 namespace services {
24 namespace view_manager {
26 namespace {
28 base::RunLoop* current_run_loop = NULL;
30 // Sets |current_run_loop| and runs it. It is expected that someone else quits
31 // the loop.
32 void DoRunLoop() {
33 base::RunLoop run_loop;
34 current_run_loop = &run_loop;
35 current_run_loop->Run();
36 current_run_loop = NULL;
39 // Converts |id| into a string.
40 std::string NodeIdToString(TransportNodeId id) {
41 return (id == 0) ? "null" :
42 base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
45 // Boolean callback. Sets |result_cache| to the value of |result| and quits
46 // the run loop.
47 void BooleanCallback(bool* result_cache, bool result) {
48 *result_cache = result;
49 current_run_loop->Quit();
52 struct TestNode {
53 std::string ToString() const {
54 return base::StringPrintf("node=%s parent=%s view=%s",
55 NodeIdToString(node_id).c_str(),
56 NodeIdToString(parent_id).c_str(),
57 NodeIdToString(view_id).c_str());
60 TransportNodeId parent_id;
61 TransportNodeId node_id;
62 TransportNodeId view_id;
65 // Callback that results in a vector of INodes. The INodes are converted to
66 // TestNodes.
67 void INodesCallback(std::vector<TestNode>* test_nodes,
68 const mojo::Array<INode>& data) {
69 for (size_t i = 0; i < data.size(); ++i) {
70 TestNode node;
71 node.parent_id = data[i].parent_id();
72 node.node_id = data[i].node_id();
73 node.view_id = data[i].view_id();
74 test_nodes->push_back(node);
76 current_run_loop->Quit();
79 // Creates an id used for transport from the specified parameters.
80 TransportNodeId CreateNodeId(TransportConnectionId connection_id,
81 TransportConnectionSpecificNodeId node_id) {
82 return (connection_id << 16) | node_id;
85 // Creates an id used for transport from the specified parameters.
86 TransportViewId CreateViewId(TransportConnectionId connection_id,
87 TransportConnectionSpecificViewId view_id) {
88 return (connection_id << 16) | view_id;
91 // Creates a node with the specified id. Returns true on success. Blocks until
92 // we get back result from server.
93 bool CreateNode(IViewManager* view_manager,
94 TransportConnectionSpecificNodeId id) {
95 bool result = false;
96 view_manager->CreateNode(id, base::Bind(&BooleanCallback, &result));
97 DoRunLoop();
98 return result;
101 // TODO(sky): make a macro for these functions, they are all the same.
103 // Deletes a node, blocking until done.
104 bool DeleteNode(IViewManager* view_manager,
105 TransportNodeId node_id,
106 TransportChangeId change_id) {
107 bool result = false;
108 view_manager->DeleteNode(node_id, change_id,
109 base::Bind(&BooleanCallback, &result));
110 DoRunLoop();
111 return result;
114 // Adds a node, blocking until done.
115 bool AddNode(IViewManager* view_manager,
116 TransportNodeId parent,
117 TransportNodeId child,
118 TransportChangeId change_id) {
119 bool result = false;
120 view_manager->AddNode(parent, child, change_id,
121 base::Bind(&BooleanCallback, &result));
122 DoRunLoop();
123 return result;
126 // Removes a node, blocking until done.
127 bool RemoveNodeFromParent(IViewManager* view_manager,
128 TransportNodeId node_id,
129 TransportChangeId change_id) {
130 bool result = false;
131 view_manager->RemoveNodeFromParent(node_id, change_id,
132 base::Bind(&BooleanCallback, &result));
133 DoRunLoop();
134 return result;
137 void GetNodeTree(IViewManager* view_manager,
138 TransportNodeId node_id,
139 std::vector<TestNode>* nodes) {
140 view_manager->GetNodeTree(node_id, base::Bind(&INodesCallback, nodes));
141 DoRunLoop();
144 // Creates a view with the specified id. Returns true on success. Blocks until
145 // we get back result from server.
146 bool CreateView(IViewManager* view_manager,
147 TransportConnectionSpecificViewId id) {
148 bool result = false;
149 view_manager->CreateView(id, base::Bind(&BooleanCallback, &result));
150 DoRunLoop();
151 return result;
154 // Sets a view on the specified node. Returns true on success. Blocks until we
155 // get back result from server.
156 bool SetView(IViewManager* view_manager,
157 TransportNodeId node_id,
158 TransportViewId view_id,
159 TransportChangeId change_id) {
160 bool result = false;
161 view_manager->SetView(node_id, view_id, change_id,
162 base::Bind(&BooleanCallback, &result));
163 DoRunLoop();
164 return result;
167 } // namespace
169 typedef std::vector<std::string> Changes;
171 class ViewManagerClientImpl : public IViewManagerClient {
172 public:
173 ViewManagerClientImpl() : id_(0), quit_count_(0) {}
175 TransportConnectionId id() const { return id_; }
177 Changes GetAndClearChanges() {
178 Changes changes;
179 changes.swap(changes_);
180 return changes;
183 void WaitForId() {
184 if (id_ == 0)
185 DoRunLoop();
188 void DoRunLoopUntilChangesCount(size_t count) {
189 if (changes_.size() >= count)
190 return;
191 quit_count_ = count - changes_.size();
192 DoRunLoop();
195 private:
196 // IViewManagerClient overrides:
197 virtual void OnConnectionEstablished(
198 TransportConnectionId connection_id) OVERRIDE {
199 id_ = connection_id;
200 if (current_run_loop)
201 current_run_loop->Quit();
203 virtual void OnNodeHierarchyChanged(TransportNodeId node,
204 TransportNodeId new_parent,
205 TransportNodeId old_parent,
206 TransportChangeId change_id) OVERRIDE {
207 changes_.push_back(
208 base::StringPrintf(
209 "change_id=%d node=%s new_parent=%s old_parent=%s",
210 static_cast<int>(change_id), NodeIdToString(node).c_str(),
211 NodeIdToString(new_parent).c_str(),
212 NodeIdToString(old_parent).c_str()));
213 QuitIfNecessary();
215 virtual void OnNodeViewReplaced(TransportNodeId node,
216 TransportViewId new_view_id,
217 TransportViewId old_view_id,
218 TransportChangeId change_id) OVERRIDE {
219 changes_.push_back(
220 base::StringPrintf(
221 "change_id=%d node=%s new_view=%s old_view=%s",
222 static_cast<int>(change_id), NodeIdToString(node).c_str(),
223 NodeIdToString(new_view_id).c_str(),
224 NodeIdToString(old_view_id).c_str()));
225 QuitIfNecessary();
227 virtual void OnNodeDeleted(TransportNodeId node,
228 TransportChangeId change_id) OVERRIDE {
229 changes_.push_back(
230 base::StringPrintf(
231 "change_id=%d node=%s deleted",
232 static_cast<int>(change_id), NodeIdToString(node).c_str()));
233 QuitIfNecessary();
236 void QuitIfNecessary() {
237 if (quit_count_ > 0 && --quit_count_ == 0)
238 current_run_loop->Quit();
241 TransportConnectionId id_;
243 // Used to determine when/if to quit the run loop.
244 size_t quit_count_;
246 Changes changes_;
248 DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl);
251 class ViewManagerConnectionTest : public testing::Test {
252 public:
253 ViewManagerConnectionTest() {}
255 virtual void SetUp() OVERRIDE {
256 test_helper_.Init();
258 ConnectTo(test_helper_.shell(), "mojo:mojo_view_manager", &view_manager_);
259 view_manager_->SetClient(&client_);
261 client_.WaitForId();
264 protected:
265 // Creates a second connection to the viewmanager.
266 void EstablishSecondConnection() {
267 ConnectTo(test_helper_.shell(), "mojo:mojo_view_manager", &view_manager2_);
268 view_manager2_->SetClient(&client2_);
270 client2_.WaitForId();
273 void DestroySecondConnection() {
274 view_manager2_.reset();
277 base::MessageLoop loop_;
278 shell::ShellTestHelper test_helper_;
280 ViewManagerClientImpl client_;
281 IViewManagerPtr view_manager_;
283 ViewManagerClientImpl client2_;
284 IViewManagerPtr view_manager2_;
286 DISALLOW_COPY_AND_ASSIGN(ViewManagerConnectionTest);
289 // Verifies client gets a valid id.
290 TEST_F(ViewManagerConnectionTest, ValidId) {
291 // All these tests assume 1 for the client id. The only real assertion here is
292 // the client id is not zero, but adding this as rest of code here assumes 1.
293 EXPECT_EQ(1, client_.id());
296 // Verifies two clients/connections get different ids.
297 TEST_F(ViewManagerConnectionTest, TwoClientsGetDifferentConnectionIds) {
298 EstablishSecondConnection();
299 EXPECT_NE(0, client2_.id());
300 EXPECT_NE(client_.id(), client2_.id());
303 // Verifies client gets a valid id.
304 TEST_F(ViewManagerConnectionTest, CreateNode) {
305 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
307 // Can't create a node with the same id.
308 ASSERT_FALSE(CreateNode(view_manager_.get(), 1));
311 // Verifies hierarchy changes.
312 TEST_F(ViewManagerConnectionTest, AddRemoveNotify) {
313 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
314 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
316 EXPECT_TRUE(client_.GetAndClearChanges().empty());
318 // Make 2 a child of 1.
320 AllocationScope scope;
321 ASSERT_TRUE(AddNode(view_manager_.get(),
322 CreateNodeId(client_.id(), 1),
323 CreateNodeId(client_.id(), 2),
324 11));
325 Changes changes(client_.GetAndClearChanges());
326 ASSERT_EQ(1u, changes.size());
327 EXPECT_EQ("change_id=11 node=1,2 new_parent=1,1 old_parent=null",
328 changes[0]);
331 // Remove 2 from its parent.
333 AllocationScope scope;
334 ASSERT_TRUE(RemoveNodeFromParent(view_manager_.get(),
335 CreateNodeId(client_.id(), 2),
336 101));
337 Changes changes(client_.GetAndClearChanges());
338 ASSERT_EQ(1u, changes.size());
339 EXPECT_EQ("change_id=101 node=1,2 new_parent=null old_parent=1,1",
340 changes[0]);
344 // Verifies hierarchy changes are sent to multiple clients.
345 TEST_F(ViewManagerConnectionTest, AddRemoveNotifyMultipleConnections) {
346 EstablishSecondConnection();
348 // Create two nodes in first connection.
349 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
350 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
352 EXPECT_TRUE(client_.GetAndClearChanges().empty());
353 EXPECT_TRUE(client2_.GetAndClearChanges().empty());
355 // Make 2 a child of 1.
357 AllocationScope scope;
358 ASSERT_TRUE(AddNode(view_manager_.get(),
359 CreateNodeId(client_.id(), 1),
360 CreateNodeId(client_.id(), 2),
361 11));
362 Changes changes(client_.GetAndClearChanges());
363 ASSERT_EQ(1u, changes.size());
364 EXPECT_EQ("change_id=11 node=1,2 new_parent=1,1 old_parent=null",
365 changes[0]);
368 // Second client should also have received the change.
370 client2_.DoRunLoopUntilChangesCount(1);
371 Changes changes(client2_.GetAndClearChanges());
372 ASSERT_EQ(1u, changes.size());
373 EXPECT_EQ("change_id=0 node=1,2 new_parent=1,1 old_parent=null",
374 changes[0]);
378 // Verifies adding to root sends right notifications.
379 TEST_F(ViewManagerConnectionTest, AddToRoot) {
380 ASSERT_TRUE(CreateNode(view_manager_.get(), 21));
381 ASSERT_TRUE(CreateNode(view_manager_.get(), 3));
382 EXPECT_TRUE(client_.GetAndClearChanges().empty());
384 // Make 3 a child of 21.
386 AllocationScope scope;
387 ASSERT_TRUE(AddNode(view_manager_.get(),
388 CreateNodeId(client_.id(), 21),
389 CreateNodeId(client_.id(), 3),
390 11));
391 Changes changes(client_.GetAndClearChanges());
392 ASSERT_EQ(1u, changes.size());
393 EXPECT_EQ("change_id=11 node=1,3 new_parent=1,21 old_parent=null",
394 changes[0]);
397 // Make 21 a child of the root.
399 AllocationScope scope;
400 ASSERT_TRUE(AddNode(view_manager_.get(),
401 CreateNodeId(0, 1),
402 CreateNodeId(client_.id(), 21),
403 44));
404 Changes changes(client_.GetAndClearChanges());
405 ASSERT_EQ(1u, changes.size());
406 EXPECT_EQ("change_id=44 node=1,21 new_parent=0,1 old_parent=null",
407 changes[0]);
411 // Verifies DeleteNode works.
412 TEST_F(ViewManagerConnectionTest, DeleteNode) {
413 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
414 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
415 EXPECT_TRUE(client_.GetAndClearChanges().empty());
417 // Make 2 a child of 1.
419 AllocationScope scope;
420 ASSERT_TRUE(AddNode(view_manager_.get(),
421 CreateNodeId(client_.id(), 1),
422 CreateNodeId(client_.id(), 2),
423 11));
424 Changes changes(client_.GetAndClearChanges());
425 ASSERT_EQ(1u, changes.size());
426 EXPECT_EQ("change_id=11 node=1,2 new_parent=1,1 old_parent=null",
427 changes[0]);
430 // Add 1 to the root
432 AllocationScope scope;
433 ASSERT_TRUE(AddNode(view_manager_.get(),
434 CreateNodeId(0, 1),
435 CreateNodeId(client_.id(), 1),
436 101));
437 Changes changes(client_.GetAndClearChanges());
438 ASSERT_EQ(1u, changes.size());
439 EXPECT_EQ("change_id=101 node=1,1 new_parent=0,1 old_parent=null",
440 changes[0]);
443 // Delete 1.
445 AllocationScope scope;
446 ASSERT_TRUE(DeleteNode(view_manager_.get(),
447 CreateNodeId(client_.id(), 1),
448 121));
449 Changes changes(client_.GetAndClearChanges());
450 ASSERT_EQ(3u, changes.size());
451 EXPECT_EQ("change_id=121 node=1,1 new_parent=null old_parent=0,1",
452 changes[0]);
453 EXPECT_EQ("change_id=121 node=1,2 new_parent=null old_parent=1,1",
454 changes[1]);
455 EXPECT_EQ("change_id=121 node=1,1 deleted", changes[2]);
459 // Assertions around setting a view.
460 TEST_F(ViewManagerConnectionTest, SetView) {
461 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
462 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
463 ASSERT_TRUE(CreateView(view_manager_.get(), 11));
464 EXPECT_TRUE(client_.GetAndClearChanges().empty());
466 // Set view 11 on node 1.
468 ASSERT_TRUE(SetView(view_manager_.get(),
469 CreateNodeId(client_.id(), 1),
470 CreateViewId(client_.id(), 11),
471 21));
472 Changes changes(client_.GetAndClearChanges());
473 ASSERT_EQ(1u, changes.size());
474 EXPECT_EQ("change_id=21 node=1,1 new_view=1,11 old_view=null",
475 changes[0]);
478 // Set view 11 on node 2.
480 ASSERT_TRUE(SetView(view_manager_.get(),
481 CreateNodeId(client_.id(), 2),
482 CreateViewId(client_.id(), 11),
483 22));
484 Changes changes(client_.GetAndClearChanges());
485 ASSERT_EQ(2u, changes.size());
486 EXPECT_EQ("change_id=22 node=1,1 new_view=null old_view=1,11",
487 changes[0]);
488 EXPECT_EQ("change_id=22 node=1,2 new_view=1,11 old_view=null",
489 changes[1]);
493 // Verifies deleting a node with a view sends correct notifications.
494 TEST_F(ViewManagerConnectionTest, DeleteNodeWithView) {
495 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
496 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
497 ASSERT_TRUE(CreateView(view_manager_.get(), 11));
498 EXPECT_TRUE(client_.GetAndClearChanges().empty());
500 // Set view 11 on node 1.
501 ASSERT_TRUE(SetView(view_manager_.get(),
502 CreateNodeId(client_.id(), 1),
503 CreateViewId(client_.id(), 11),
504 21));
505 client_.GetAndClearChanges();
507 // Delete node 1.
509 ASSERT_TRUE(DeleteNode(view_manager_.get(),
510 CreateNodeId(client_.id(), 1),
511 121));
512 Changes changes(client_.GetAndClearChanges());
513 ASSERT_EQ(2u, changes.size());
514 EXPECT_EQ("change_id=121 node=1,1 new_view=null old_view=1,11",
515 changes[0]);
516 EXPECT_EQ("change_id=121 node=1,1 deleted", changes[1]);
519 // Set view 11 on node 2.
521 ASSERT_TRUE(SetView(view_manager_.get(),
522 CreateNodeId(client_.id(), 2),
523 CreateViewId(client_.id(), 11),
524 22));
525 Changes changes(client_.GetAndClearChanges());
526 ASSERT_EQ(1u, changes.size());
527 EXPECT_EQ("change_id=22 node=1,2 new_view=1,11 old_view=null", changes[0]);
531 // Sets view from one connection on another.
532 TEST_F(ViewManagerConnectionTest, SetViewFromSecondConnection) {
533 EstablishSecondConnection();
535 // Create two nodes in first connection.
536 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
537 ASSERT_TRUE(CreateNode(view_manager_.get(), 2));
539 EXPECT_TRUE(client_.GetAndClearChanges().empty());
540 EXPECT_TRUE(client2_.GetAndClearChanges().empty());
542 // Create a view in the second connection.
543 ASSERT_TRUE(CreateView(view_manager2_.get(), 51));
545 // Attach view to node 1 in the first connection.
547 ASSERT_TRUE(SetView(view_manager2_.get(),
548 CreateNodeId(client_.id(), 1),
549 CreateViewId(client2_.id(), 51),
550 22));
551 client_.DoRunLoopUntilChangesCount(1);
552 Changes changes(client_.GetAndClearChanges());
553 ASSERT_EQ(1u, changes.size());
554 EXPECT_EQ("change_id=0 node=1,1 new_view=2,51 old_view=null", changes[0]);
556 client2_.DoRunLoopUntilChangesCount(1);
557 changes = client2_.GetAndClearChanges();
558 ASSERT_EQ(1u, changes.size());
559 EXPECT_EQ("change_id=22 node=1,1 new_view=2,51 old_view=null", changes[0]);
562 // Shutdown the second connection and verify view is removed.
564 DestroySecondConnection();
565 client_.DoRunLoopUntilChangesCount(1);
567 Changes changes(client_.GetAndClearChanges());
568 ASSERT_EQ(1u, changes.size());
569 EXPECT_EQ("change_id=0 node=1,1 new_view=null old_view=2,51", changes[0]);
573 // Assertions for GetNodeTree.
574 TEST_F(ViewManagerConnectionTest, GetNodeTree) {
575 EstablishSecondConnection();
577 // Create two nodes in first connection, 1 and 11 (11 is a child of 1).
578 ASSERT_TRUE(CreateNode(view_manager_.get(), 1));
579 ASSERT_TRUE(CreateNode(view_manager_.get(), 11));
580 ASSERT_TRUE(AddNode(view_manager_.get(),
581 CreateNodeId(0, 1),
582 CreateNodeId(client_.id(), 1),
583 101));
584 ASSERT_TRUE(AddNode(view_manager_.get(),
585 CreateNodeId(client_.id(), 1),
586 CreateNodeId(client_.id(), 11),
587 102));
589 // Create two nodes in second connection, 2 and 3, both children of the root.
590 ASSERT_TRUE(CreateNode(view_manager2_.get(), 2));
591 ASSERT_TRUE(CreateNode(view_manager2_.get(), 3));
592 ASSERT_TRUE(AddNode(view_manager2_.get(),
593 CreateNodeId(0, 1),
594 CreateNodeId(client2_.id(), 2),
595 99));
596 ASSERT_TRUE(AddNode(view_manager2_.get(),
597 CreateNodeId(0, 1),
598 CreateNodeId(client2_.id(), 3),
599 99));
601 // Attach view to node 11 in the first connection.
602 ASSERT_TRUE(CreateView(view_manager_.get(), 51));
603 ASSERT_TRUE(SetView(view_manager_.get(),
604 CreateNodeId(client_.id(), 11),
605 CreateViewId(client_.id(), 51),
606 22));
608 // Verifies GetNodeTree() on the root.
610 AllocationScope scope;
611 std::vector<TestNode> nodes;
612 GetNodeTree(view_manager2_.get(), CreateNodeId(0, 1), &nodes);
613 ASSERT_EQ(5u, nodes.size());
614 EXPECT_EQ("node=0,1 parent=null view=null", nodes[0].ToString());
615 EXPECT_EQ("node=1,1 parent=0,1 view=null", nodes[1].ToString());
616 EXPECT_EQ("node=1,11 parent=1,1 view=1,51", nodes[2].ToString());
617 EXPECT_EQ("node=2,2 parent=0,1 view=null", nodes[3].ToString());
618 EXPECT_EQ("node=2,3 parent=0,1 view=null", nodes[4].ToString());
621 // Verifies GetNodeTree() on the node 1,1.
623 AllocationScope scope;
624 std::vector<TestNode> nodes;
625 GetNodeTree(view_manager2_.get(), CreateNodeId(1, 1), &nodes);
626 ASSERT_EQ(2u, nodes.size());
627 EXPECT_EQ("node=1,1 parent=0,1 view=null", nodes[0].ToString());
628 EXPECT_EQ("node=1,11 parent=1,1 view=1,51", nodes[1].ToString());
632 } // namespace view_manager
633 } // namespace services
634 } // namespace mojo