Home | History | Annotate | Download | only in apps
      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