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 16using 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. 20class GeometryCacheChangeHelper : AppWindowGeometryCache::Observer { 21 public: 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_|. 38 void WaitForEntirelyChanged() { 39 if (satisfied_) 40 return; 41 42 waiting_ = true; 43 content::RunMessageLoop(); 44 } 45 46 // Implements the content::NotificationObserver interface. 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). 76class AppWindowAPITest : public extensions::PlatformAppBrowserTest { 77 protected: 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 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: 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 129IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCreate) { 130 ASSERT_TRUE(RunAppWindowAPITest("testCreate")) << message_; 131} 132 133IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestSingleton) { 134 ASSERT_TRUE(RunAppWindowAPITest("testSingleton")) << message_; 135} 136 137IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestCloseEvent) { 138 ASSERT_TRUE(RunAppWindowAPITest("testCloseEvent")) << message_; 139} 140 141IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestMaximize) { 142 ASSERT_TRUE(RunAppWindowAPITest("testMaximize")) << message_; 143} 144 145IN_PROC_BROWSER_TEST_F(AppWindowAPITest, DISABLED_TestRestore) { 146 ASSERT_TRUE(RunAppWindowAPITest("testRestore")) << message_; 147} 148 149IN_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 168IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestDeprecatedBounds) { 169 ASSERT_TRUE(RunAppWindowAPITest("testDeprecatedBounds")) << message_; 170} 171 172IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialBounds) { 173 ASSERT_TRUE(RunAppWindowAPITest("testInitialBounds")) << message_; 174} 175 176IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestInitialConstraints) { 177 ASSERT_TRUE(RunAppWindowAPITest("testInitialConstraints")) << message_; 178} 179 180IN_PROC_BROWSER_TEST_F(AppWindowAPITest, MAYBE_TestSetBounds) { 181 ASSERT_TRUE(RunAppWindowAPITest("testSetBounds")) << message_; 182} 183 184IN_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. 189IN_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 241IN_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) 248IN_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. 255IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColorsInStable) { 256 extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_STABLE); 257 ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_; 258} 259#endif 260