1 // Copyright 2013 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 "apps/app_window_geometry_cache.h"
6 #include "chrome/browser/apps/app_browsertest_util.h"
7 #include "chrome/browser/extensions/extension_test_message_listener.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/extensions/application_launch.h"
11 #include "content/public/browser/notification_service.h"
12 #include "content/public/test/test_utils.h"
13 #include "extensions/common/constants.h"
14 #include "extensions/common/extension.h"
15
16 using apps::AppWindowGeometryCache;
17
18 // This helper class can be used to wait for changes in the app window
19 // geometry cache registry for a specific window in a specific extension.
20 class GeometryCacheChangeHelper : AppWindowGeometryCache::Observer {
21 public:
GeometryCacheChangeHelper(AppWindowGeometryCache * cache,const std::string & extension_id,const std::string & window_id,const gfx::Rect & bounds)22 GeometryCacheChangeHelper(AppWindowGeometryCache* cache,
23 const std::string& extension_id,
24 const std::string& window_id,
25 const gfx::Rect& bounds)
26 : cache_(cache),
27 extension_id_(extension_id),
28 window_id_(window_id),
29 bounds_(bounds),
30 satisfied_(false),
31 waiting_(false) {
32 cache_->AddObserver(this);
33 }
34
35 // This method will block until the app window geometry cache registry will
36 // provide a bound for |window_id_| that is entirely different (as in x/y/w/h)
37 // from the initial |bounds_|.
WaitForEntirelyChanged()38 void WaitForEntirelyChanged() {
39 if (satisfied_)
40 return;
41
42 waiting_ = true;
43 content::RunMessageLoop();
44 }
45
46 // Implements the content::NotificationObserver interface.
OnGeometryCacheChanged(const std::string & extension_id,const std::string & window_id,const gfx::Rect & bounds)47 virtual void OnGeometryCacheChanged(const std::string& extension_id,
48 const std::string& window_id,
49 const gfx::Rect& bounds)
50 OVERRIDE {
51 if (extension_id != extension_id_ || window_id != window_id_)
52 return;
53
54 if (bounds_.x() != bounds.x() &&
55 bounds_.y() != bounds.y() &&
56 bounds_.width() != bounds.width() &&
57 bounds_.height() != bounds.height()) {
58 satisfied_ = true;
59 cache_->RemoveObserver(this);
60
61 if (waiting_)
62 base::MessageLoopForUI::current()->Quit();
63 }
64 }
65
66 private:
67 AppWindowGeometryCache* cache_;
68 std::string extension_id_;
69 std::string window_id_;
70 gfx::Rect bounds_;
71 bool satisfied_;
72 bool waiting_;
73 };
74
75 // Helper class for tests related to the Apps Window API (chrome.app.window).
76 class AppWindowAPITest : public extensions::PlatformAppBrowserTest {
77 protected:
RunAppWindowAPITest(const char * testName)78 bool RunAppWindowAPITest(const char* testName) {
79 if (!BeginAppWindowAPITest(testName))
80 return false;
81
82 ResultCatcher catcher;
83 if (!catcher.GetNextResult()) {
84 message_ = catcher.message();
85 return false;
86 }
87
88 return true;
89 }
90
RunAppWindowAPITestAndWaitForRoundTrip(const char * testName)91 bool RunAppWindowAPITestAndWaitForRoundTrip(const char* testName) {
92 if (!BeginAppWindowAPITest(testName))
93 return false;
94
95 ExtensionTestMessageListener round_trip_listener("WaitForRoundTrip", true);
96 if (!round_trip_listener.WaitUntilSatisfied()) {
97 message_ = "Did not get the 'WaitForRoundTrip' message.";
98 return false;
99 }
100
101 round_trip_listener.Reply("");
102
103 ResultCatcher catcher;
104 if (!catcher.GetNextResult()) {
105 message_ = catcher.message();
106 return false;
107 }
108
109 return true;
110 }
111
112 private:
BeginAppWindowAPITest(const char * testName)113 bool BeginAppWindowAPITest(const char* testName) {
114 ExtensionTestMessageListener launched_listener("Launched", true);
115 LoadAndLaunchPlatformApp("window_api", &launched_listener);
116 if (!launched_listener.WaitUntilSatisfied()) {
117 message_ = "Did not get the 'Launched' message.";
118 return false;
119 }
120
121 launched_listener.Reply(testName);
122 return true;
123 }
124 };
125
126 // These tests are flaky after https://codereview.chromium.org/57433010/.
127 // See http://crbug.com/319613.
128
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestCreate)129 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCreate) {
130 ASSERT_TRUE(RunAppWindowAPITest("testCreate")) << message_;
131 }
132
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestSingleton)133 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestSingleton) {
134 ASSERT_TRUE(RunAppWindowAPITest("testSingleton")) << message_;
135 }
136
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestCloseEvent)137 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCloseEvent) {
138 ASSERT_TRUE(RunAppWindowAPITest("testCloseEvent")) << message_;
139 }
140
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,DISABLED_TestMaximize)141 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestMaximize) {
142 ASSERT_TRUE(RunAppWindowAPITest("testMaximize")) << message_;
143 }
144
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,DISABLED_TestRestore)145 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestRestore) {
146 ASSERT_TRUE(RunAppWindowAPITest("testRestore")) << message_;
147 }
148
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,DISABLED_TestRestoreAfterClose)149 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestRestoreAfterClose) {
150 ASSERT_TRUE(RunAppWindowAPITest("testRestoreAfterClose")) << message_;
151 }
152
153 // These tests will be flaky in Linux as window bounds change asynchronously.
154 #if defined(OS_LINUX)
155 #define MAYBE_TestDeprecatedBounds DISABLED_TestDeprecatedBounds
156 #define MAYBE_TestInitialBounds DISABLED_TestInitialBounds
157 #define MAYBE_TestInitialConstraints DISABLED_TestInitialConstraints
158 #define MAYBE_TestSetBounds DISABLED_TestSetBounds
159 #define MAYBE_TestSetSizeConstraints DISABLED_TestSetSizeConstraints
160 #else
161 #define MAYBE_TestDeprecatedBounds TestDeprecatedBounds
162 #define MAYBE_TestInitialBounds TestInitialBounds
163 #define MAYBE_TestInitialConstraints TestInitialConstraints
164 #define MAYBE_TestSetBounds TestSetBounds
165 #define MAYBE_TestSetSizeConstraints TestSetSizeConstraints
166 #endif
167
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,MAYBE_TestDeprecatedBounds)168 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestDeprecatedBounds) {
169 ASSERT_TRUE(RunAppWindowAPITest("testDeprecatedBounds")) << message_;
170 }
171
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,MAYBE_TestInitialBounds)172 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialBounds) {
173 ASSERT_TRUE(RunAppWindowAPITest("testInitialBounds")) << message_;
174 }
175
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,MAYBE_TestInitialConstraints)176 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialConstraints) {
177 ASSERT_TRUE(RunAppWindowAPITest("testInitialConstraints")) << message_;
178 }
179
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,MAYBE_TestSetBounds)180 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestSetBounds) {
181 ASSERT_TRUE(RunAppWindowAPITest("testSetBounds")) << message_;
182 }
183
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,MAYBE_TestSetSizeConstraints)184 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestSetSizeConstraints) {
185 ASSERT_TRUE(RunAppWindowAPITest("testSetSizeConstraints")) << message_;
186 }
187
188 // Flaky failures on mac_rel and WinXP, see http://crbug.com/324915.
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,DISABLED_TestRestoreGeometryCacheChange)189 IN_PROC_BROWSER_TEST_F(AppWindowAPITest,
190 DISABLED_TestRestoreGeometryCacheChange) {
191 // This test is similar to the other AppWindowAPI tests except that at some
192 // point the app will send a 'ListenGeometryChange' message at which point the
193 // test will check if the geometry cache entry for the test window has
194 // changed. When the change happens, the test will let the app know so it can
195 // continue running.
196 ExtensionTestMessageListener launched_listener("Launched", true);
197
198 content::WindowedNotificationObserver app_loaded_observer(
199 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
200 content::NotificationService::AllSources());
201
202 const extensions::Extension* extension = LoadExtension(
203 test_data_dir_.AppendASCII("platform_apps").AppendASCII("window_api"));
204 EXPECT_TRUE(extension);
205
206 OpenApplication(AppLaunchParams(browser()->profile(),
207 extension,
208 extensions::LAUNCH_CONTAINER_NONE,
209 NEW_WINDOW));
210
211 ExtensionTestMessageListener geometry_listener("ListenGeometryChange", true);
212
213 ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
214 launched_listener.Reply("testRestoreAfterGeometryCacheChange");
215
216 ASSERT_TRUE(geometry_listener.WaitUntilSatisfied());
217
218 GeometryCacheChangeHelper geo_change_helper_1(
219 AppWindowGeometryCache::Get(browser()->profile()),
220 extension->id(),
221 // The next line has information that has to stay in sync with the app.
222 "test-ra",
223 gfx::Rect(200, 200, 200, 200));
224
225 GeometryCacheChangeHelper geo_change_helper_2(
226 AppWindowGeometryCache::Get(browser()->profile()),
227 extension->id(),
228 // The next line has information that has to stay in sync with the app.
229 "test-rb",
230 gfx::Rect(200, 200, 200, 200));
231
232 // These calls will block until the app window geometry cache will change.
233 geo_change_helper_1.WaitForEntirelyChanged();
234 geo_change_helper_2.WaitForEntirelyChanged();
235
236 ResultCatcher catcher;
237 geometry_listener.Reply("");
238 ASSERT_TRUE(catcher.GetNextResult());
239 }
240
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestBadging)241 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestBadging) {
242 ASSERT_TRUE(
243 RunAppWindowAPITestAndWaitForRoundTrip("testBadging")) << message_;
244 }
245
246 // TODO(benwells): Implement on Mac.
247 #if defined(USE_AURA)
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestFrameColors)248 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColors) {
249 ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_;
250 }
251
252 // TODO(benwells): Remove this test once all the things are merged together. It
253 // is currently present as this feature was previously disabled on stable
254 // channel, so the test is to ensure it has all been re-enabled properly.
IN_PROC_BROWSER_TEST_F(AppWindowAPITest,TestFrameColorsInStable)255 IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColorsInStable) {
256 extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_STABLE);
257 ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_;
258 }
259 #endif
260