shell_desktop_controller_aura_browsertest.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2018 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. #include "extensions/shell/browser/shell_desktop_controller_aura.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/run_loop.h"
  9. #include "base/test/bind.h"
  10. #include "base/time/time.h"
  11. #include "components/keep_alive_registry/keep_alive_registry.h"
  12. #include "extensions/browser/app_window/app_window.h"
  13. #include "extensions/browser/app_window/app_window_registry.h"
  14. #include "extensions/browser/browsertest_util.h"
  15. #include "extensions/shell/browser/desktop_controller.h"
  16. #include "extensions/shell/test/shell_apitest.h"
  17. #include "extensions/test/result_catcher.h"
  18. namespace extensions {
  19. // Tests that spin up the ShellDesktopControllerAura and run async tasks like
  20. // launching and reloading apps.
  21. class ShellDesktopControllerAuraBrowserTest : public ShellApiTest {
  22. public:
  23. ShellDesktopControllerAuraBrowserTest() = default;
  24. ~ShellDesktopControllerAuraBrowserTest() override = default;
  25. ShellDesktopControllerAuraBrowserTest(
  26. const ShellDesktopControllerAuraBrowserTest&) = delete;
  27. ShellDesktopControllerAuraBrowserTest& operator=(
  28. const ShellDesktopControllerAuraBrowserTest&) = delete;
  29. // Loads and launches a platform app that opens an app window.
  30. void LoadAndLaunchApp() {
  31. ASSERT_FALSE(app_);
  32. app_ = LoadApp("platform_app");
  33. ASSERT_TRUE(app_);
  34. // Wait for app window to load.
  35. ResultCatcher catcher;
  36. EXPECT_TRUE(catcher.GetNextResult());
  37. // A window was created.
  38. EXPECT_EQ(1u,
  39. AppWindowRegistry::Get(browser_context())->app_windows().size());
  40. }
  41. protected:
  42. // Returns an open app window.
  43. AppWindow* GetAppWindow() {
  44. EXPECT_GT(AppWindowRegistry::Get(browser_context())->app_windows().size(),
  45. 0u);
  46. return AppWindowRegistry::Get(browser_context())->app_windows().front();
  47. }
  48. // ShellApiTest:
  49. void SetUpOnMainThread() override {
  50. ShellApiTest::SetUpOnMainThread();
  51. desktop_controller_ =
  52. static_cast<ShellDesktopControllerAura*>(DesktopController::instance());
  53. ASSERT_TRUE(desktop_controller_);
  54. }
  55. void TearDownOnMainThread() override {
  56. EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive());
  57. ShellApiTest::TearDownOnMainThread();
  58. }
  59. void RunDesktopController() {
  60. desktop_controller_->PreMainMessageLoopRun();
  61. auto run_loop = std::make_unique<base::RunLoop>();
  62. desktop_controller_->WillRunMainMessageLoop(run_loop);
  63. run_loop->Run();
  64. desktop_controller_->PostMainMessageLoopRun();
  65. }
  66. scoped_refptr<const Extension> app_;
  67. private:
  68. raw_ptr<ShellDesktopControllerAura> desktop_controller_ = nullptr;
  69. };
  70. // Test that closing the app window stops the DesktopController.
  71. IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, CloseAppWindow) {
  72. bool test_succeeded = false;
  73. // Post a task so everything runs after the DesktopController starts.
  74. base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
  75. FROM_HERE,
  76. // Asynchronously launch the app.
  77. base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
  78. base::Unretained(this)),
  79. // Once the app launches, run the test.
  80. base::BindLambdaForTesting([this, &test_succeeded]() {
  81. // Close the app window so DesktopController quits.
  82. GetAppWindow()->OnNativeClose();
  83. test_succeeded = true;
  84. }));
  85. // Start DesktopController. It should run until the last app window closes.
  86. RunDesktopController();
  87. EXPECT_TRUE(test_succeeded)
  88. << "DesktopController quit before test completed.";
  89. }
  90. // Test that the DesktopController runs until all app windows close.
  91. IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, TwoAppWindows) {
  92. bool test_succeeded = false;
  93. // Post a task so everything runs after the DesktopController starts.
  94. base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
  95. FROM_HERE,
  96. // Asynchronously launch the app.
  97. base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
  98. base::Unretained(this)),
  99. // Once the app launches, run the test.
  100. base::BindLambdaForTesting([this, &test_succeeded]() {
  101. // Create a second app window.
  102. ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
  103. browser_context(), app_->id(),
  104. "chrome.app.window.create('/hello.html');"));
  105. ResultCatcher catcher;
  106. ASSERT_TRUE(catcher.GetNextResult());
  107. // Close the first app window.
  108. GetAppWindow()->OnNativeClose();
  109. // One window is still open, so the DesktopController should still be
  110. // running. Post a task to close the last window.
  111. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  112. FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() {
  113. GetAppWindow()->OnNativeClose();
  114. test_succeeded = true;
  115. }),
  116. // A regression might cause DesktopController to quit before the
  117. // last window closes. To ensure we catch this, wait a while before
  118. // closing the last window. If DesktopController::Run() finishes
  119. // before we close the last window and update |test_succeeded|, the
  120. // test fails.
  121. base::Milliseconds(500));
  122. }));
  123. RunDesktopController();
  124. EXPECT_TRUE(test_succeeded)
  125. << "DesktopController quit before test completed.";
  126. }
  127. // Test that the DesktopController stays open while an app reloads, even though
  128. // the app window closes.
  129. IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, ReloadApp) {
  130. bool test_succeeded = false;
  131. // Post a task so everything runs after the DesktopController starts.
  132. base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
  133. FROM_HERE,
  134. // Asynchronously launch the app.
  135. base::BindOnce(&ShellDesktopControllerAuraBrowserTest::LoadAndLaunchApp,
  136. base::Unretained(this)),
  137. // Once the app launches, run the test.
  138. base::BindLambdaForTesting([this, &test_succeeded]() {
  139. // Reload the app.
  140. ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait(
  141. browser_context(), app_->id(), "chrome.runtime.reload();"));
  142. // Wait for the app window to re-open.
  143. ResultCatcher catcher;
  144. ASSERT_TRUE(catcher.GetNextResult());
  145. // Close the new window after a delay. DesktopController should remain
  146. // open until the window closes.
  147. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  148. FROM_HERE, base::BindLambdaForTesting([this, &test_succeeded]() {
  149. AppWindow* app_window = AppWindowRegistry::Get(browser_context())
  150. ->app_windows()
  151. .front();
  152. app_window->OnNativeClose();
  153. test_succeeded = true;
  154. }),
  155. base::Milliseconds(500));
  156. }));
  157. RunDesktopController();
  158. EXPECT_TRUE(test_succeeded)
  159. << "DesktopController quit before test completed.";
  160. }
  161. } // namespace extensions