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.
4
5#include "mojo/services/public/cpp/view_manager/view_manager.h"
6
7#include "base/auto_reset.h"
8#include "base/bind.h"
9#include "base/logging.h"
10#include "mojo/public/cpp/application/application.h"
11#include "mojo/service_manager/service_manager.h"
12#include "mojo/services/public/cpp/view_manager/lib/node_private.h"
13#include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h"
14#include "mojo/services/public/cpp/view_manager/node_observer.h"
15#include "mojo/services/public/cpp/view_manager/util.h"
16#include "mojo/services/public/cpp/view_manager/view.h"
17#include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
18#include "mojo/services/public/cpp/view_manager/view_observer.h"
19#include "mojo/shell/shell_test_helper.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22namespace mojo {
23namespace view_manager {
24namespace {
25
26const char kWindowManagerURL[] = "mojo:window_manager";
27const char kEmbeddedApp1URL[] = "mojo:embedded_app_1";
28
29base::RunLoop* current_run_loop = NULL;
30
31void DoRunLoop() {
32  base::RunLoop run_loop;
33  current_run_loop = &run_loop;
34  current_run_loop->Run();
35  current_run_loop = NULL;
36}
37
38void QuitRunLoop() {
39  current_run_loop->Quit();
40}
41
42void WaitForAllChangesToBeAcked(ViewManagerClientImpl* client) {
43  client->set_changes_acked_callback(base::Bind(&QuitRunLoop));
44  DoRunLoop();
45  client->ClearChangesAckedCallback();
46}
47
48class ConnectServiceLoader : public ServiceLoader,
49                             public ViewManagerDelegate {
50 public:
51  typedef base::Callback<void(ViewManager*, Node*)> LoadedCallback;
52
53  explicit ConnectServiceLoader(const LoadedCallback& callback)
54      : callback_(callback) {
55  }
56  virtual ~ConnectServiceLoader() {}
57
58 private:
59  // Overridden from ServiceLoader:
60  virtual void LoadService(ServiceManager* manager,
61                           const GURL& url,
62                           ScopedMessagePipeHandle shell_handle) OVERRIDE {
63    scoped_ptr<Application> app(new Application(shell_handle.Pass()));
64    ViewManager::Create(app.get(), this);
65    apps_.push_back(app.release());
66  }
67  virtual void OnServiceError(ServiceManager* manager,
68                              const GURL& url) OVERRIDE {
69  }
70
71  // Overridden from ViewManagerDelegate:
72  virtual void OnRootAdded(ViewManager* view_manager,
73                           Node* root) OVERRIDE {
74    callback_.Run(view_manager, root);
75  }
76
77  ScopedVector<Application> apps_;
78  LoadedCallback callback_;
79
80  DISALLOW_COPY_AND_ASSIGN(ConnectServiceLoader);
81};
82
83class ActiveViewChangedObserver : public NodeObserver {
84 public:
85  explicit ActiveViewChangedObserver(Node* node)
86      : node_(node) {}
87  virtual ~ActiveViewChangedObserver() {}
88
89 private:
90  // Overridden from NodeObserver:
91  virtual void OnNodeActiveViewChange(Node* node,
92                                      View* old_view,
93                                      View* new_view,
94                                      DispositionChangePhase phase) OVERRIDE {
95    DCHECK_EQ(node, node_);
96    QuitRunLoop();
97  }
98
99  Node* node_;
100
101  DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedObserver);
102};
103
104// Waits until the active view id of the supplied node changes.
105void WaitForActiveViewToChange(Node* node) {
106  ActiveViewChangedObserver observer(node);
107  node->AddObserver(&observer);
108  DoRunLoop();
109  node->RemoveObserver(&observer);
110}
111
112class BoundsChangeObserver : public NodeObserver {
113 public:
114  explicit BoundsChangeObserver(Node* node) : node_(node) {}
115  virtual ~BoundsChangeObserver() {}
116
117 private:
118  // Overridden from NodeObserver:
119  virtual void OnNodeBoundsChange(Node* node,
120                                  const gfx::Rect& old_bounds,
121                                  const gfx::Rect& new_bounds,
122                                  DispositionChangePhase phase) OVERRIDE {
123    DCHECK_EQ(node, node_);
124    if (phase != NodeObserver::DISPOSITION_CHANGED)
125      return;
126    QuitRunLoop();
127  }
128
129  Node* node_;
130
131  DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
132};
133
134// Wait until the bounds of the supplied node change.
135void WaitForBoundsToChange(Node* node) {
136  BoundsChangeObserver observer(node);
137  node->AddObserver(&observer);
138  DoRunLoop();
139  node->RemoveObserver(&observer);
140}
141
142// Spins a runloop until the tree beginning at |root| has |tree_size| nodes
143// (including |root|).
144class TreeSizeMatchesObserver : public NodeObserver {
145 public:
146  TreeSizeMatchesObserver(Node* tree, size_t tree_size)
147      : tree_(tree),
148        tree_size_(tree_size) {}
149  virtual ~TreeSizeMatchesObserver() {}
150
151  bool IsTreeCorrectSize() {
152    return CountNodes(tree_) == tree_size_;
153  }
154
155 private:
156  // Overridden from NodeObserver:
157  virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE {
158    if (IsTreeCorrectSize())
159      QuitRunLoop();
160  }
161
162  size_t CountNodes(const Node* node) const {
163    size_t count = 1;
164    Node::Children::const_iterator it = node->children().begin();
165    for (; it != node->children().end(); ++it)
166      count += CountNodes(*it);
167    return count;
168  }
169
170  Node* tree_;
171  size_t tree_size_;
172
173  DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
174};
175
176void WaitForTreeSizeToMatch(Node* node, size_t tree_size) {
177  TreeSizeMatchesObserver observer(node, tree_size);
178  if (observer.IsTreeCorrectSize())
179    return;
180  node->AddObserver(&observer);
181  DoRunLoop();
182  node->RemoveObserver(&observer);
183}
184
185
186// Utility class that waits for the destruction of some number of nodes and
187// views.
188class DestructionObserver : public NodeObserver, public ViewObserver {
189 public:
190  // |nodes| or |views| can be NULL.
191  DestructionObserver(std::set<Id>* nodes, std::set<Id>* views)
192      : nodes_(nodes),
193        views_(views) {}
194
195 private:
196  // Overridden from NodeObserver:
197  virtual void OnNodeDestroy(
198      Node* node,
199      NodeObserver::DispositionChangePhase phase) OVERRIDE {
200    if (phase != NodeObserver::DISPOSITION_CHANGED)
201      return;
202    std::set<Id>::iterator it = nodes_->find(node->id());
203    if (it != nodes_->end())
204      nodes_->erase(it);
205    if (CanQuit())
206      QuitRunLoop();
207  }
208
209  // Overridden from ViewObserver:
210  virtual void OnViewDestroy(
211      View* view,
212      ViewObserver::DispositionChangePhase phase) OVERRIDE {
213    if (phase != ViewObserver::DISPOSITION_CHANGED)
214      return;
215    std::set<Id>::iterator it = views_->find(view->id());
216    if (it != views_->end())
217      views_->erase(it);
218    if (CanQuit())
219      QuitRunLoop();
220  }
221
222  bool CanQuit() {
223    return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty());
224  }
225
226  std::set<Id>* nodes_;
227  std::set<Id>* views_;
228
229  DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
230};
231
232void WaitForDestruction(ViewManager* view_manager,
233                        std::set<Id>* nodes,
234                        std::set<Id>* views) {
235  DestructionObserver observer(nodes, views);
236  DCHECK(nodes || views);
237  if (nodes) {
238    for (std::set<Id>::const_iterator it = nodes->begin();
239          it != nodes->end(); ++it) {
240      view_manager->GetNodeById(*it)->AddObserver(&observer);
241    }
242  }
243  if (views) {
244    for (std::set<Id>::const_iterator it = views->begin();
245          it != views->end(); ++it) {
246      view_manager->GetViewById(*it)->AddObserver(&observer);
247    }
248  }
249  DoRunLoop();
250}
251
252class OrderChangeObserver : public NodeObserver {
253 public:
254  OrderChangeObserver(Node* node) : node_(node) {
255    node_->AddObserver(this);
256  }
257  virtual ~OrderChangeObserver() {
258    node_->RemoveObserver(this);
259  }
260
261 private:
262  // Overridden from NodeObserver:
263  virtual void OnNodeReordered(Node* node,
264                               Node* relative_node,
265                               OrderDirection direction,
266                               DispositionChangePhase phase) OVERRIDE {
267    if (phase != NodeObserver::DISPOSITION_CHANGED)
268      return;
269
270    DCHECK_EQ(node, node_);
271    QuitRunLoop();
272  }
273
274  Node* node_;
275
276  DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
277};
278
279void WaitForOrderChange(ViewManager* view_manager, Node* node) {
280  OrderChangeObserver observer(node);
281  DoRunLoop();
282}
283
284// Tracks a node's destruction. Query is_valid() for current state.
285class NodeTracker : public NodeObserver {
286 public:
287  explicit NodeTracker(Node* node) : node_(node) {
288    node_->AddObserver(this);
289  }
290  virtual ~NodeTracker() {
291    if (node_)
292      node_->RemoveObserver(this);
293  }
294
295  bool is_valid() const { return !!node_; }
296
297 private:
298  // Overridden from NodeObserver:
299  virtual void OnNodeDestroy(
300      Node* node,
301      NodeObserver::DispositionChangePhase phase) OVERRIDE {
302    if (phase != NodeObserver::DISPOSITION_CHANGED)
303      return;
304    DCHECK_EQ(node, node_);
305    node_ = NULL;
306  }
307
308  int id_;
309  Node* node_;
310
311  DISALLOW_COPY_AND_ASSIGN(NodeTracker);
312};
313
314}  // namespace
315
316// ViewManager -----------------------------------------------------------------
317
318// These tests model synchronization of two peer connections to the view manager
319// service, that are given access to some root node.
320
321class ViewManagerTest : public testing::Test {
322 public:
323  ViewManagerTest()
324      : connect_loop_(NULL),
325        loaded_view_manager_(NULL),
326        window_manager_(NULL),
327        commit_count_(0) {}
328
329 protected:
330  ViewManager* window_manager() { return window_manager_; }
331
332  Node* CreateNodeInParent(Node* parent) {
333    ViewManager* parent_manager = NodePrivate(parent).view_manager();
334    Node* node = Node::Create(parent_manager);
335    parent->AddChild(node);
336    return node;
337  }
338
339  // Embeds another version of the test app @ node.
340  ViewManager* Embed(ViewManager* view_manager, Node* node) {
341    DCHECK_EQ(view_manager, NodePrivate(node).view_manager());
342    node->Embed(kEmbeddedApp1URL);
343    RunRunLoop();
344    return GetLoadedViewManager();
345  }
346
347  // TODO(beng): remove these methods once all the tests are migrated.
348  void DestroyViewManager1() {}
349  ViewManager* view_manager_1() { return NULL; }
350  ViewManager* view_manager_2() { return NULL; }
351
352  ViewManager* GetLoadedViewManager() {
353    ViewManager* view_manager = loaded_view_manager_;
354    loaded_view_manager_ = NULL;
355    return view_manager;
356  }
357
358  void UnloadApplication(const GURL& url) {
359    test_helper_.SetLoaderForURL(scoped_ptr<ServiceLoader>(), url);
360  }
361
362 private:
363  // Overridden from testing::Test:
364  virtual void SetUp() OVERRIDE {
365    ConnectServiceLoader::LoadedCallback ready_callback =
366        base::Bind(&ViewManagerTest::OnViewManagerLoaded,
367                   base::Unretained(this));
368    test_helper_.Init();
369    test_helper_.SetLoaderForURL(
370        scoped_ptr<ServiceLoader>(new ConnectServiceLoader(ready_callback)),
371        GURL(kWindowManagerURL));
372    test_helper_.SetLoaderForURL(
373        scoped_ptr<ServiceLoader>(new ConnectServiceLoader(ready_callback)),
374        GURL(kEmbeddedApp1URL));
375
376    ConnectToService(test_helper_.service_provider(),
377                     "mojo:mojo_view_manager",
378                     &view_manager_init_);
379    ASSERT_TRUE(EmbedRoot(view_manager_init_.get(), kWindowManagerURL));
380  }
381
382  void EmbedRootCallback(bool* result_cache, bool result) {
383    *result_cache = result;
384  }
385
386  bool EmbedRoot(ViewManagerInitService* view_manager_init,
387                 const std::string& url) {
388    bool result = false;
389    view_manager_init->EmbedRoot(
390        url,
391        base::Bind(&ViewManagerTest::EmbedRootCallback, base::Unretained(this),
392                   &result));
393    RunRunLoop();
394    window_manager_ = GetLoadedViewManager();
395    return result;
396  }
397
398  void OnViewManagerLoaded(ViewManager* view_manager, Node* root) {
399    loaded_view_manager_ = view_manager;
400    connect_loop_->Quit();
401  }
402
403  void RunRunLoop() {
404    base::RunLoop run_loop;
405    connect_loop_ = &run_loop;
406    connect_loop_->Run();
407    connect_loop_ = NULL;
408  }
409
410  base::MessageLoop loop_;
411  base::RunLoop* connect_loop_;
412  shell::ShellTestHelper test_helper_;
413  ViewManagerInitServicePtr view_manager_init_;
414  // Used to receive the most recent view manager loaded by an embed action.
415  ViewManager* loaded_view_manager_;
416  // The View Manager connection held by the window manager (app running at the
417  // root node).
418  ViewManager* window_manager_;
419  int commit_count_;
420
421  DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
422};
423
424TEST_F(ViewManagerTest, SetUp) {}
425
426TEST_F(ViewManagerTest, Embed) {
427  Node* node = Node::Create(window_manager());
428  window_manager()->GetRoots().front()->AddChild(node);
429  ViewManager* embedded = Embed(window_manager(), node);
430  EXPECT_TRUE(NULL != embedded);
431
432  Node* node_in_embedded = embedded->GetRoots().front();
433  EXPECT_EQ(node->parent(), window_manager()->GetRoots().front());
434  EXPECT_EQ(NULL, node_in_embedded->parent());
435}
436
437// When Window Manager embeds A @ N, then creates N2 and parents to N, N becomes
438// visible to A.
439// TODO(beng): verify whether or not this is a policy we like.
440TEST_F(ViewManagerTest, HierarchyChanged_NodeAdded) {
441  Node* node = Node::Create(window_manager());
442  window_manager()->GetRoots().front()->AddChild(node);
443  ViewManager* embedded = Embed(window_manager(), node);
444  Node* nested = Node::Create(window_manager());
445  node->AddChild(nested);
446  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 2);
447  EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(),
448            nested->id());
449}
450
451// Window manager has two nodes, N1 & N2. Embeds A at N1. Creates node N21,
452// a child of N2. Reparents N2 to N1. N1 should become visible to A.
453// TODO(beng): verify whether or not this is a policy we like.
454TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) {
455  Node* node1 = Node::Create(window_manager());
456  window_manager()->GetRoots().front()->AddChild(node1);
457  ViewManager* embedded = Embed(window_manager(), node1);
458  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1);
459
460  Node* node2 = Node::Create(window_manager());
461  window_manager()->GetRoots().front()->AddChild(node2);
462  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1);
463  EXPECT_TRUE(embedded->GetRoots().front()->children().empty());
464
465  Node* node21 = Node::Create(window_manager());
466  node2->AddChild(node21);
467  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1);
468  EXPECT_TRUE(embedded->GetRoots().front()->children().empty());
469
470  // Makes node21 visible to |embedded|.
471  node1->AddChild(node21);
472  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 2);
473  EXPECT_FALSE(embedded->GetRoots().front()->children().empty());
474  EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(),
475            node21->id());
476}
477
478// Window manager has two nodes, N1 and N11. Embeds A at N1. Removes N11 from
479// N1. N11 should disappear from A.
480// TODO(beng): verify whether or not this is a policy we like.
481TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) {
482  Node* node = Node::Create(window_manager());
483  window_manager()->GetRoots().front()->AddChild(node);
484  Node* nested = Node::Create(window_manager());
485  node->AddChild(nested);
486
487  ViewManager* embedded = Embed(window_manager(), node);
488  EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(),
489            nested->id());
490
491  node->RemoveChild(nested);
492  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1);
493  EXPECT_TRUE(embedded->GetRoots().front()->children().empty());
494}
495
496// Window manager has two nodes, N1 and N11. Embeds A at N1. Destroys N11.
497// N11 should disappear from A.
498// TODO(beng): verify whether or not this is a policy we like.
499TEST_F(ViewManagerTest, NodeDestroyed) {
500  Node* node = Node::Create(window_manager());
501  window_manager()->GetRoots().front()->AddChild(node);
502  Node* nested = Node::Create(window_manager());
503  node->AddChild(nested);
504
505  ViewManager* embedded = Embed(window_manager(), node);
506  EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(),
507            nested->id());
508
509  // |nested| will be deleted after calling Destroy() below.
510  Id id = nested->id();
511  nested->Destroy();
512
513  std::set<Id> nodes;
514  nodes.insert(id);
515  WaitForDestruction(embedded, &nodes, NULL);
516
517  EXPECT_TRUE(embedded->GetRoots().front()->children().empty());
518  EXPECT_EQ(NULL, embedded->GetNodeById(id));
519}
520
521TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) {
522  Node* node = Node::Create(window_manager());
523  window_manager()->GetRoots().front()->AddChild(node);
524  ViewManager* embedded = Embed(window_manager(), node);
525
526  Id node_id = node->id();
527
528  UnloadApplication(GURL(kWindowManagerURL));
529
530  std::set<Id> nodes;
531  nodes.insert(node_id);
532  WaitForDestruction(embedded, &nodes, NULL);
533
534  EXPECT_TRUE(embedded->GetRoots().empty());
535}
536
537TEST_F(ViewManagerTest, SetActiveView) {
538  Node* node = Node::Create(window_manager());
539  window_manager()->GetRoots().front()->AddChild(node);
540  ViewManager* embedded = Embed(window_manager(), node);
541
542  View* view = View::Create(window_manager());
543  node->SetActiveView(view);
544
545  Node* node_in_embedded = embedded->GetNodeById(node->id());
546  WaitForActiveViewToChange(node_in_embedded);
547
548  EXPECT_EQ(node_in_embedded->active_view()->id(), view->id());
549}
550
551TEST_F(ViewManagerTest, DestroyView) {
552  Node* node = Node::Create(window_manager());
553  window_manager()->GetRoots().front()->AddChild(node);
554  ViewManager* embedded = Embed(window_manager(), node);
555
556  View* view = View::Create(window_manager());
557  node->SetActiveView(view);
558
559  Node* node_in_embedded = embedded->GetNodeById(node->id());
560  WaitForActiveViewToChange(node_in_embedded);
561
562  EXPECT_EQ(node_in_embedded->active_view()->id(), view->id());
563
564  Id view_id = view->id();
565  view->Destroy();
566
567  std::set<Id> views;
568  views.insert(view_id);
569  WaitForDestruction(embedded, NULL, &views);
570  EXPECT_EQ(NULL, node_in_embedded->active_view());
571  EXPECT_EQ(NULL, embedded->GetViewById(view_id));
572}
573
574// Destroying the connection that created a node and view should result in that
575// node and view disappearing from all connections that see them.
576TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) {
577  Node* node = Node::Create(window_manager());
578  window_manager()->GetRoots().front()->AddChild(node);
579  View* view = View::Create(window_manager());
580  node->SetActiveView(view);
581  ViewManager* embedded = Embed(window_manager(), node);
582
583  Id node_id = node->id();
584  Id view_id = view->id();
585
586  UnloadApplication(GURL(kWindowManagerURL));
587
588  std::set<Id> observed_nodes;
589  observed_nodes.insert(node_id);
590  std::set<Id> observed_views;
591  observed_views.insert(view_id);
592  WaitForDestruction(embedded, &observed_nodes, &observed_views);
593
594  EXPECT_TRUE(embedded->GetRoots().empty());
595  EXPECT_EQ(NULL, embedded->GetNodeById(node_id));
596  EXPECT_EQ(NULL, embedded->GetViewById(view_id));
597}
598
599// This test validates the following scenario:
600// -  a node originating from one connection
601// -  a view originating from a second connection
602// +  the connection originating the node is destroyed
603// -> the view should still exist (since the second connection is live) but
604//    should be disconnected from any nodes.
605TEST_F(ViewManagerTest,
606       ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) {
607  Node* node = Node::Create(window_manager());
608  window_manager()->GetRoots().front()->AddChild(node);
609  ViewManager* embedded = Embed(window_manager(), node);
610  View* view_in_embedded = View::Create(embedded);
611  Node* node_in_embedded = embedded->GetNodeById(node->id());
612  node_in_embedded->SetActiveView(view_in_embedded);
613
614  WaitForActiveViewToChange(node);
615
616  Id node_id = node->id();
617  Id view_id = view_in_embedded->id();
618
619  UnloadApplication(GURL(kWindowManagerURL));
620  std::set<Id> nodes;
621  nodes.insert(node_id);
622  WaitForDestruction(embedded, &nodes, NULL);
623
624  EXPECT_TRUE(embedded->GetRoots().empty());
625  // node was owned by the window manager, so it should be gone.
626  EXPECT_EQ(NULL, embedded->GetNodeById(node_id));
627  // view_in_embedded was owned by the embedded app, so it should still exist,
628  // but disconnected from the node tree.
629  EXPECT_EQ(view_in_embedded, embedded->GetViewById(view_id));
630  EXPECT_EQ(NULL, view_in_embedded->node());
631}
632
633// This test verifies that it is not possible to set the active view to a view
634// defined in a different connection.
635// TODO(beng): write these tests for Node::AddChild(), RemoveChild() and
636//             Contains().
637TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) {
638  Node* node = Node::Create(window_manager());
639  window_manager()->GetRoots().front()->AddChild(node);
640  ViewManager* embedded = Embed(window_manager(), node);
641
642  View* view_in_embedded = View::Create(embedded);
643  EXPECT_DEATH(node->SetActiveView(view_in_embedded), "");
644}
645
646// This test verifies that a node hierarchy constructed in one connection
647// becomes entirely visible to the second connection when the hierarchy is
648// attached.
649TEST_F(ViewManagerTest, MapSubtreeOnAttach) {
650  Node* node = Node::Create(window_manager());
651  window_manager()->GetRoots().front()->AddChild(node);
652  ViewManager* embedded = Embed(window_manager(), node);
653
654  // Create a subtree private to the window manager and make some changes to it.
655  Node* child1 = Node::Create(window_manager());
656  Node* child11 = Node::Create(window_manager());
657  child1->AddChild(child11);
658  gfx::Rect child11_bounds(800, 600);
659  child11->SetBounds(child11_bounds);
660  View* view11 = View::Create(window_manager());
661  child11->SetActiveView(view11);
662  WaitForAllChangesToBeAcked(
663      static_cast<ViewManagerClientImpl*>(window_manager()));
664
665  // When added to the shared node, the entire hierarchy and all property
666  // changes should become visible to the embedded app.
667  node->AddChild(child1);
668  WaitForTreeSizeToMatch(embedded->GetRoots().front(), 3);
669
670  Node* child11_in_embedded = embedded->GetNodeById(child11->id());
671  View* view11_in_embedded = embedded->GetViewById(view11->id());
672  EXPECT_TRUE(child11_in_embedded != NULL);
673  EXPECT_EQ(view11_in_embedded, child11_in_embedded->active_view());
674  EXPECT_EQ(child11_bounds, child11_in_embedded->bounds());
675}
676
677// Verifies that bounds changes applied to a node hierarchy in one connection
678// are reflected to another.
679TEST_F(ViewManagerTest, SetBounds) {
680  Node* node = Node::Create(window_manager());
681  window_manager()->GetRoots().front()->AddChild(node);
682  ViewManager* embedded = Embed(window_manager(), node);
683
684  Node* node_in_embedded = embedded->GetNodeById(node->id());
685  EXPECT_EQ(node->bounds(), node_in_embedded->bounds());
686
687  node->SetBounds(gfx::Rect(100, 100));
688  EXPECT_NE(node->bounds(), node_in_embedded->bounds());
689  WaitForBoundsToChange(node_in_embedded);
690  EXPECT_EQ(node->bounds(), node_in_embedded->bounds());
691}
692
693// Verifies that bounds changes applied to a node owned by a different
694// connection are refused.
695TEST_F(ViewManagerTest, SetBoundsSecurity) {
696  Node* node = Node::Create(window_manager());
697  window_manager()->GetRoots().front()->AddChild(node);
698  ViewManager* embedded = Embed(window_manager(), node);
699
700  Node* node_in_embedded = embedded->GetNodeById(node->id());
701  node->SetBounds(gfx::Rect(800, 600));
702  WaitForBoundsToChange(node_in_embedded);
703
704  node_in_embedded->SetBounds(gfx::Rect(1024, 768));
705  // Bounds change should have been rejected.
706  EXPECT_EQ(node->bounds(), node_in_embedded->bounds());
707}
708
709// Verifies that a node can only be destroyed by the connection that created it.
710TEST_F(ViewManagerTest, DestroySecurity) {
711  Node* node = Node::Create(window_manager());
712  window_manager()->GetRoots().front()->AddChild(node);
713  ViewManager* embedded = Embed(window_manager(), node);
714
715  Node* node_in_embedded = embedded->GetNodeById(node->id());
716
717  NodeTracker tracker2(node_in_embedded);
718  node_in_embedded->Destroy();
719  // Node should not have been destroyed.
720  EXPECT_TRUE(tracker2.is_valid());
721
722  NodeTracker tracker1(node);
723  node->Destroy();
724  EXPECT_FALSE(tracker1.is_valid());
725}
726
727TEST_F(ViewManagerTest, MultiRoots) {
728  Node* node1 = Node::Create(window_manager());
729  window_manager()->GetRoots().front()->AddChild(node1);
730  Node* node2 = Node::Create(window_manager());
731  window_manager()->GetRoots().front()->AddChild(node2);
732  ViewManager* embedded1 = Embed(window_manager(), node1);
733  ViewManager* embedded2 = Embed(window_manager(), node2);
734  EXPECT_EQ(embedded1, embedded2);
735}
736
737TEST_F(ViewManagerTest, EmbeddingIdentity) {
738  Node* node = Node::Create(window_manager());
739  window_manager()->GetRoots().front()->AddChild(node);
740  ViewManager* embedded = Embed(window_manager(), node);
741  EXPECT_EQ(kWindowManagerURL, embedded->GetEmbedderURL());
742}
743
744TEST_F(ViewManagerTest, Reorder) {
745  Node* node1 = Node::Create(window_manager());
746  window_manager()->GetRoots().front()->AddChild(node1);
747
748  Node* node11 = Node::Create(window_manager());
749  node1->AddChild(node11);
750  Node* node12 = Node::Create(window_manager());
751  node1->AddChild(node12);
752
753  ViewManager* embedded = Embed(window_manager(), node1);
754
755  Node* node1_in_embedded = embedded->GetNodeById(node1->id());
756
757  {
758    node11->MoveToFront();
759    WaitForOrderChange(embedded, embedded->GetNodeById(node11->id()));
760
761    EXPECT_EQ(node1_in_embedded->children().front(),
762              embedded->GetNodeById(node12->id()));
763    EXPECT_EQ(node1_in_embedded->children().back(),
764              embedded->GetNodeById(node11->id()));
765  }
766
767  {
768    node11->MoveToBack();
769    WaitForOrderChange(embedded, embedded->GetNodeById(node11->id()));
770
771    EXPECT_EQ(node1_in_embedded->children().front(),
772              embedded->GetNodeById(node11->id()));
773    EXPECT_EQ(node1_in_embedded->children().back(),
774              embedded->GetNodeById(node12->id()));
775  }
776}
777
778}  // namespace view_manager
779}  // namespace mojo
780