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

Side by Side Diff: components/mus/ws/window_tree_apptest.cc

Issue 1771393002: Convert mus apptests to shelltests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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 <stddef.h>
6 #include <stdint.h>
7
8 #include "base/bind.h"
9 #include "base/macros.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "components/mus/public/interfaces/window_tree.mojom.h"
14 #include "components/mus/public/interfaces/window_tree_host.mojom.h"
15 #include "components/mus/ws/ids.h"
16 #include "components/mus/ws/test_change_tracker.h"
17 #include "mojo/converters/geometry/geometry_type_converters.h"
18 #include "mojo/public/cpp/bindings/associated_binding.h"
19 #include "mojo/shell/public/cpp/application_test_base.h"
20
21 using mojo::Array;
22 using mojo::Callback;
23 using mojo::Connection;
24 using mojo::InterfaceRequest;
25 using mojo::RectPtr;
26 using mojo::ShellClient;
27 using mojo::String;
28 using mus::mojom::ErrorCode;
29 using mus::mojom::EventPtr;
30 using mus::mojom::ViewportMetricsPtr;
31 using mus::mojom::WindowDataPtr;
32 using mus::mojom::WindowTree;
33 using mus::mojom::WindowTreeClient;
34
35 namespace mus {
36 namespace ws {
37 namespace test {
38
39 namespace {
40
41 // Creates an id used for transport from the specified parameters.
42 Id BuildWindowId(ConnectionSpecificId connection_id,
43 ConnectionSpecificId window_id) {
44 return (connection_id << 16) | window_id;
45 }
46
47 // Callback function from WindowTree functions.
48 // ----------------------------------
49
50 void WindowTreeResultCallback(base::RunLoop* run_loop,
51 std::vector<TestWindow>* windows,
52 Array<WindowDataPtr> results) {
53 WindowDatasToTestWindows(results, windows);
54 run_loop->Quit();
55 }
56
57 void EmbedCallbackImpl(base::RunLoop* run_loop,
58 bool* result_cache,
59 bool result,
60 ConnectionSpecificId connection_id) {
61 *result_cache = result;
62 run_loop->Quit();
63 }
64
65 // -----------------------------------------------------------------------------
66
67 bool EmbedUrl(mojo::Connector* connector,
68 WindowTree* tree,
69 const String& url,
70 Id root_id) {
71 bool result = false;
72 base::RunLoop run_loop;
73 {
74 mojom::WindowTreeClientPtr client;
75 connector->ConnectToInterface(url.get(), &client);
76 tree->Embed(root_id, std::move(client),
77 mojom::WindowTree::kAccessPolicyDefault,
78 base::Bind(&EmbedCallbackImpl, &run_loop, &result));
79 }
80 run_loop.Run();
81 return result;
82 }
83
84 bool Embed(WindowTree* tree, Id root_id, mojom::WindowTreeClientPtr client) {
85 bool result = false;
86 base::RunLoop run_loop;
87 {
88 tree->Embed(root_id, std::move(client),
89 mojom::WindowTree::kAccessPolicyDefault,
90 base::Bind(&EmbedCallbackImpl, &run_loop, &result));
91 }
92 run_loop.Run();
93 return result;
94 }
95
96 void GetWindowTree(WindowTree* tree,
97 Id window_id,
98 std::vector<TestWindow>* windows) {
99 base::RunLoop run_loop;
100 tree->GetWindowTree(
101 window_id, base::Bind(&WindowTreeResultCallback, &run_loop, windows));
102 run_loop.Run();
103 }
104
105 // Utility functions -----------------------------------------------------------
106
107 const Id kNullParentId = 0;
108 std::string IdToString(Id id) {
109 return (id == kNullParentId) ? "null" : base::StringPrintf(
110 "%d,%d", HiWord(id), LoWord(id));
111 }
112
113 std::string WindowParentToString(Id window, Id parent) {
114 return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(),
115 IdToString(parent).c_str());
116 }
117
118 // -----------------------------------------------------------------------------
119
120 // A WindowTreeClient implementation that logs all changes to a tracker.
121 class TestWindowTreeClientImpl : public mojom::WindowTreeClient,
122 public TestChangeTracker::Delegate,
123 public mojom::WindowManager {
124 public:
125 TestWindowTreeClientImpl()
126 : binding_(this),
127 connection_id_(0),
128 root_window_id_(0),
129 // Start with a random large number so tests can use lower ids if they
130 // want.
131 next_change_id_(10000),
132 waiting_change_id_(0),
133 on_change_completed_result_(false),
134 track_root_bounds_changes_(false) {
135 tracker_.set_delegate(this);
136 }
137
138 void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
139 binding_.Bind(std::move(request));
140 }
141
142 mojom::WindowTree* tree() { return tree_.get(); }
143 TestChangeTracker* tracker() { return &tracker_; }
144 Id root_window_id() const { return root_window_id_; }
145
146 // Sets whether changes to the bounds of the root should be tracked. Normally
147 // they are ignored (as during startup we often times get random size
148 // changes).
149 void set_track_root_bounds_changes(bool value) {
150 track_root_bounds_changes_ = value;
151 }
152
153 // Runs a nested MessageLoop until |count| changes (calls to
154 // WindowTreeClient functions) have been received.
155 void WaitForChangeCount(size_t count) {
156 if (tracker_.changes()->size() >= count)
157 return;
158
159 ASSERT_TRUE(wait_state_.get() == nullptr);
160 wait_state_.reset(new WaitState);
161 wait_state_->change_count = count;
162 wait_state_->run_loop.Run();
163 wait_state_.reset();
164 }
165
166 uint32_t GetAndAdvanceChangeId() { return next_change_id_++; }
167
168 // Runs a nested MessageLoop until OnEmbed() has been encountered.
169 void WaitForOnEmbed() {
170 if (tree_)
171 return;
172 embed_run_loop_.reset(new base::RunLoop);
173 embed_run_loop_->Run();
174 embed_run_loop_.reset();
175 }
176
177 bool WaitForIncomingMethodCall() {
178 return binding_.WaitForIncomingMethodCall();
179 }
180
181 bool WaitForChangeCompleted(uint32_t id) {
182 waiting_change_id_ = id;
183 change_completed_run_loop_.reset(new base::RunLoop);
184 change_completed_run_loop_->Run();
185 return on_change_completed_result_;
186 }
187
188 bool DeleteWindow(Id id) {
189 const uint32_t change_id = GetAndAdvanceChangeId();
190 tree()->DeleteWindow(change_id, id);
191 return WaitForChangeCompleted(change_id);
192 }
193
194 bool AddWindow(Id parent, Id child) {
195 const uint32_t change_id = GetAndAdvanceChangeId();
196 tree()->AddWindow(change_id, parent, child);
197 return WaitForChangeCompleted(change_id);
198 }
199
200 bool RemoveWindowFromParent(Id window_id) {
201 const uint32_t change_id = GetAndAdvanceChangeId();
202 tree()->RemoveWindowFromParent(change_id, window_id);
203 return WaitForChangeCompleted(change_id);
204 }
205
206 bool ReorderWindow(Id window_id,
207 Id relative_window_id,
208 mojom::OrderDirection direction) {
209 const uint32_t change_id = GetAndAdvanceChangeId();
210 tree()->ReorderWindow(change_id, window_id, relative_window_id, direction);
211 return WaitForChangeCompleted(change_id);
212 }
213
214 // Waits for all messages to be received by |ws|. This is done by attempting
215 // to create a bogus window. When we get the response we know all messages
216 // have been processed.
217 bool WaitForAllMessages() {
218 return NewWindowWithCompleteId(WindowIdToTransportId(InvalidWindowId())) ==
219 0;
220 }
221
222 Id NewWindow(ConnectionSpecificId window_id) {
223 return NewWindowWithCompleteId(BuildWindowId(connection_id_, window_id));
224 }
225
226 // Generally you want NewWindow(), but use this if you need to test given
227 // a complete window id (NewWindow() ors with the connection id).
228 Id NewWindowWithCompleteId(Id id) {
229 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties;
230 const uint32_t change_id = GetAndAdvanceChangeId();
231 tree()->NewWindow(change_id, id, std::move(properties));
232 return WaitForChangeCompleted(change_id) ? id : 0;
233 }
234
235 bool SetWindowProperty(Id window_id,
236 const std::string& name,
237 const std::vector<uint8_t>* data) {
238 Array<uint8_t> mojo_data(nullptr);
239 if (data)
240 mojo_data = Array<uint8_t>::From(*data);
241 const uint32_t change_id = GetAndAdvanceChangeId();
242 tree()->SetWindowProperty(change_id, window_id, name, std::move(mojo_data));
243 return WaitForChangeCompleted(change_id);
244 }
245
246 bool SetPredefinedCursor(Id window_id, mojom::Cursor cursor) {
247 const uint32_t change_id = GetAndAdvanceChangeId();
248 tree()->SetPredefinedCursor(change_id, window_id, cursor);
249 return WaitForChangeCompleted(change_id);
250 }
251
252 bool SetWindowVisibility(Id window_id, bool visible) {
253 const uint32_t change_id = GetAndAdvanceChangeId();
254 tree()->SetWindowVisibility(change_id, window_id, visible);
255 return WaitForChangeCompleted(change_id);
256 }
257
258 private:
259 // Used when running a nested MessageLoop.
260 struct WaitState {
261 WaitState() : change_count(0) {}
262
263 // Number of changes waiting for.
264 size_t change_count;
265 base::RunLoop run_loop;
266 };
267
268 // TestChangeTracker::Delegate:
269 void OnChangeAdded() override {
270 if (wait_state_.get() &&
271 tracker_.changes()->size() >= wait_state_->change_count) {
272 wait_state_->run_loop.Quit();
273 }
274 }
275
276 // WindowTreeClient:
277 void OnEmbed(ConnectionSpecificId connection_id,
278 WindowDataPtr root,
279 mojom::WindowTreePtr tree,
280 Id focused_window_id,
281 uint32_t access_policy) override {
282 // TODO(sky): add coverage of |focused_window_id|.
283 ASSERT_TRUE(root);
284 root_window_id_ = root->window_id;
285 tree_ = std::move(tree);
286 connection_id_ = connection_id;
287 tracker()->OnEmbed(connection_id, std::move(root));
288 if (embed_run_loop_)
289 embed_run_loop_->Quit();
290 }
291 void OnEmbeddedAppDisconnected(Id window_id) override {
292 tracker()->OnEmbeddedAppDisconnected(window_id);
293 }
294 void OnUnembed(Id window_id) override { tracker()->OnUnembed(window_id); }
295 void OnLostCapture(Id window_id) override {
296 tracker()->OnLostCapture(window_id);
297 }
298 void OnTopLevelCreated(uint32_t change_id,
299 mojom::WindowDataPtr data) override {
300 tracker()->OnTopLevelCreated(change_id, std::move(data));
301 }
302 void OnWindowBoundsChanged(Id window_id,
303 RectPtr old_bounds,
304 RectPtr new_bounds) override {
305 // The bounds of the root may change during startup on Android at random
306 // times. As this doesn't matter, and shouldn't impact test exepctations,
307 // it is ignored.
308 if (window_id == root_window_id_ && !track_root_bounds_changes_)
309 return;
310 tracker()->OnWindowBoundsChanged(window_id, std::move(old_bounds),
311 std::move(new_bounds));
312 }
313 void OnClientAreaChanged(
314 uint32_t window_id,
315 mojo::InsetsPtr new_client_area,
316 mojo::Array<mojo::RectPtr> new_additional_client_areas) override {}
317 void OnTransientWindowAdded(uint32_t window_id,
318 uint32_t transient_window_id) override {
319 tracker()->OnTransientWindowAdded(window_id, transient_window_id);
320 }
321 void OnTransientWindowRemoved(uint32_t window_id,
322 uint32_t transient_window_id) override {
323 tracker()->OnTransientWindowRemoved(window_id, transient_window_id);
324 }
325 void OnWindowViewportMetricsChanged(mojo::Array<uint32_t> window_ids,
326 ViewportMetricsPtr old_metrics,
327 ViewportMetricsPtr new_metrics) override {
328 // Don't track the metrics as they are available at an indeterministic time
329 // on Android.
330 }
331 void OnWindowHierarchyChanged(Id window,
332 Id new_parent,
333 Id old_parent,
334 Array<WindowDataPtr> windows) override {
335 tracker()->OnWindowHierarchyChanged(window, new_parent, old_parent,
336 std::move(windows));
337 }
338 void OnWindowReordered(Id window_id,
339 Id relative_window_id,
340 mojom::OrderDirection direction) override {
341 tracker()->OnWindowReordered(window_id, relative_window_id, direction);
342 }
343 void OnWindowDeleted(Id window) override {
344 tracker()->OnWindowDeleted(window);
345 }
346 void OnWindowVisibilityChanged(uint32_t window, bool visible) override {
347 tracker()->OnWindowVisibilityChanged(window, visible);
348 }
349 void OnWindowDrawnStateChanged(uint32_t window, bool drawn) override {
350 tracker()->OnWindowDrawnStateChanged(window, drawn);
351 }
352 void OnWindowInputEvent(uint32_t event_id,
353 Id window_id,
354 EventPtr event) override {
355 // Ack input events to clear the state on the server. These can be received
356 // during test startup. X11Window::DispatchEvent sends a synthetic move
357 // event to notify of entry.
358 tree()->OnWindowInputEventAck(event_id);
359 // Don't log input events as none of the tests care about them and they
360 // may come in at random points.
361 }
362 void OnWindowSharedPropertyChanged(uint32_t window,
363 const String& name,
364 Array<uint8_t> new_data) override {
365 tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data));
366 }
367 // TODO(sky): add testing coverage.
368 void OnWindowFocused(uint32_t focused_window_id) override {}
369 void OnWindowPredefinedCursorChanged(uint32_t window_id,
370 mojom::Cursor cursor_id) override {
371 tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
372 }
373 void OnChangeCompleted(uint32_t change_id, bool success) override {
374 if (waiting_change_id_ == change_id && change_completed_run_loop_) {
375 on_change_completed_result_ = success;
376 change_completed_run_loop_->Quit();
377 }
378 }
379 void RequestClose(uint32_t window_id) override {}
380 void GetWindowManager(mojo::AssociatedInterfaceRequest<mojom::WindowManager>
381 internal) override {
382 window_manager_binding_.reset(
383 new mojo::AssociatedBinding<mojom::WindowManager>(this,
384 std::move(internal)));
385 tree_->GetWindowManagerClient(
386 GetProxy(&window_manager_client_, tree_.associated_group()));
387 }
388
389 // mojom::WindowManager:
390 void WmSetBounds(uint32_t change_id,
391 uint32_t window_id,
392 mojo::RectPtr bounds) override {
393 window_manager_client_->WmResponse(change_id, false);
394 }
395 void WmSetProperty(uint32_t change_id,
396 uint32_t window_id,
397 const mojo::String& name,
398 mojo::Array<uint8_t> value) override {
399 window_manager_client_->WmResponse(change_id, false);
400 }
401 void WmCreateTopLevelWindow(
402 uint32_t change_id,
403 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) override {
404 NOTIMPLEMENTED();
405 }
406 void OnAccelerator(uint32_t id, mojom::EventPtr event) override {
407 NOTIMPLEMENTED();
408 }
409
410 TestChangeTracker tracker_;
411
412 mojom::WindowTreePtr tree_;
413
414 // If non-null we're waiting for OnEmbed() using this RunLoop.
415 scoped_ptr<base::RunLoop> embed_run_loop_;
416
417 // If non-null we're waiting for a certain number of change notifications to
418 // be encountered.
419 scoped_ptr<WaitState> wait_state_;
420
421 mojo::Binding<WindowTreeClient> binding_;
422 Id connection_id_;
423 Id root_window_id_;
424 uint32_t next_change_id_;
425 uint32_t waiting_change_id_;
426 bool on_change_completed_result_;
427 bool track_root_bounds_changes_;
428 scoped_ptr<base::RunLoop> change_completed_run_loop_;
429
430 scoped_ptr<mojo::AssociatedBinding<mojom::WindowManager>>
431 window_manager_binding_;
432 mojom::WindowManagerClientAssociatedPtr window_manager_client_;
433
434 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClientImpl);
435 };
436
437 // -----------------------------------------------------------------------------
438
439 // InterfaceFactory for vending TestWindowTreeClientImpls.
440 class WindowTreeClientFactory
441 : public mojo::InterfaceFactory<WindowTreeClient> {
442 public:
443 WindowTreeClientFactory() {}
444 ~WindowTreeClientFactory() override {}
445
446 // Runs a nested MessageLoop until a new instance has been created.
447 scoped_ptr<TestWindowTreeClientImpl> WaitForInstance() {
448 if (!client_impl_.get()) {
449 DCHECK(!run_loop_);
450 run_loop_.reset(new base::RunLoop);
451 run_loop_->Run();
452 run_loop_.reset();
453 }
454 return std::move(client_impl_);
455 }
456
457 private:
458 // InterfaceFactory<WindowTreeClient>:
459 void Create(Connection* connection,
460 InterfaceRequest<WindowTreeClient> request) override {
461 client_impl_.reset(new TestWindowTreeClientImpl());
462 client_impl_->Bind(std::move(request));
463 if (run_loop_.get())
464 run_loop_->Quit();
465 }
466
467 scoped_ptr<TestWindowTreeClientImpl> client_impl_;
468 scoped_ptr<base::RunLoop> run_loop_;
469
470 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory);
471 };
472
473 } // namespace
474
475 class WindowTreeAppTest : public mojo::test::ApplicationTestBase,
476 public mojo::ShellClient {
477 public:
478 WindowTreeAppTest()
479 : connection_id_1_(0), connection_id_2_(0), root_window_id_(0) {}
480 ~WindowTreeAppTest() override {}
481
482 protected:
483 // Returns the changes from the various connections.
484 std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); }
485 std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); }
486 std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); }
487
488 // Various connections. |wt1()|, being the first connection, has special
489 // permissions (it's treated as the window manager).
490 WindowTree* wt1() { return wt_client1_->tree(); }
491 WindowTree* wt2() { return wt_client2_->tree(); }
492 WindowTree* wt3() { return wt_client3_->tree(); }
493
494 TestWindowTreeClientImpl* wt_client1() { return wt_client1_.get(); }
495 TestWindowTreeClientImpl* wt_client2() { return wt_client2_.get(); }
496 TestWindowTreeClientImpl* wt_client3() { return wt_client3_.get(); }
497
498 Id root_window_id() const { return root_window_id_; }
499
500 int connection_id_1() const { return connection_id_1_; }
501 int connection_id_2() const { return connection_id_2_; }
502
503 void EstablishSecondConnectionWithRoot(Id root_id) {
504 ASSERT_TRUE(wt_client2_.get() == nullptr);
505 wt_client2_ =
506 EstablishConnectionViaEmbed(wt1(), root_id, &connection_id_2_);
507 ASSERT_GT(connection_id_2_, 0);
508 ASSERT_TRUE(wt_client2_.get() != nullptr);
509 }
510
511 void EstablishSecondConnection(bool create_initial_window) {
512 Id window_1_1 = 0;
513 if (create_initial_window) {
514 window_1_1 = wt_client1()->NewWindow(1);
515 ASSERT_TRUE(window_1_1);
516 }
517 ASSERT_NO_FATAL_FAILURE(
518 EstablishSecondConnectionWithRoot(BuildWindowId(connection_id_1(), 1)));
519
520 if (create_initial_window) {
521 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
522 ChangeWindowDescription(*changes2()));
523 }
524 }
525
526 void EstablishThirdConnection(WindowTree* owner, Id root_id) {
527 ASSERT_TRUE(wt_client3_.get() == nullptr);
528 wt_client3_ = EstablishConnectionViaEmbed(owner, root_id, nullptr);
529 ASSERT_TRUE(wt_client3_.get() != nullptr);
530 }
531
532 scoped_ptr<TestWindowTreeClientImpl> WaitForWindowTreeClient() {
533 return client_factory_->WaitForInstance();
534 }
535
536 // Establishes a new connection by way of Embed() on the specified
537 // WindowTree.
538 scoped_ptr<TestWindowTreeClientImpl> EstablishConnectionViaEmbed(
539 WindowTree* owner,
540 Id root_id,
541 int* connection_id) {
542 return EstablishConnectionViaEmbedWithPolicyBitmask(
543 owner, root_id, mojom::WindowTree::kAccessPolicyDefault, connection_id);
544 }
545
546 scoped_ptr<TestWindowTreeClientImpl>
547 EstablishConnectionViaEmbedWithPolicyBitmask(WindowTree* owner,
548 Id root_id,
549 uint32_t policy_bitmask,
550 int* connection_id) {
551 if (!EmbedUrl(connector(), owner, test_name(), root_id)) {
552 ADD_FAILURE() << "Embed() failed";
553 return nullptr;
554 }
555 scoped_ptr<TestWindowTreeClientImpl> client =
556 client_factory_->WaitForInstance();
557 if (!client.get()) {
558 ADD_FAILURE() << "WaitForInstance failed";
559 return nullptr;
560 }
561 client->WaitForOnEmbed();
562
563 EXPECT_EQ("OnEmbed",
564 SingleChangeToDescription(*client->tracker()->changes()));
565 if (connection_id)
566 *connection_id = (*client->tracker()->changes())[0].connection_id;
567 return client;
568 }
569
570 // ApplicationTestBase:
571 mojo::ShellClient* GetShellClient() override { return this; }
572 void SetUp() override {
573 ApplicationTestBase::SetUp();
574 client_factory_.reset(new WindowTreeClientFactory());
575
576 mojom::WindowTreeHostFactoryPtr factory;
577 connector()->ConnectToInterface("mojo:mus", &factory);
578
579 mojom::WindowTreeClientPtr tree_client_ptr;
580 wt_client1_.reset(new TestWindowTreeClientImpl());
581 wt_client1_->Bind(GetProxy(&tree_client_ptr));
582
583 factory->CreateWindowTreeHost(GetProxy(&host_),
584 std::move(tree_client_ptr));
585
586 // Next we should get an embed call on the "window manager" client.
587 wt_client1_->WaitForIncomingMethodCall();
588
589 ASSERT_EQ(1u, changes1()->size());
590 EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type);
591 // All these tests assume 1 for the client id. The only real assertion here
592 // is the client id is not zero, but adding this as rest of code here
593 // assumes 1.
594 ASSERT_GT((*changes1())[0].connection_id, 0);
595 connection_id_1_ = (*changes1())[0].connection_id;
596 ASSERT_FALSE((*changes1())[0].windows.empty());
597 root_window_id_ = (*changes1())[0].windows[0].window_id;
598 ASSERT_EQ(root_window_id_, wt_client1_->root_window_id());
599 changes1()->clear();
600 }
601
602 // mojo::ShellClient implementation.
603 bool AcceptConnection(Connection* connection) override {
604 connection->AddInterface(client_factory_.get());
605 return true;
606 }
607
608 scoped_ptr<TestWindowTreeClientImpl> wt_client1_;
609 scoped_ptr<TestWindowTreeClientImpl> wt_client2_;
610 scoped_ptr<TestWindowTreeClientImpl> wt_client3_;
611
612 mojom::WindowTreeHostPtr host_;
613
614 private:
615 scoped_ptr<WindowTreeClientFactory> client_factory_;
616 int connection_id_1_;
617 int connection_id_2_;
618 Id root_window_id_;
619
620 DISALLOW_COPY_AND_ASSIGN(WindowTreeAppTest);
621 };
622
623 // Verifies two clients/connections get different ids.
624 TEST_F(WindowTreeAppTest, TwoClientsGetDifferentConnectionIds) {
625 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
626
627 ASSERT_EQ(1u, changes2()->size());
628 ASSERT_NE(connection_id_1(), connection_id_2());
629 }
630
631 // Verifies when Embed() is invoked any child windows are removed.
632 TEST_F(WindowTreeAppTest, WindowsRemovedWhenEmbedding) {
633 // Two windows 1 and 2. 2 is parented to 1.
634 Id window_1_1 = wt_client1()->NewWindow(1);
635 ASSERT_TRUE(window_1_1);
636 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
637
638 Id window_1_2 = wt_client1()->NewWindow(2);
639 ASSERT_TRUE(window_1_2);
640 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
641
642 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
643 ASSERT_EQ(1u, changes2()->size());
644 ASSERT_EQ(1u, (*changes2())[0].windows.size());
645 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
646 ChangeWindowDescription(*changes2()));
647
648 // Embed() removed window 2.
649 {
650 std::vector<TestWindow> windows;
651 GetWindowTree(wt1(), window_1_2, &windows);
652 EXPECT_EQ(WindowParentToString(window_1_2, kNullParentId),
653 SingleWindowDescription(windows));
654 }
655
656 // ws2 should not see window 2.
657 {
658 std::vector<TestWindow> windows;
659 GetWindowTree(wt2(), window_1_1, &windows);
660 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
661 SingleWindowDescription(windows));
662 }
663 {
664 std::vector<TestWindow> windows;
665 GetWindowTree(wt2(), window_1_2, &windows);
666 EXPECT_TRUE(windows.empty());
667 }
668
669 // Windows 3 and 4 in connection 2.
670 Id window_2_3 = wt_client2()->NewWindow(3);
671 Id window_2_4 = wt_client2()->NewWindow(4);
672 ASSERT_TRUE(window_2_3);
673 ASSERT_TRUE(window_2_4);
674 ASSERT_TRUE(wt_client2()->AddWindow(window_2_3, window_2_4));
675
676 // Connection 3 rooted at 2.
677 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_3));
678
679 // Window 4 should no longer have a parent.
680 {
681 std::vector<TestWindow> windows;
682 GetWindowTree(wt2(), window_2_3, &windows);
683 EXPECT_EQ(WindowParentToString(window_2_3, kNullParentId),
684 SingleWindowDescription(windows));
685
686 windows.clear();
687 GetWindowTree(wt2(), window_2_4, &windows);
688 EXPECT_EQ(WindowParentToString(window_2_4, kNullParentId),
689 SingleWindowDescription(windows));
690 }
691
692 // And window 4 should not be visible to connection 3.
693 {
694 std::vector<TestWindow> windows;
695 GetWindowTree(wt3(), window_2_3, &windows);
696 EXPECT_EQ("no windows", SingleWindowDescription(windows));
697 }
698 }
699
700 // Verifies once Embed() has been invoked the parent connection can't see any
701 // children.
702 TEST_F(WindowTreeAppTest, CantAccessChildrenOfEmbeddedWindow) {
703 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
704
705 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
706 Id window_2_2 = wt_client2()->NewWindow(2);
707 ASSERT_TRUE(window_2_2);
708 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
709
710 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_2));
711
712 Id window_3_3 = wt_client3()->NewWindow(3);
713 ASSERT_TRUE(window_3_3);
714 ASSERT_TRUE(
715 wt_client3()->AddWindow(wt_client3()->root_window_id(), window_3_3));
716
717 // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a
718 // different connection.
719 {
720 std::vector<TestWindow> windows;
721 GetWindowTree(wt2(), window_2_2, &windows);
722 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
723 SingleWindowDescription(windows));
724 }
725
726 // Connection 2 shouldn't be able to get window 3 at all.
727 {
728 std::vector<TestWindow> windows;
729 GetWindowTree(wt2(), window_3_3, &windows);
730 EXPECT_TRUE(windows.empty());
731 }
732
733 // Connection 1 should be able to see it all (its the root).
734 {
735 std::vector<TestWindow> windows;
736 GetWindowTree(wt1(), window_1_1, &windows);
737 ASSERT_EQ(3u, windows.size());
738 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
739 windows[0].ToString());
740 // NOTE: we expect a match of WindowParentToString(window_2_2, window_1_1),
741 // but the ids are in the id space of client2, which is not the same as
742 // the id space of wt1().
743 EXPECT_EQ("window=2,1 parent=1,1", windows[1].ToString());
744 // Same thing here, we really want to test for
745 // WindowParentToString(window_3_3, window_2_2).
746 EXPECT_EQ("window=3,1 parent=2,1", windows[2].ToString());
747 }
748 }
749
750 // Verifies once Embed() has been invoked the parent can't mutate the children.
751 TEST_F(WindowTreeAppTest, CantModifyChildrenOfEmbeddedWindow) {
752 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
753
754 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
755 Id window_2_1 = wt_client2()->NewWindow(1);
756 ASSERT_TRUE(window_2_1);
757 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
758
759 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_1));
760
761 Id window_2_2 = wt_client2()->NewWindow(2);
762 ASSERT_TRUE(window_2_2);
763 // Connection 2 shouldn't be able to add anything to the window anymore.
764 ASSERT_FALSE(wt_client2()->AddWindow(window_2_1, window_2_2));
765
766 // Create window 3 in connection 3 and add it to window 3.
767 Id window_3_1 = wt_client3()->NewWindow(1);
768 ASSERT_TRUE(window_3_1);
769 ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_1));
770
771 // Connection 2 shouldn't be able to remove window 3.
772 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_3_1));
773 }
774
775 // Verifies client gets a valid id.
776 TEST_F(WindowTreeAppTest, NewWindow) {
777 Id window_1_1 = wt_client1()->NewWindow(1);
778 ASSERT_TRUE(window_1_1);
779 EXPECT_TRUE(changes1()->empty());
780
781 // Can't create a window with the same id.
782 ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(window_1_1));
783 EXPECT_TRUE(changes1()->empty());
784
785 // Can't create a window with a bogus connection id.
786 ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(
787 BuildWindowId(connection_id_1() + 1, 1)));
788 EXPECT_TRUE(changes1()->empty());
789 }
790
791 // Verifies AddWindow fails when window is already in position.
792 TEST_F(WindowTreeAppTest, AddWindowWithNoChange) {
793 // Create the embed point now so that the ids line up.
794 ASSERT_TRUE(wt_client1()->NewWindow(1));
795 Id window_1_2 = wt_client1()->NewWindow(2);
796 Id window_1_3 = wt_client1()->NewWindow(3);
797 ASSERT_TRUE(window_1_2);
798 ASSERT_TRUE(window_1_3);
799
800 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
801
802 // Make 3 a child of 2.
803 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3));
804
805 // Try again, this should fail.
806 EXPECT_FALSE(wt_client1()->AddWindow(window_1_2, window_1_3));
807 }
808
809 // Verifies AddWindow fails when window is already in position.
810 TEST_F(WindowTreeAppTest, AddAncestorFails) {
811 // Create the embed point now so that the ids line up.
812 ASSERT_TRUE(wt_client1()->NewWindow(1));
813 Id window_1_2 = wt_client1()->NewWindow(2);
814 Id window_1_3 = wt_client1()->NewWindow(3);
815 ASSERT_TRUE(window_1_2);
816 ASSERT_TRUE(window_1_3);
817
818 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
819
820 // Make 3 a child of 2.
821 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3));
822
823 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
824 EXPECT_FALSE(wt_client1()->AddWindow(window_1_3, window_1_2));
825 }
826
827 // Verifies adding to root sends right notifications.
828 TEST_F(WindowTreeAppTest, AddToRoot) {
829 // Create the embed point now so that the ids line up.
830 Id window_1_1 = wt_client1()->NewWindow(1);
831 ASSERT_TRUE(window_1_1);
832 Id window_1_21 = wt_client1()->NewWindow(21);
833 Id window_1_3 = wt_client1()->NewWindow(3);
834 ASSERT_TRUE(window_1_21);
835 ASSERT_TRUE(window_1_3);
836
837 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
838 changes2()->clear();
839
840 // Make 3 a child of 21.
841 ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_3));
842
843 // Make 21 a child of 1.
844 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_21));
845
846 // Connection 2 should not be told anything (because the window is from a
847 // different connection). Create a window to ensure we got a response from
848 // the server.
849 ASSERT_TRUE(wt_client2()->NewWindow(100));
850 EXPECT_TRUE(changes2()->empty());
851 }
852
853 // Verifies HierarchyChanged is correctly sent for various adds/removes.
854 TEST_F(WindowTreeAppTest, WindowHierarchyChangedWindows) {
855 // Create the embed point now so that the ids line up.
856 Id window_1_1 = wt_client1()->NewWindow(1);
857 // 1,2->1,11.
858 Id window_1_2 = wt_client1()->NewWindow(2);
859 ASSERT_TRUE(window_1_2);
860 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
861 Id window_1_11 = wt_client1()->NewWindow(11);
862 ASSERT_TRUE(window_1_11);
863 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_11, true));
864 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_11));
865
866 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
867 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
868
869 ASSERT_TRUE(wt_client2()->WaitForAllMessages());
870 changes2()->clear();
871
872 // 1,1->1,2->1,11
873 {
874 // Client 2 should not get anything (1,2 is from another connection).
875 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
876 ASSERT_TRUE(wt_client2()->WaitForAllMessages());
877 EXPECT_TRUE(changes2()->empty());
878 }
879
880 // 0,1->1,1->1,2->1,11.
881 {
882 // Client 2 is now connected to the root, so it should have gotten a drawn
883 // notification.
884 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
885 wt_client2_->WaitForChangeCount(1u);
886 EXPECT_EQ(
887 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
888 SingleChangeToDescription(*changes2()));
889 }
890
891 // 1,1->1,2->1,11.
892 {
893 // Client 2 is no longer connected to the root, should get drawn state
894 // changed.
895 changes2()->clear();
896 ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
897 wt_client2_->WaitForChangeCount(1);
898 EXPECT_EQ(
899 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=false",
900 SingleChangeToDescription(*changes2()));
901 }
902
903 // 1,1->1,2->1,11->1,111.
904 Id window_1_111 = wt_client1()->NewWindow(111);
905 ASSERT_TRUE(window_1_111);
906 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_111, true));
907 {
908 changes2()->clear();
909 ASSERT_TRUE(wt_client1()->AddWindow(window_1_11, window_1_111));
910 ASSERT_TRUE(wt_client2()->WaitForAllMessages());
911 EXPECT_TRUE(changes2()->empty());
912 }
913
914 // 0,1->1,1->1,2->1,11->1,111
915 {
916 changes2()->clear();
917 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
918 wt_client2_->WaitForChangeCount(1);
919 EXPECT_EQ(
920 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
921 SingleChangeToDescription(*changes2()));
922 }
923 }
924
925 TEST_F(WindowTreeAppTest, WindowHierarchyChangedAddingKnownToUnknown) {
926 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
927 // parent).
928 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
929 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
930
931 Id window_2_11 = wt_client2()->NewWindow(11);
932 Id window_2_2 = wt_client2()->NewWindow(2);
933 Id window_2_21 = wt_client2()->NewWindow(21);
934 ASSERT_TRUE(window_2_11);
935 ASSERT_TRUE(window_2_2);
936 ASSERT_TRUE(window_2_21);
937
938 // Set up the hierarchy.
939 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
940 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_11));
941 ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_21));
942
943 // Remove 11, should result in a hierarchy change for the root.
944 {
945 changes1()->clear();
946 ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
947
948 wt_client1_->WaitForChangeCount(1);
949 // 2,1 should be IdToString(window_2_11), but window_2_11 is in the id
950 // space of client2, not client1.
951 EXPECT_EQ("HierarchyChanged window=2,1 new_parent=null old_parent=" +
952 IdToString(window_1_1),
953 SingleChangeToDescription(*changes1()));
954 }
955
956 // Add 2 to 1.
957 {
958 changes1()->clear();
959 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
960 wt_client1_->WaitForChangeCount(1);
961 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
962 " new_parent=" + IdToString(window_1_1) + " old_parent=null",
963 SingleChangeToDescription(*changes1()));
964 // "window=2,3 parent=2,2]" should be,
965 // WindowParentToString(window_2_21, window_2_2), but isn't because of
966 // differing id spaces.
967 EXPECT_EQ("[" + WindowParentToString(window_2_2, window_1_1) +
968 "],[window=2,3 parent=2,2]",
969 ChangeWindowDescription(*changes1()));
970 }
971 }
972
973 TEST_F(WindowTreeAppTest, ReorderWindow) {
974 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
975
976 Id window_2_1 = wt_client2()->NewWindow(1);
977 Id window_2_2 = wt_client2()->NewWindow(2);
978 Id window_2_3 = wt_client2()->NewWindow(3);
979 Id window_1_4 = wt_client1()->NewWindow(4); // Peer to 1,1
980 Id window_1_5 = wt_client1()->NewWindow(5); // Peer to 1,1
981 Id window_2_6 = wt_client2()->NewWindow(6); // Child of 1,2.
982 Id window_2_7 = wt_client2()->NewWindow(7); // Unparented.
983 Id window_2_8 = wt_client2()->NewWindow(8); // Unparented.
984 ASSERT_TRUE(window_2_1);
985 ASSERT_TRUE(window_2_2);
986 ASSERT_TRUE(window_2_3);
987 ASSERT_TRUE(window_1_4);
988 ASSERT_TRUE(window_1_5);
989 ASSERT_TRUE(window_2_6);
990 ASSERT_TRUE(window_2_7);
991 ASSERT_TRUE(window_2_8);
992
993 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
994 ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_6));
995 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_3));
996 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_4));
997 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_5));
998 ASSERT_TRUE(
999 wt_client2()->AddWindow(BuildWindowId(connection_id_1(), 1), window_2_1));
1000
1001 {
1002 changes1()->clear();
1003 ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
1004 mojom::OrderDirection::ABOVE));
1005
1006 wt_client1_->WaitForChangeCount(1);
1007 EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
1008 IdToString(window_2_3) + " direction=above",
1009 SingleChangeToDescription(*changes1()));
1010 }
1011
1012 {
1013 changes1()->clear();
1014 ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
1015 mojom::OrderDirection::BELOW));
1016
1017 wt_client1_->WaitForChangeCount(1);
1018 EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
1019 IdToString(window_2_3) + " direction=below",
1020 SingleChangeToDescription(*changes1()));
1021 }
1022
1023 // view2 is already below view3.
1024 EXPECT_FALSE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
1025 mojom::OrderDirection::BELOW));
1026
1027 // view4 & 5 are unknown to connection2_.
1028 EXPECT_FALSE(wt_client2()->ReorderWindow(window_1_4, window_1_5,
1029 mojom::OrderDirection::ABOVE));
1030
1031 // view6 & view3 have different parents.
1032 EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_3, window_2_6,
1033 mojom::OrderDirection::ABOVE));
1034
1035 // Non-existent window-ids
1036 EXPECT_FALSE(wt_client1()->ReorderWindow(BuildWindowId(connection_id_1(), 27),
1037 BuildWindowId(connection_id_1(), 28),
1038 mojom::OrderDirection::ABOVE));
1039
1040 // view7 & view8 are un-parented.
1041 EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_7, window_2_8,
1042 mojom::OrderDirection::ABOVE));
1043 }
1044
1045 // Verifies DeleteWindow works.
1046 TEST_F(WindowTreeAppTest, DeleteWindow) {
1047 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1048 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1049 Id window_2_1 = wt_client2()->NewWindow(1);
1050 ASSERT_TRUE(window_2_1);
1051
1052 // Make 2 a child of 1.
1053 {
1054 changes1()->clear();
1055 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1056 wt_client1_->WaitForChangeCount(1);
1057 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
1058 " new_parent=" + IdToString(window_1_1) + " old_parent=null",
1059 SingleChangeToDescription(*changes1()));
1060 }
1061
1062 // Delete 2.
1063 {
1064 changes1()->clear();
1065 changes2()->clear();
1066 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
1067 EXPECT_TRUE(changes2()->empty());
1068
1069 wt_client1_->WaitForChangeCount(1);
1070 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
1071 SingleChangeToDescription(*changes1()));
1072 }
1073 }
1074
1075 // Verifies DeleteWindow isn't allowed from a separate connection.
1076 TEST_F(WindowTreeAppTest, DeleteWindowFromAnotherConnectionDisallowed) {
1077 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1078 EXPECT_FALSE(wt_client2()->DeleteWindow(BuildWindowId(connection_id_1(), 1)));
1079 }
1080
1081 // Verifies if a window was deleted and then reused that other clients are
1082 // properly notified.
1083 TEST_F(WindowTreeAppTest, ReuseDeletedWindowId) {
1084 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1085 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1086 Id window_2_1 = wt_client2()->NewWindow(1);
1087 ASSERT_TRUE(window_2_1);
1088
1089 // Add 2 to 1.
1090 {
1091 changes1()->clear();
1092 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1093 wt_client1_->WaitForChangeCount(1);
1094 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
1095 " new_parent=" + IdToString(window_1_1) + " old_parent=null",
1096 SingleChangeToDescription(*changes1()));
1097 EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]",
1098 ChangeWindowDescription(*changes1()));
1099 }
1100
1101 // Delete 2.
1102 {
1103 changes1()->clear();
1104 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
1105
1106 wt_client1_->WaitForChangeCount(1);
1107 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
1108 SingleChangeToDescription(*changes1()));
1109 }
1110
1111 // Create 2 again, and add it back to 1. Should get the same notification.
1112 window_2_1 = wt_client2()->NewWindow(2);
1113 ASSERT_TRUE(window_2_1);
1114 {
1115 changes1()->clear();
1116 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1117
1118 wt_client1_->WaitForChangeCount(1);
1119 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
1120 " new_parent=" + IdToString(window_1_1) + " old_parent=null",
1121 SingleChangeToDescription(*changes1()));
1122 EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]",
1123 ChangeWindowDescription(*changes1()));
1124 }
1125 }
1126
1127 // Assertions for GetWindowTree.
1128 TEST_F(WindowTreeAppTest, GetWindowTree) {
1129 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1130 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1131
1132 // Create 11 in first connection and make it a child of 1.
1133 Id window_1_11 = wt_client1()->NewWindow(11);
1134 ASSERT_TRUE(window_1_11);
1135 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1136 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_11));
1137
1138 // Create two windows in second connection, 2 and 3, both children of 1.
1139 Id window_2_1 = wt_client2()->NewWindow(1);
1140 Id window_2_2 = wt_client2()->NewWindow(2);
1141 ASSERT_TRUE(window_2_1);
1142 ASSERT_TRUE(window_2_2);
1143 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1144 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
1145
1146 // Verifies GetWindowTree() on the root. The root connection sees all.
1147 {
1148 std::vector<TestWindow> windows;
1149 GetWindowTree(wt1(), root_window_id(), &windows);
1150 ASSERT_EQ(5u, windows.size());
1151 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
1152 windows[0].ToString());
1153 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()),
1154 windows[1].ToString());
1155 EXPECT_EQ(WindowParentToString(window_1_11, window_1_1),
1156 windows[2].ToString());
1157 EXPECT_EQ(WindowParentToString(window_2_1, window_1_1),
1158 windows[3].ToString());
1159 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
1160 windows[4].ToString());
1161 }
1162
1163 // Verifies GetWindowTree() on the window 1,1 from wt2(). wt2() sees 1,1 as
1164 // 1,1
1165 // is wt2()'s root and wt2() sees all the windows it created.
1166 {
1167 std::vector<TestWindow> windows;
1168 GetWindowTree(wt2(), window_1_1, &windows);
1169 ASSERT_EQ(3u, windows.size());
1170 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
1171 windows[0].ToString());
1172 EXPECT_EQ(WindowParentToString(window_2_1, window_1_1),
1173 windows[1].ToString());
1174 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
1175 windows[2].ToString());
1176 }
1177
1178 // Connection 2 shouldn't be able to get the root tree.
1179 {
1180 std::vector<TestWindow> windows;
1181 GetWindowTree(wt2(), root_window_id(), &windows);
1182 ASSERT_EQ(0u, windows.size());
1183 }
1184 }
1185
1186 TEST_F(WindowTreeAppTest, SetWindowBounds) {
1187 Id window_1_1 = wt_client1()->NewWindow(1);
1188 ASSERT_TRUE(window_1_1);
1189 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1190
1191 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1192
1193 changes2()->clear();
1194
1195 wt_client2_->set_track_root_bounds_changes(true);
1196
1197 wt1()->SetWindowBounds(10, window_1_1,
1198 mojo::Rect::From(gfx::Rect(0, 0, 100, 100)));
1199 ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(10));
1200
1201 wt_client2_->WaitForChangeCount(1);
1202 EXPECT_EQ("BoundsChanged window=" + IdToString(window_1_1) +
1203 " old_bounds=0,0 0x0 new_bounds=0,0 100x100",
1204 SingleChangeToDescription(*changes2()));
1205
1206 // Should not be possible to change the bounds of a window created by another
1207 // connection.
1208 wt2()->SetWindowBounds(11, window_1_1,
1209 mojo::Rect::From(gfx::Rect(0, 0, 0, 0)));
1210 ASSERT_FALSE(wt_client2()->WaitForChangeCompleted(11));
1211 }
1212
1213 // Verify AddWindow fails when trying to manipulate windows in other roots.
1214 TEST_F(WindowTreeAppTest, CantMoveWindowsFromOtherRoot) {
1215 // Create 1 and 2 in the first connection.
1216 Id window_1_1 = wt_client1()->NewWindow(1);
1217 Id window_1_2 = wt_client1()->NewWindow(2);
1218 ASSERT_TRUE(window_1_1);
1219 ASSERT_TRUE(window_1_2);
1220
1221 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1222
1223 // Try to move 2 to be a child of 1 from connection 2. This should fail as 2
1224 // should not be able to access 1.
1225 ASSERT_FALSE(wt_client2()->AddWindow(window_1_1, window_1_2));
1226
1227 // Try to reparent 1 to the root. A connection is not allowed to reparent its
1228 // roots.
1229 ASSERT_FALSE(wt_client2()->AddWindow(root_window_id(), window_1_1));
1230 }
1231
1232 // Verify RemoveWindowFromParent fails for windows that are descendants of the
1233 // roots.
1234 TEST_F(WindowTreeAppTest, CantRemoveWindowsInOtherRoots) {
1235 // Create 1 and 2 in the first connection and parent both to the root.
1236 Id window_1_1 = wt_client1()->NewWindow(1);
1237 Id window_1_2 = wt_client1()->NewWindow(2);
1238 ASSERT_TRUE(window_1_1);
1239 ASSERT_TRUE(window_1_2);
1240
1241 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1242 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
1243
1244 // Establish the second connection and give it the root 1.
1245 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1246
1247 // Connection 2 should not be able to remove window 2 or 1 from its parent.
1248 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_2));
1249 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_1));
1250
1251 // Create windows 10 and 11 in 2.
1252 Id window_2_10 = wt_client2()->NewWindow(10);
1253 Id window_2_11 = wt_client2()->NewWindow(11);
1254 ASSERT_TRUE(window_2_10);
1255 ASSERT_TRUE(window_2_11);
1256
1257 // Parent 11 to 10.
1258 ASSERT_TRUE(wt_client2()->AddWindow(window_2_10, window_2_11));
1259 // Remove 11 from 10.
1260 ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
1261
1262 // Verify nothing was actually removed.
1263 {
1264 std::vector<TestWindow> windows;
1265 GetWindowTree(wt1(), root_window_id(), &windows);
1266 ASSERT_EQ(3u, windows.size());
1267 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
1268 windows[0].ToString());
1269 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()),
1270 windows[1].ToString());
1271 EXPECT_EQ(WindowParentToString(window_1_2, root_window_id()),
1272 windows[2].ToString());
1273 }
1274 }
1275
1276 // Verify GetWindowTree fails for windows that are not descendants of the roots.
1277 TEST_F(WindowTreeAppTest, CantGetWindowTreeOfOtherRoots) {
1278 // Create 1 and 2 in the first connection and parent both to the root.
1279 Id window_1_1 = wt_client1()->NewWindow(1);
1280 Id window_1_2 = wt_client1()->NewWindow(2);
1281 ASSERT_TRUE(window_1_1);
1282 ASSERT_TRUE(window_1_2);
1283
1284 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1285 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
1286
1287 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1288
1289 std::vector<TestWindow> windows;
1290
1291 // Should get nothing for the root.
1292 GetWindowTree(wt2(), root_window_id(), &windows);
1293 ASSERT_TRUE(windows.empty());
1294
1295 // Should get nothing for window 2.
1296 GetWindowTree(wt2(), window_1_2, &windows);
1297 ASSERT_TRUE(windows.empty());
1298
1299 // Should get window 1 if asked for.
1300 GetWindowTree(wt2(), window_1_1, &windows);
1301 ASSERT_EQ(1u, windows.size());
1302 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
1303 windows[0].ToString());
1304 }
1305
1306 TEST_F(WindowTreeAppTest, EmbedWithSameWindowId) {
1307 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1308 changes2()->clear();
1309
1310 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1311 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt1(), window_1_1));
1312
1313 // Connection2 should have been told of the unembed and delete.
1314 {
1315 wt_client2_->WaitForChangeCount(2);
1316 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1),
1317 ChangesToDescription1(*changes2())[0]);
1318 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1),
1319 ChangesToDescription1(*changes2())[1]);
1320 }
1321
1322 // Connection2 has no root. Verify it can't see window 1,1 anymore.
1323 {
1324 std::vector<TestWindow> windows;
1325 GetWindowTree(wt2(), window_1_1, &windows);
1326 EXPECT_TRUE(windows.empty());
1327 }
1328 }
1329
1330 TEST_F(WindowTreeAppTest, EmbedWithSameWindowId2) {
1331 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1332 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1333 changes2()->clear();
1334
1335 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt1(), window_1_1));
1336
1337 // Connection2 should have been told about the unembed and delete.
1338 wt_client2_->WaitForChangeCount(2);
1339 changes2()->clear();
1340
1341 // Create a window in the third connection and parent it to the root.
1342 Id window_3_1 = wt_client3()->NewWindow(1);
1343 ASSERT_TRUE(window_3_1);
1344 ASSERT_TRUE(wt_client3()->AddWindow(window_1_1, window_3_1));
1345
1346 // Connection 1 should have been told about the add (it owns the window).
1347 {
1348 wt_client1_->WaitForChangeCount(1);
1349 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_3_1) +
1350 " new_parent=" + IdToString(window_1_1) + " old_parent=null",
1351 SingleChangeToDescription(*changes1()));
1352 }
1353
1354 // Embed 1,1 again.
1355 {
1356 changes3()->clear();
1357
1358 // We should get a new connection for the new embedding.
1359 scoped_ptr<TestWindowTreeClientImpl> connection4(
1360 EstablishConnectionViaEmbed(wt1(), window_1_1, nullptr));
1361 ASSERT_TRUE(connection4.get());
1362 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
1363 ChangeWindowDescription(*connection4->tracker()->changes()));
1364
1365 // And 3 should get an unembed and delete.
1366 wt_client3_->WaitForChangeCount(2);
1367 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1),
1368 ChangesToDescription1(*changes3())[0]);
1369 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1),
1370 ChangesToDescription1(*changes3())[1]);
1371 }
1372
1373 // wt3() has no root. Verify it can't see window 1,1 anymore.
1374 {
1375 std::vector<TestWindow> windows;
1376 GetWindowTree(wt3(), window_1_1, &windows);
1377 EXPECT_TRUE(windows.empty());
1378 }
1379
1380 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
1381 // wt3() can no longer see 1,1.
1382 {
1383 std::vector<TestWindow> windows;
1384 GetWindowTree(wt1(), window_1_1, &windows);
1385 ASSERT_EQ(1u, windows.size());
1386 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
1387 windows[0].ToString());
1388 }
1389
1390 // Verify wt3() can still see the window it created 3,1.
1391 {
1392 std::vector<TestWindow> windows;
1393 GetWindowTree(wt3(), window_3_1, &windows);
1394 ASSERT_EQ(1u, windows.size());
1395 EXPECT_EQ(WindowParentToString(window_3_1, kNullParentId),
1396 windows[0].ToString());
1397 }
1398 }
1399
1400 // Assertions for SetWindowVisibility.
1401 TEST_F(WindowTreeAppTest, SetWindowVisibility) {
1402 // Create 1 and 2 in the first connection and parent both to the root.
1403 Id window_1_1 = wt_client1()->NewWindow(1);
1404 Id window_1_2 = wt_client1()->NewWindow(2);
1405 ASSERT_TRUE(window_1_1);
1406 ASSERT_TRUE(window_1_2);
1407
1408 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1409 {
1410 std::vector<TestWindow> windows;
1411 GetWindowTree(wt1(), root_window_id(), &windows);
1412 ASSERT_EQ(2u, windows.size());
1413 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId) +
1414 " visible=true drawn=true",
1415 windows[0].ToString2());
1416 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()) +
1417 " visible=false drawn=false",
1418 windows[1].ToString2());
1419 }
1420
1421 // Show all the windows.
1422 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
1423 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
1424 {
1425 std::vector<TestWindow> windows;
1426 GetWindowTree(wt1(), root_window_id(), &windows);
1427 ASSERT_EQ(2u, windows.size());
1428 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId) +
1429 " visible=true drawn=true",
1430 windows[0].ToString2());
1431 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()) +
1432 " visible=true drawn=true",
1433 windows[1].ToString2());
1434 }
1435
1436 // Hide 1.
1437 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
1438 {
1439 std::vector<TestWindow> windows;
1440 GetWindowTree(wt1(), window_1_1, &windows);
1441 ASSERT_EQ(1u, windows.size());
1442 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()) +
1443 " visible=false drawn=false",
1444 windows[0].ToString2());
1445 }
1446
1447 // Attach 2 to 1.
1448 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
1449 {
1450 std::vector<TestWindow> windows;
1451 GetWindowTree(wt1(), window_1_1, &windows);
1452 ASSERT_EQ(2u, windows.size());
1453 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()) +
1454 " visible=false drawn=false",
1455 windows[0].ToString2());
1456 EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) +
1457 " visible=true drawn=false",
1458 windows[1].ToString2());
1459 }
1460
1461 // Show 1.
1462 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
1463 {
1464 std::vector<TestWindow> windows;
1465 GetWindowTree(wt1(), window_1_1, &windows);
1466 ASSERT_EQ(2u, windows.size());
1467 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()) +
1468 " visible=true drawn=true",
1469 windows[0].ToString2());
1470 EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) +
1471 " visible=true drawn=true",
1472 windows[1].ToString2());
1473 }
1474 }
1475
1476 // Test that we hear the cursor change in other connections.
1477 TEST_F(WindowTreeAppTest, SetCursor) {
1478 // Get a second connection to listen in.
1479 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1480 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1481 changes2()->clear();
1482
1483 ASSERT_TRUE(
1484 wt_client1()->SetPredefinedCursor(window_1_1, mojom::Cursor::IBEAM));
1485 wt_client2_->WaitForChangeCount(1u);
1486
1487 EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4",
1488 SingleChangeToDescription(*changes2()));
1489 }
1490
1491 // Assertions for SetWindowVisibility sending notifications.
1492 TEST_F(WindowTreeAppTest, SetWindowVisibilityNotifications) {
1493 // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
1494 Id window_1_1 = wt_client1()->NewWindow(1);
1495 ASSERT_TRUE(window_1_1);
1496 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
1497 Id window_1_2 = wt_client1()->NewWindow(2);
1498 ASSERT_TRUE(window_1_2);
1499 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
1500 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1501 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
1502
1503 // Establish the second connection at 1,2.
1504 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnectionWithRoot(window_1_2));
1505
1506 // Add 2,3 as a child of 1,2.
1507 Id window_2_1 = wt_client2()->NewWindow(1);
1508 ASSERT_TRUE(window_2_1);
1509 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, true));
1510 ASSERT_TRUE(wt_client2()->AddWindow(window_1_2, window_2_1));
1511 ASSERT_TRUE(wt_client1()->WaitForAllMessages());
1512
1513 changes2()->clear();
1514 // Hide 1,2 from connection 1. Connection 2 should see this.
1515 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, false));
1516 {
1517 wt_client2_->WaitForChangeCount(1);
1518 EXPECT_EQ(
1519 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=false",
1520 SingleChangeToDescription(*changes2()));
1521 }
1522
1523 changes1()->clear();
1524 // Show 1,2 from connection 2, connection 1 should be notified.
1525 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_1_2, true));
1526 {
1527 wt_client1_->WaitForChangeCount(1);
1528 EXPECT_EQ(
1529 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true",
1530 SingleChangeToDescription(*changes1()));
1531 }
1532
1533 changes2()->clear();
1534 // Hide 1,1, connection 2 should be told the draw state changed.
1535 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
1536 {
1537 wt_client2_->WaitForChangeCount(1);
1538 EXPECT_EQ(
1539 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false",
1540 SingleChangeToDescription(*changes2()));
1541 }
1542
1543 changes2()->clear();
1544 // Show 1,1 from connection 1. Connection 2 should see this.
1545 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
1546 {
1547 wt_client2_->WaitForChangeCount(1);
1548 EXPECT_EQ(
1549 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true",
1550 SingleChangeToDescription(*changes2()));
1551 }
1552
1553 // Change visibility of 2,3, connection 1 should see this.
1554 changes1()->clear();
1555 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, false));
1556 {
1557 wt_client1_->WaitForChangeCount(1);
1558 EXPECT_EQ(
1559 "VisibilityChanged window=" + IdToString(window_2_1) + " visible=false",
1560 SingleChangeToDescription(*changes1()));
1561 }
1562
1563 changes2()->clear();
1564 // Remove 1,1 from the root, connection 2 should see drawn state changed.
1565 ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
1566 {
1567 wt_client2_->WaitForChangeCount(1);
1568 EXPECT_EQ(
1569 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false",
1570 SingleChangeToDescription(*changes2()));
1571 }
1572
1573 changes2()->clear();
1574 // Add 1,1 back to the root, connection 2 should see drawn state changed.
1575 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1576 {
1577 wt_client2_->WaitForChangeCount(1);
1578 EXPECT_EQ(
1579 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true",
1580 SingleChangeToDescription(*changes2()));
1581 }
1582 }
1583
1584 TEST_F(WindowTreeAppTest, SetWindowProperty) {
1585 Id window_1_1 = wt_client1()->NewWindow(1);
1586 ASSERT_TRUE(window_1_1);
1587
1588 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
1589 changes2()->clear();
1590
1591 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1592 {
1593 std::vector<TestWindow> windows;
1594 GetWindowTree(wt1(), root_window_id(), &windows);
1595 ASSERT_EQ(2u, windows.size());
1596 EXPECT_EQ(root_window_id(), windows[0].window_id);
1597 EXPECT_EQ(window_1_1, windows[1].window_id);
1598 ASSERT_EQ(0u, windows[1].properties.size());
1599 }
1600
1601 // Set properties on 1.
1602 changes2()->clear();
1603 std::vector<uint8_t> one(1, '1');
1604 ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", &one));
1605 {
1606 wt_client2_->WaitForChangeCount(1);
1607 EXPECT_EQ(
1608 "PropertyChanged window=" + IdToString(window_1_1) + " key=one value=1",
1609 SingleChangeToDescription(*changes2()));
1610 }
1611
1612 // Test that our properties exist in the window tree
1613 {
1614 std::vector<TestWindow> windows;
1615 GetWindowTree(wt1(), window_1_1, &windows);
1616 ASSERT_EQ(1u, windows.size());
1617 ASSERT_EQ(1u, windows[0].properties.size());
1618 EXPECT_EQ(one, windows[0].properties["one"]);
1619 }
1620
1621 changes2()->clear();
1622 // Set back to null.
1623 ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", NULL));
1624 {
1625 wt_client2_->WaitForChangeCount(1);
1626 EXPECT_EQ("PropertyChanged window=" + IdToString(window_1_1) +
1627 " key=one value=NULL",
1628 SingleChangeToDescription(*changes2()));
1629 }
1630 }
1631
1632 TEST_F(WindowTreeAppTest, OnEmbeddedAppDisconnected) {
1633 // Create connection 2 and 3.
1634 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1635 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1636 Id window_2_1 = wt_client2()->NewWindow(1);
1637 ASSERT_TRUE(window_2_1);
1638 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1639 changes2()->clear();
1640 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_1));
1641
1642 // Connection 1 should get a hierarchy change for window_2_1.
1643 wt_client1_->WaitForChangeCount(1);
1644 changes1()->clear();
1645
1646 // Close connection 3. Connection 2 (which had previously embedded 3) should
1647 // be notified of this.
1648 wt_client3_.reset();
1649 wt_client2_->WaitForChangeCount(1);
1650 EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_2_1),
1651 SingleChangeToDescription(*changes2()));
1652
1653 wt_client1_->WaitForChangeCount(1);
1654 EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_2_1),
1655 SingleChangeToDescription(*changes1()));
1656 }
1657
1658 // Verifies when the parent of an Embed() is destroyed the embedded app gets
1659 // a WindowDeleted (and doesn't trigger a DCHECK).
1660 TEST_F(WindowTreeAppTest, OnParentOfEmbedDisconnects) {
1661 // Create connection 2 and 3.
1662 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1663 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1664 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1665 Id window_2_1 = wt_client2()->NewWindow(1);
1666 Id window_2_2 = wt_client2()->NewWindow(2);
1667 ASSERT_TRUE(window_2_1);
1668 ASSERT_TRUE(window_2_2);
1669 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1670 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
1671 changes2()->clear();
1672 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_2));
1673 changes3()->clear();
1674
1675 // Close connection 2. Connection 3 should get a delete (for its root).
1676 wt_client2_.reset();
1677 wt_client3_->WaitForChangeCount(1);
1678 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2),
1679 SingleChangeToDescription(*changes3()));
1680 }
1681
1682 // Verifies WindowTreeImpl doesn't incorrectly erase from its internal
1683 // map when a window from another connection with the same window_id is removed.
1684 TEST_F(WindowTreeAppTest, DontCleanMapOnDestroy) {
1685 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1686 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1687 ASSERT_TRUE(wt_client2()->NewWindow(1));
1688 changes1()->clear();
1689 wt_client2_.reset();
1690 wt_client1_->WaitForChangeCount(1);
1691 EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_1_1),
1692 SingleChangeToDescription(*changes1()));
1693 std::vector<TestWindow> windows;
1694 GetWindowTree(wt1(), window_1_1, &windows);
1695 EXPECT_FALSE(windows.empty());
1696 }
1697
1698 // Verifies Embed() works when supplying a WindowTreeClient.
1699 TEST_F(WindowTreeAppTest, EmbedSupplyingWindowTreeClient) {
1700 ASSERT_TRUE(wt_client1()->NewWindow(1));
1701
1702 TestWindowTreeClientImpl client2;
1703 mojom::WindowTreeClientPtr client2_ptr;
1704 mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr);
1705 ASSERT_TRUE(Embed(wt1(), BuildWindowId(connection_id_1(), 1),
1706 std::move(client2_ptr)));
1707 client2.WaitForOnEmbed();
1708 EXPECT_EQ("OnEmbed",
1709 SingleChangeToDescription(*client2.tracker()->changes()));
1710 }
1711
1712 TEST_F(WindowTreeAppTest, EmbedFailsFromOtherConnection) {
1713 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1714
1715 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1716 Id window_2_1 = wt_client2()->NewWindow(1);
1717 ASSERT_TRUE(window_2_1);
1718 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1719 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt2(), window_2_1));
1720
1721 Id window_3_3 = wt_client3()->NewWindow(3);
1722 ASSERT_TRUE(window_3_3);
1723 ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_3));
1724
1725 // 2 should not be able to embed in window_3_3 as window_3_3 was not created
1726 // by
1727 // 2.
1728 EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(), window_3_3));
1729 }
1730
1731 // Verifies Embed() from window manager on another connections window works.
1732 TEST_F(WindowTreeAppTest, EmbedFromOtherConnection) {
1733 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1734
1735 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1736 Id window_2_1 = wt_client2()->NewWindow(1);
1737 ASSERT_TRUE(window_2_1);
1738 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1739
1740 changes2()->clear();
1741
1742 // Establish a third connection in window_2_1.
1743 ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(wt1(), window_2_1));
1744
1745 ASSERT_TRUE(wt_client2()->WaitForAllMessages());
1746 EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
1747 }
1748
1749 TEST_F(WindowTreeAppTest, CantEmbedFromConnectionRoot) {
1750 // Shouldn't be able to embed into the root.
1751 ASSERT_FALSE(EmbedUrl(connector(), wt1(), test_name(), root_window_id()));
1752
1753 // Even though the call above failed a WindowTreeClient was obtained. We need
1754 // to
1755 // wait for it else we throw off the next connect.
1756 WaitForWindowTreeClient();
1757
1758 // Don't allow a connection to embed into its own root.
1759 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1760 EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(),
1761 BuildWindowId(connection_id_1(), 1)));
1762
1763 // Need to wait for a WindowTreeClient for same reason as above.
1764 WaitForWindowTreeClient();
1765
1766 Id window_1_2 = wt_client1()->NewWindow(2);
1767 ASSERT_TRUE(window_1_2);
1768 ASSERT_TRUE(
1769 wt_client1()->AddWindow(BuildWindowId(connection_id_1(), 1), window_1_2));
1770 ASSERT_TRUE(wt_client3_.get() == nullptr);
1771 wt_client3_ = EstablishConnectionViaEmbedWithPolicyBitmask(
1772 wt1(), window_1_2, mojom::WindowTree::kAccessPolicyEmbedRoot, nullptr);
1773 ASSERT_TRUE(wt_client3_.get() != nullptr);
1774
1775 // window_1_2 is ws3's root, so even though v3 is an embed root it should not
1776 // be able to Embed into itself.
1777 ASSERT_FALSE(EmbedUrl(connector(), wt3(), test_name(), window_1_2));
1778 }
1779
1780 // Verifies that a transient window tracks its parent's lifetime.
1781 TEST_F(WindowTreeAppTest, TransientWindowTracksTransientParentLifetime) {
1782 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
1783 Id window_1_1 = BuildWindowId(connection_id_1(), 1);
1784
1785 Id window_2_1 = wt_client2()->NewWindow(1);
1786 Id window_2_2 = wt_client2()->NewWindow(2);
1787 Id window_2_3 = wt_client2()->NewWindow(3);
1788 ASSERT_TRUE(window_2_1);
1789
1790 // root -> window_1_1 -> window_2_1
1791 // root -> window_1_1 -> window_2_2
1792 // root -> window_1_1 -> window_2_3
1793 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1794 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
1795 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
1796 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_3));
1797
1798 // window_2_2 and window_2_3 now track the lifetime of window_2_1.
1799 changes1()->clear();
1800 wt2()->AddTransientWindow(10, window_2_1, window_2_2);
1801 wt2()->AddTransientWindow(11, window_2_1, window_2_3);
1802 wt_client1()->WaitForChangeCount(2);
1803 EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
1804 " child = " + IdToString(window_2_2),
1805 ChangesToDescription1(*changes1())[0]);
1806 EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
1807 " child = " + IdToString(window_2_3),
1808 ChangesToDescription1(*changes1())[1]);
1809
1810 changes1()->clear();
1811 wt2()->RemoveTransientWindowFromParent(12, window_2_3);
1812 wt_client1()->WaitForChangeCount(1);
1813 EXPECT_EQ("RemoveTransientWindowFromParent parent = " +
1814 IdToString(window_2_1) + " child = " + IdToString(window_2_3),
1815 SingleChangeToDescription(*changes1()));
1816
1817 changes1()->clear();
1818 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
1819 wt_client1()->WaitForChangeCount(2);
1820 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2),
1821 ChangesToDescription1(*changes1())[0]);
1822 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
1823 ChangesToDescription1(*changes1())[1]);
1824 }
1825
1826 TEST_F(WindowTreeAppTest, Ids) {
1827 const Id window_1_100 = wt_client1()->NewWindow(100);
1828 ASSERT_TRUE(window_1_100);
1829 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100));
1830
1831 // Establish the second connection at 1,100.
1832 ASSERT_NO_FATAL_FAILURE(EstablishSecondConnectionWithRoot(window_1_100));
1833
1834 // 1,100 is the id in the wt_client1's id space. The new client should see
1835 // 2,1 (the server id).
1836 const Id window_1_100_in_ws2 = BuildWindowId(connection_id_1(), 1);
1837 EXPECT_EQ(window_1_100_in_ws2, wt_client2()->root_window_id());
1838
1839 // The first window created in the second connection gets a server id of 2,1
1840 // regardless of the id the client uses.
1841 const Id window_2_101 = wt_client2()->NewWindow(101);
1842 ASSERT_TRUE(wt_client2()->AddWindow(window_1_100_in_ws2, window_2_101));
1843 const Id window_2_101_in_ws1 = BuildWindowId(connection_id_2(), 1);
1844 wt_client1()->WaitForChangeCount(1);
1845 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101_in_ws1) +
1846 " new_parent=" + IdToString(window_1_100) + " old_parent=null",
1847 SingleChangeToDescription(*changes1()));
1848 changes1()->clear();
1849
1850 // Change the bounds of window_2_101 and make sure server gets it.
1851 wt2()->SetWindowBounds(11, window_2_101,
1852 mojo::Rect::From(gfx::Rect(1, 2, 3, 4)));
1853 ASSERT_TRUE(wt_client2()->WaitForChangeCompleted(11));
1854 wt_client1()->WaitForChangeCount(1);
1855 EXPECT_EQ("BoundsChanged window=" + IdToString(window_2_101_in_ws1) +
1856 " old_bounds=0,0 0x0 new_bounds=1,2 3x4",
1857 SingleChangeToDescription(*changes1()));
1858 changes2()->clear();
1859
1860 // Remove 2_101 from wm, client1 should see the change.
1861 wt1()->RemoveWindowFromParent(12, window_2_101_in_ws1);
1862 ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(12));
1863 wt_client2()->WaitForChangeCount(1);
1864 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101) +
1865 " new_parent=null old_parent=" +
1866 IdToString(window_1_100_in_ws2),
1867 SingleChangeToDescription(*changes2()));
1868 }
1869
1870 // Tests that setting capture fails when no input event has occurred, and there
1871 // is no notification of lost capture.
1872 TEST_F(WindowTreeAppTest, ExplicitCaptureWithoutInput) {
1873 Id window_1_1 = wt_client1()->NewWindow(1);
1874
1875 // Add the window to the root, so that they have a Display to handle input
1876 // capture.
1877 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1878 changes1()->clear();
1879
1880 // Since there has been no input, capture should not succeed. No lost capture
1881 // message is expected.
1882 wt1()->SetCapture(1, window_1_1);
1883 wt_client1_->WaitForAllMessages();
1884 EXPECT_TRUE(changes1()->empty());
1885
1886 // Since there is no window with capture, lost capture should not be notified.
1887 wt1()->ReleaseCapture(3, window_1_1);
1888 wt_client1_->WaitForAllMessages();
1889 EXPECT_TRUE(changes1()->empty());
1890 }
1891
1892 // TODO(jonross): Enable this once apptests can send input events to the server.
1893 // Enabling capture requires that the connection be processing events.
1894 TEST_F(WindowTreeAppTest, DISABLED_ExplicitCapturePropagation) {
1895 Id window_1_1 = wt_client1()->NewWindow(1);
1896 Id window_1_2 = wt_client1()->NewWindow(2);
1897
1898 // Add the windows to the root, so that they have a Display to handle input
1899 // capture.
1900 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
1901 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
1902
1903 changes1()->clear();
1904 // Window 1 takes capture then Window 2 takes capture.
1905 // Verify that window 1 has lost capture.
1906 wt1()->SetCapture(1, window_1_1);
1907 wt1()->SetCapture(2, window_1_2);
1908 wt_client1_->WaitForChangeCount(1);
1909
1910 EXPECT_EQ("OnLostCapture window=" + IdToString(window_1_1),
1911 SingleChangeToDescription(*changes1()));
1912
1913 changes1()->clear();
1914 // Explicitly releasing capture should not notify of lost capture.
1915 wt1()->ReleaseCapture(3, window_1_2);
1916 wt_client1_->WaitForAllMessages();
1917
1918 EXPECT_TRUE(changes1()->empty());
1919 }
1920
1921 // TODO(sky): need to better track changes to initial connection. For example,
1922 // that SetBounsdWindows/AddWindow and the like don't result in messages to the
1923 // originating connection.
1924
1925 // TODO(sky): make sure coverage of what was
1926 // WindowManagerTest.SecondEmbedRoot_InitService and
1927 // WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window
1928 // manager
1929 // tests.
1930
1931 } // namespace test
1932 } // namespace ws
1933 } // namespace mus
OLDNEW
« no previous file with comments | « components/mus/ws/window_manager_client_unittest.cc ('k') | components/mus/ws/window_tree_client_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698