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