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 17using extensions::AppWindowGeometryCache; 18using 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. 22class 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). 78class 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 131IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCreate) { 132 ASSERT_TRUE(RunAppWindowAPITest("testCreate")) << message_; 133} 134 135IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestSingleton) { 136 ASSERT_TRUE(RunAppWindowAPITest("testSingleton")) << message_; 137} 138 139IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCloseEvent) { 140 ASSERT_TRUE(RunAppWindowAPITest("testCloseEvent")) << message_; 141} 142 143IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestMaximize) { 144 ASSERT_TRUE(RunAppWindowAPITest("testMaximize")) << message_; 145} 146 147IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestRestore) { 148 ASSERT_TRUE(RunAppWindowAPITest("testRestore")) << message_; 149} 150 151IN_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 170IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestDeprecatedBounds) { 171 ASSERT_TRUE(RunAppWindowAPITest("testDeprecatedBounds")) << message_; 172} 173 174IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialBounds) { 175 ASSERT_TRUE(RunAppWindowAPITest("testInitialBounds")) << message_; 176} 177 178IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialConstraints) { 179 ASSERT_TRUE(RunAppWindowAPITest("testInitialConstraints")) << message_; 180} 181 182IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestSetBounds) { 183 ASSERT_TRUE(RunAppWindowAPITest("testSetBounds")) << message_; 184} 185 186IN_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. 191IN_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 243IN_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) 250IN_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. 257IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColorsInStable) { 258 extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_STABLE); 259 ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_; 260} 261#endif 262 263IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestVisibleOnAllWorkspaces) { 264 ASSERT_TRUE( 265 RunAppWindowAPITestAndWaitForRoundTrip("testVisibleOnAllWorkspaces")) 266 << message_; 267} 268