Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: mojo/services/view_manager/view_manager_client_apptest.cc

Issue 1049993002: Get mojo_shell building inside chromium checkout. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix presubmit Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "third_party/mojo_services/src/view_manager/public/cpp/view_manager.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/test/test_timeouts.h"
14 #include "mojo/public/cpp/application/application_connection.h"
15 #include "mojo/public/cpp/application/application_delegate.h"
16 #include "mojo/public/cpp/application/application_impl.h"
17 #include "mojo/public/cpp/application/application_test_base.h"
18 #include "mojo/public/cpp/application/service_provider_impl.h"
19 #include "third_party/mojo_services/src/geometry/public/cpp/geometry_util.h"
20 #include "third_party/mojo_services/src/view_manager/public/cpp/lib/view_manager _client_impl.h"
21 #include "third_party/mojo_services/src/view_manager/public/cpp/view_manager_cli ent_factory.h"
22 #include "third_party/mojo_services/src/view_manager/public/cpp/view_manager_con text.h"
23 #include "third_party/mojo_services/src/view_manager/public/cpp/view_manager_del egate.h"
24 #include "third_party/mojo_services/src/view_manager/public/cpp/view_observer.h"
25
26 namespace mojo {
27
28 namespace {
29
30 base::RunLoop* current_run_loop = nullptr;
31
32 void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) {
33 CHECK(current_run_loop);
34 *timeout = true;
35 timeout_task.Run();
36 }
37
38 bool DoRunLoopWithTimeout() {
39 if (current_run_loop != nullptr)
40 return false;
41
42 bool timeout = false;
43 base::RunLoop run_loop;
44 base::MessageLoop::current()->PostDelayedTask(
45 FROM_HERE, base::Bind(&TimeoutRunLoop, run_loop.QuitClosure(), &timeout),
46 TestTimeouts::action_timeout());
47
48 current_run_loop = &run_loop;
49 current_run_loop->Run();
50 current_run_loop = nullptr;
51 return !timeout;
52 }
53
54 void QuitRunLoop() {
55 current_run_loop->Quit();
56 current_run_loop = nullptr;
57 }
58
59 class BoundsChangeObserver : public ViewObserver {
60 public:
61 explicit BoundsChangeObserver(View* view) : view_(view) {
62 view_->AddObserver(this);
63 }
64 ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
65
66 private:
67 // Overridden from ViewObserver:
68 void OnViewBoundsChanged(View* view,
69 const Rect& old_bounds,
70 const Rect& new_bounds) override {
71 DCHECK_EQ(view, view_);
72 QuitRunLoop();
73 }
74
75 View* view_;
76
77 MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
78 };
79
80 // Wait until the bounds of the supplied view change; returns false on timeout.
81 bool WaitForBoundsToChange(View* view) {
82 BoundsChangeObserver observer(view);
83 return DoRunLoopWithTimeout();
84 }
85
86 // Spins a run loop until the tree beginning at |root| has |tree_size| views
87 // (including |root|).
88 class TreeSizeMatchesObserver : public ViewObserver {
89 public:
90 TreeSizeMatchesObserver(View* tree, size_t tree_size)
91 : tree_(tree), tree_size_(tree_size) {
92 tree_->AddObserver(this);
93 }
94 ~TreeSizeMatchesObserver() override { tree_->RemoveObserver(this); }
95
96 bool IsTreeCorrectSize() { return CountViews(tree_) == tree_size_; }
97
98 private:
99 // Overridden from ViewObserver:
100 void OnTreeChanged(const TreeChangeParams& params) override {
101 if (IsTreeCorrectSize())
102 QuitRunLoop();
103 }
104
105 size_t CountViews(const View* view) const {
106 size_t count = 1;
107 View::Children::const_iterator it = view->children().begin();
108 for (; it != view->children().end(); ++it)
109 count += CountViews(*it);
110 return count;
111 }
112
113 View* tree_;
114 size_t tree_size_;
115
116 MOJO_DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
117 };
118
119 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
120 bool WaitForTreeSizeToMatch(View* view, size_t tree_size) {
121 TreeSizeMatchesObserver observer(view, tree_size);
122 return observer.IsTreeCorrectSize() || DoRunLoopWithTimeout();
123 }
124
125 class OrderChangeObserver : public ViewObserver {
126 public:
127 OrderChangeObserver(View* view) : view_(view) { view_->AddObserver(this); }
128 ~OrderChangeObserver() override { view_->RemoveObserver(this); }
129
130 private:
131 // Overridden from ViewObserver:
132 void OnViewReordered(View* view,
133 View* relative_view,
134 OrderDirection direction) override {
135 DCHECK_EQ(view, view_);
136 QuitRunLoop();
137 }
138
139 View* view_;
140
141 MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
142 };
143
144 // Wait until |view|'s tree size matches |tree_size|; returns false on timeout.
145 bool WaitForOrderChange(ViewManager* view_manager, View* view) {
146 OrderChangeObserver observer(view);
147 return DoRunLoopWithTimeout();
148 }
149
150 // Tracks a view's destruction. Query is_valid() for current state.
151 class ViewTracker : public ViewObserver {
152 public:
153 explicit ViewTracker(View* view) : view_(view) { view_->AddObserver(this); }
154 ~ViewTracker() override {
155 if (view_)
156 view_->RemoveObserver(this);
157 }
158
159 bool is_valid() const { return !!view_; }
160
161 private:
162 // Overridden from ViewObserver:
163 void OnViewDestroyed(View* view) override {
164 DCHECK_EQ(view, view_);
165 view_ = nullptr;
166 }
167
168 int id_;
169 View* view_;
170
171 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewTracker);
172 };
173
174 } // namespace
175
176 // ViewManager -----------------------------------------------------------------
177
178 // These tests model synchronization of two peer connections to the view manager
179 // service, that are given access to some root view.
180
181 class ViewManagerTest : public test::ApplicationTestBase,
182 public ApplicationDelegate,
183 public ViewManagerDelegate {
184 public:
185 ViewManagerTest()
186 : most_recent_view_manager_(nullptr), window_manager_(nullptr) {}
187
188 // Overridden from ApplicationDelegate:
189 void Initialize(ApplicationImpl* app) override {
190 view_manager_client_factory_.reset(
191 new ViewManagerClientFactory(app->shell(), this));
192 }
193
194 // ApplicationDelegate implementation.
195 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
196 connection->AddService(view_manager_client_factory_.get());
197 return true;
198 }
199
200 ViewManager* window_manager() { return window_manager_; }
201
202 // Embeds another version of the test app @ view; returns nullptr on timeout.
203 ViewManager* Embed(ViewManager* view_manager, View* view) {
204 DCHECK_EQ(view_manager, view->view_manager());
205 most_recent_view_manager_ = nullptr;
206 view->Embed(application_impl()->url());
207 if (!DoRunLoopWithTimeout())
208 return nullptr;
209 ViewManager* vm = nullptr;
210 std::swap(vm, most_recent_view_manager_);
211 return vm;
212 }
213
214 ApplicationDelegate* GetApplicationDelegate() override { return this; }
215
216 // Overridden from ViewManagerDelegate:
217 void OnEmbed(View* root,
218 InterfaceRequest<ServiceProvider> services,
219 ServiceProviderPtr exposed_services) override {
220 most_recent_view_manager_ = root->view_manager();
221 QuitRunLoop();
222 }
223 void OnViewManagerDisconnected(ViewManager* view_manager) override {}
224
225 private:
226 // Overridden from testing::Test:
227 void SetUp() override {
228 ApplicationTestBase::SetUp();
229
230 view_manager_context_.reset(new ViewManagerContext(application_impl()));
231 view_manager_context_->Embed(application_impl()->url());
232 ASSERT_TRUE(DoRunLoopWithTimeout());
233 std::swap(window_manager_, most_recent_view_manager_);
234 }
235
236 // Overridden from testing::Test:
237 void TearDown() override { ApplicationTestBase::TearDown(); }
238
239 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_;
240
241 scoped_ptr<ViewManagerContext> view_manager_context_;
242
243 // Used to receive the most recent view manager loaded by an embed action.
244 ViewManager* most_recent_view_manager_;
245 // The View Manager connection held by the window manager (app running at the
246 // root view).
247 ViewManager* window_manager_;
248
249 MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
250 };
251
252 TEST_F(ViewManagerTest, RootView) {
253 ASSERT_NE(nullptr, window_manager());
254 EXPECT_NE(nullptr, window_manager()->GetRoot());
255 EXPECT_EQ("mojo:window_manager", window_manager()->GetEmbedderURL());
256 }
257
258 TEST_F(ViewManagerTest, Embed) {
259 View* view = window_manager()->CreateView();
260 ASSERT_NE(nullptr, view);
261 view->SetVisible(true);
262 window_manager()->GetRoot()->AddChild(view);
263 ViewManager* embedded = Embed(window_manager(), view);
264 ASSERT_NE(nullptr, embedded);
265
266 View* view_in_embedded = embedded->GetRoot();
267 ASSERT_NE(nullptr, view_in_embedded);
268 EXPECT_EQ(view->id(), view_in_embedded->id());
269 EXPECT_EQ(nullptr, view_in_embedded->parent());
270 EXPECT_TRUE(view_in_embedded->children().empty());
271 }
272
273 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see
274 // N11.
275 TEST_F(ViewManagerTest, EmbeddedDoesntSeeChild) {
276 View* view = window_manager()->CreateView();
277 ASSERT_NE(nullptr, view);
278 view->SetVisible(true);
279 window_manager()->GetRoot()->AddChild(view);
280 View* nested = window_manager()->CreateView();
281 ASSERT_NE(nullptr, nested);
282 nested->SetVisible(true);
283 view->AddChild(nested);
284
285 ViewManager* embedded = Embed(window_manager(), view);
286 ASSERT_NE(nullptr, embedded);
287 View* view_in_embedded = embedded->GetRoot();
288 EXPECT_EQ(view->id(), view_in_embedded->id());
289 EXPECT_EQ(nullptr, view_in_embedded->parent());
290 EXPECT_TRUE(view_in_embedded->children().empty());
291 }
292
293 // TODO(beng): write a replacement test for the one that once existed here:
294 // This test validates the following scenario:
295 // - a view originating from one connection
296 // - a view originating from a second connection
297 // + the connection originating the view is destroyed
298 // -> the view should still exist (since the second connection is live) but
299 // should be disconnected from any views.
300 // http://crbug.com/396300
301 //
302 // TODO(beng): The new test should validate the scenario as described above
303 // except that the second connection still has a valid tree.
304
305 // Verifies that bounds changes applied to a view hierarchy in one connection
306 // are reflected to another.
307 TEST_F(ViewManagerTest, SetBounds) {
308 View* view = window_manager()->CreateView();
309 view->SetVisible(true);
310 window_manager()->GetRoot()->AddChild(view);
311 ViewManager* embedded = Embed(window_manager(), view);
312 ASSERT_NE(nullptr, embedded);
313
314 View* view_in_embedded = embedded->GetViewById(view->id());
315 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
316
317 Rect rect;
318 rect.width = rect.height = 100;
319 view->SetBounds(rect);
320 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
321 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
322 }
323
324 // Verifies that bounds changes applied to a view owned by a different
325 // connection are refused.
326 TEST_F(ViewManagerTest, SetBoundsSecurity) {
327 View* view = window_manager()->CreateView();
328 view->SetVisible(true);
329 window_manager()->GetRoot()->AddChild(view);
330 ViewManager* embedded = Embed(window_manager(), view);
331 ASSERT_NE(nullptr, embedded);
332
333 View* view_in_embedded = embedded->GetViewById(view->id());
334 Rect rect;
335 rect.width = 800;
336 rect.height = 600;
337 view->SetBounds(rect);
338 ASSERT_TRUE(WaitForBoundsToChange(view_in_embedded));
339
340 rect.width = 1024;
341 rect.height = 768;
342 view_in_embedded->SetBounds(rect);
343 // Bounds change should have been rejected.
344 EXPECT_EQ(view->bounds(), view_in_embedded->bounds());
345 }
346
347 // Verifies that a view can only be destroyed by the connection that created it.
348 TEST_F(ViewManagerTest, DestroySecurity) {
349 View* view = window_manager()->CreateView();
350 view->SetVisible(true);
351 window_manager()->GetRoot()->AddChild(view);
352 ViewManager* embedded = Embed(window_manager(), view);
353 ASSERT_NE(nullptr, embedded);
354
355 View* view_in_embedded = embedded->GetViewById(view->id());
356
357 ViewTracker tracker2(view_in_embedded);
358 view_in_embedded->Destroy();
359 // View should not have been destroyed.
360 EXPECT_TRUE(tracker2.is_valid());
361
362 ViewTracker tracker1(view);
363 view->Destroy();
364 EXPECT_FALSE(tracker1.is_valid());
365 }
366
367 TEST_F(ViewManagerTest, MultiRoots) {
368 View* view1 = window_manager()->CreateView();
369 view1->SetVisible(true);
370 window_manager()->GetRoot()->AddChild(view1);
371 View* view2 = window_manager()->CreateView();
372 view2->SetVisible(true);
373 window_manager()->GetRoot()->AddChild(view2);
374 ViewManager* embedded1 = Embed(window_manager(), view1);
375 ASSERT_NE(nullptr, embedded1);
376 ViewManager* embedded2 = Embed(window_manager(), view2);
377 ASSERT_NE(nullptr, embedded2);
378 EXPECT_NE(embedded1, embedded2);
379 }
380
381 TEST_F(ViewManagerTest, EmbeddingIdentity) {
382 View* view = window_manager()->CreateView();
383 view->SetVisible(true);
384 window_manager()->GetRoot()->AddChild(view);
385 ViewManager* embedded = Embed(window_manager(), view);
386 ASSERT_NE(nullptr, embedded);
387 EXPECT_EQ(application_impl()->url(), embedded->GetEmbedderURL());
388 }
389
390 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
391 // Debug and re-enable this.
392 TEST_F(ViewManagerTest, DISABLED_Reorder) {
393 View* view1 = window_manager()->CreateView();
394 view1->SetVisible(true);
395 window_manager()->GetRoot()->AddChild(view1);
396
397 ViewManager* embedded = Embed(window_manager(), view1);
398 ASSERT_NE(nullptr, embedded);
399
400 View* view11 = embedded->CreateView();
401 view11->SetVisible(true);
402 embedded->GetRoot()->AddChild(view11);
403 View* view12 = embedded->CreateView();
404 view12->SetVisible(true);
405 embedded->GetRoot()->AddChild(view12);
406
407 View* root_in_embedded = embedded->GetRoot();
408
409 {
410 ASSERT_TRUE(WaitForTreeSizeToMatch(root_in_embedded, 3u));
411 view11->MoveToFront();
412 ASSERT_TRUE(WaitForOrderChange(embedded, root_in_embedded));
413
414 EXPECT_EQ(root_in_embedded->children().front(),
415 embedded->GetViewById(view12->id()));
416 EXPECT_EQ(root_in_embedded->children().back(),
417 embedded->GetViewById(view11->id()));
418 }
419
420 {
421 view11->MoveToBack();
422 ASSERT_TRUE(WaitForOrderChange(embedded,
423 embedded->GetViewById(view11->id())));
424
425 EXPECT_EQ(root_in_embedded->children().front(),
426 embedded->GetViewById(view11->id()));
427 EXPECT_EQ(root_in_embedded->children().back(),
428 embedded->GetViewById(view12->id()));
429 }
430 }
431
432 namespace {
433
434 class VisibilityChangeObserver : public ViewObserver {
435 public:
436 explicit VisibilityChangeObserver(View* view) : view_(view) {
437 view_->AddObserver(this);
438 }
439 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
440
441 private:
442 // Overridden from ViewObserver:
443 void OnViewVisibilityChanged(View* view) override {
444 EXPECT_EQ(view, view_);
445 QuitRunLoop();
446 }
447
448 View* view_;
449
450 MOJO_DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
451 };
452
453 } // namespace
454
455 TEST_F(ViewManagerTest, Visible) {
456 View* view1 = window_manager()->CreateView();
457 view1->SetVisible(true);
458 window_manager()->GetRoot()->AddChild(view1);
459
460 // Embed another app and verify initial state.
461 ViewManager* embedded = Embed(window_manager(), view1);
462 ASSERT_NE(nullptr, embedded);
463 ASSERT_NE(nullptr, embedded->GetRoot());
464 View* embedded_root = embedded->GetRoot();
465 EXPECT_TRUE(embedded_root->visible());
466 EXPECT_TRUE(embedded_root->IsDrawn());
467
468 // Change the visible state from the first connection and verify its mirrored
469 // correctly to the embedded app.
470 {
471 VisibilityChangeObserver observer(embedded_root);
472 view1->SetVisible(false);
473 ASSERT_TRUE(DoRunLoopWithTimeout());
474 }
475
476 EXPECT_FALSE(view1->visible());
477 EXPECT_FALSE(view1->IsDrawn());
478
479 EXPECT_FALSE(embedded_root->visible());
480 EXPECT_FALSE(embedded_root->IsDrawn());
481
482 // Make the node visible again.
483 {
484 VisibilityChangeObserver observer(embedded_root);
485 view1->SetVisible(true);
486 ASSERT_TRUE(DoRunLoopWithTimeout());
487 }
488
489 EXPECT_TRUE(view1->visible());
490 EXPECT_TRUE(view1->IsDrawn());
491
492 EXPECT_TRUE(embedded_root->visible());
493 EXPECT_TRUE(embedded_root->IsDrawn());
494 }
495
496 namespace {
497
498 class DrawnChangeObserver : public ViewObserver {
499 public:
500 explicit DrawnChangeObserver(View* view) : view_(view) {
501 view_->AddObserver(this);
502 }
503 ~DrawnChangeObserver() override { view_->RemoveObserver(this); }
504
505 private:
506 // Overridden from ViewObserver:
507 void OnViewDrawnChanged(View* view) override {
508 EXPECT_EQ(view, view_);
509 QuitRunLoop();
510 }
511
512 View* view_;
513
514 MOJO_DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
515 };
516
517 } // namespace
518
519 TEST_F(ViewManagerTest, Drawn) {
520 View* view1 = window_manager()->CreateView();
521 view1->SetVisible(true);
522 window_manager()->GetRoot()->AddChild(view1);
523
524 // Embed another app and verify initial state.
525 ViewManager* embedded = Embed(window_manager(), view1);
526 ASSERT_NE(nullptr, embedded);
527 ASSERT_NE(nullptr, embedded->GetRoot());
528 View* embedded_root = embedded->GetRoot();
529 EXPECT_TRUE(embedded_root->visible());
530 EXPECT_TRUE(embedded_root->IsDrawn());
531
532 // Change the visibility of the root, this should propagate a drawn state
533 // change to |embedded|.
534 {
535 DrawnChangeObserver observer(embedded_root);
536 window_manager()->GetRoot()->SetVisible(false);
537 ASSERT_TRUE(DoRunLoopWithTimeout());
538 }
539
540 EXPECT_TRUE(view1->visible());
541 EXPECT_FALSE(view1->IsDrawn());
542
543 EXPECT_TRUE(embedded_root->visible());
544 EXPECT_FALSE(embedded_root->IsDrawn());
545 }
546
547 // TODO(beng): tests for view event dispatcher.
548 // - verify that we see events for all views.
549
550 namespace {
551
552 class FocusChangeObserver : public ViewObserver {
553 public:
554 explicit FocusChangeObserver(View* view)
555 : view_(view), last_gained_focus_(nullptr), last_lost_focus_(nullptr) {
556 view_->AddObserver(this);
557 }
558 ~FocusChangeObserver() override { view_->RemoveObserver(this); }
559
560 View* last_gained_focus() { return last_gained_focus_; }
561
562 View* last_lost_focus() { return last_lost_focus_; }
563
564 private:
565 // Overridden from ViewObserver.
566 void OnViewFocusChanged(View* gained_focus, View* lost_focus) override {
567 last_gained_focus_ = gained_focus;
568 last_lost_focus_ = lost_focus;
569 QuitRunLoop();
570 }
571
572 View* view_;
573 View* last_gained_focus_;
574 View* last_lost_focus_;
575
576 MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
577 };
578
579 } // namespace
580
581 TEST_F(ViewManagerTest, Focus) {
582 View* view1 = window_manager()->CreateView();
583 view1->SetVisible(true);
584 window_manager()->GetRoot()->AddChild(view1);
585
586 ViewManager* embedded = Embed(window_manager(), view1);
587 ASSERT_NE(nullptr, embedded);
588 View* view11 = embedded->CreateView();
589 view11->SetVisible(true);
590 embedded->GetRoot()->AddChild(view11);
591
592 // TODO(alhaad): Figure out why switching focus between views from different
593 // connections is causing the tests to crash and add tests for that.
594 {
595 View* embedded_root = embedded->GetRoot();
596 FocusChangeObserver observer(embedded_root);
597 embedded_root->SetFocus();
598 ASSERT_TRUE(DoRunLoopWithTimeout());
599 ASSERT_NE(nullptr, observer.last_gained_focus());
600 EXPECT_EQ(embedded_root->id(), observer.last_gained_focus()->id());
601 }
602 {
603 FocusChangeObserver observer(view11);
604 view11->SetFocus();
605 ASSERT_TRUE(DoRunLoopWithTimeout());
606 ASSERT_NE(nullptr, observer.last_gained_focus());
607 ASSERT_NE(nullptr, observer.last_lost_focus());
608 EXPECT_EQ(view11->id(), observer.last_gained_focus()->id());
609 EXPECT_EQ(embedded->GetRoot()->id(), observer.last_lost_focus()->id());
610 }
611 }
612
613 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/view_manager/view_manager_app.cc ('k') | mojo/services/view_manager/view_manager_service_apptest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698