Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm

Issue 816893002: Added HostedAppLaunch for testing hosted app shims on Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added observer_add/remove variables Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/apps/app_browsertest_util.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 #include <vector> 6 #include <vector>
7 7
8 #include "apps/app_lifetime_monitor_factory.h" 8 #include "apps/app_lifetime_monitor_factory.h"
9 #include "apps/switches.h" 9 #include "apps/switches.h"
10 #include "base/auto_reset.h" 10 #include "base/auto_reset.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/files/file_path_watcher.h" 12 #include "base/files/file_path_watcher.h"
13 #include "base/mac/foundation_util.h" 13 #include "base/mac/foundation_util.h"
14 #include "base/mac/launch_services_util.h" 14 #include "base/mac/launch_services_util.h"
15 #include "base/mac/mac_util.h" 15 #include "base/mac/mac_util.h"
16 #include "base/mac/scoped_nsobject.h" 16 #include "base/mac/scoped_nsobject.h"
17 #include "base/path_service.h" 17 #include "base/path_service.h"
18 #include "base/process/launch.h" 18 #include "base/process/launch.h"
19 #include "base/strings/sys_string_conversions.h" 19 #include "base/strings/sys_string_conversions.h"
20 #include "base/test/test_timeouts.h" 20 #include "base/test/test_timeouts.h"
21 #include "chrome/browser/apps/app_browsertest_util.h" 21 #include "chrome/browser/apps/app_browsertest_util.h"
22 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h" 22 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
23 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h" 23 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
24 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h" 24 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
25 #include "chrome/browser/browser_process.h" 25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/extensions/launch_util.h"
26 #include "chrome/browser/profiles/profile.h" 27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/ui/browser_list.h"
29 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/web_applications/web_app_mac.h" 30 #include "chrome/browser/web_applications/web_app_mac.h"
28 #include "chrome/common/chrome_paths.h" 31 #include "chrome/common/chrome_paths.h"
29 #include "chrome/common/chrome_switches.h" 32 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/mac/app_mode_common.h" 33 #include "chrome/common/mac/app_mode_common.h"
31 #include "content/public/test/test_utils.h" 34 #include "content/public/test/test_utils.h"
32 #include "extensions/browser/app_window/native_app_window.h" 35 #include "extensions/browser/app_window/native_app_window.h"
36 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/extension_registry.h" 37 #include "extensions/browser/extension_registry.h"
34 #include "extensions/test/extension_test_message_listener.h" 38 #include "extensions/test/extension_test_message_listener.h"
35 #import "ui/events/test/cocoa_test_event_utils.h" 39 #import "ui/events/test/cocoa_test_event_utils.h"
36 40
37 namespace { 41 namespace {
38 42
39 // General end-to-end test for app shims. 43 // General end-to-end test for app shims.
40 class AppShimInteractiveTest : public extensions::PlatformAppBrowserTest { 44 class AppShimInteractiveTest : public extensions::PlatformAppBrowserTest {
41 protected: 45 protected:
42 AppShimInteractiveTest() 46 AppShimInteractiveTest()
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 void OnShimQuit(Host* host) override {} 148 void OnShimQuit(Host* host) override {}
145 149
146 private: 150 private:
147 std::string app_mode_id_; 151 std::string app_mode_id_;
148 bool observed_; 152 bool observed_;
149 scoped_ptr<base::RunLoop> run_loop_; 153 scoped_ptr<base::RunLoop> run_loop_;
150 154
151 DISALLOW_COPY_AND_ASSIGN(WindowedAppShimLaunchObserver); 155 DISALLOW_COPY_AND_ASSIGN(WindowedAppShimLaunchObserver);
152 }; 156 };
153 157
158 // Watches for a hosted app browser window to open.
159 class HostedAppBrowserListObserver : public chrome::BrowserListObserver {
160 public:
161 HostedAppBrowserListObserver(const std::string& app_id)
tapted 2014/12/19 05:34:19 nit: explicit
mitchellj 2014/12/21 22:39:44 Done.
162 : app_id_(app_id), observed_add_(false), observed_removed_(false) {
163 BrowserList::AddObserver(this);
164 }
165
166 ~HostedAppBrowserListObserver() { BrowserList::RemoveObserver(this); }
167
168 void WaitUntilAdded() {
169 if (observed_add_)
170 return;
171
172 run_loop_.reset(new base::RunLoop);
173 run_loop_->Run();
174 }
175
176 void WaitUntilRemoved() {
177 if (observed_removed_)
178 return;
179
180 run_loop_.reset(new base::RunLoop);
181 run_loop_->Run();
182 }
183
184 // BrowserListObserver overrides:
185 void OnBrowserAdded(Browser* browser) override {
186 const extensions::Extension* app =
187 apps::ExtensionAppShimHandler::GetAppForBrowser(browser);
188 if (app && app->id() == app_id_) {
189 observed_add_ = true;
190 if (run_loop_.get())
191 run_loop_->Quit();
192 }
193 }
194
195 void OnBrowserRemoved(Browser* browser) override {
196 const extensions::Extension* app =
197 apps::ExtensionAppShimHandler::GetAppForBrowser(browser);
198 if (app && app->id() == app_id_) {
199 observed_removed_ = true;
200 if (run_loop_.get())
201 run_loop_->Quit();
202 }
203 }
204
205 private:
206 std::string app_id_;
207 bool observed_add_;
208 bool observed_removed_;
209 scoped_ptr<base::RunLoop> run_loop_;
210 };
tapted 2014/12/19 05:34:19 nit: DISALLOW_COPY_AND_ASSIGN(HostedAppBrowserList
mitchellj 2014/12/21 22:39:44 Done.
211
154 class AppLifetimeMonitorObserver : public apps::AppLifetimeMonitor::Observer { 212 class AppLifetimeMonitorObserver : public apps::AppLifetimeMonitor::Observer {
155 public: 213 public:
156 AppLifetimeMonitorObserver(Profile* profile) 214 AppLifetimeMonitorObserver(Profile* profile)
157 : profile_(profile), activated_count_(0), deactivated_count_(0) { 215 : profile_(profile), activated_count_(0), deactivated_count_(0) {
158 apps::AppLifetimeMonitorFactory::GetForProfile(profile_)->AddObserver(this); 216 apps::AppLifetimeMonitorFactory::GetForProfile(profile_)->AddObserver(this);
159 } 217 }
160 virtual ~AppLifetimeMonitorObserver() { 218 virtual ~AppLifetimeMonitorObserver() {
161 apps::AppLifetimeMonitorFactory::GetForProfile(profile_) 219 apps::AppLifetimeMonitorFactory::GetForProfile(profile_)
162 ->RemoveObserver(this); 220 ->RemoveObserver(this);
163 } 221 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 // is used to wait for file operations on the shim to be finished before 271 // is used to wait for file operations on the shim to be finished before
214 // attempting to launch it. Since all of the file operations are done in the 272 // attempting to launch it. Since all of the file operations are done in the
215 // same event on the FILE thread, everything will be done by the time the 273 // same event on the FILE thread, everything will be done by the time the
216 // watcher's callback is executed. 274 // watcher's callback is executed.
217 scoped_refptr<WindowedFilePathWatcher> file_watcher = 275 scoped_refptr<WindowedFilePathWatcher> file_watcher =
218 new WindowedFilePathWatcher(shim_path); 276 new WindowedFilePathWatcher(shim_path);
219 web_app::UpdateAllShortcuts(base::string16(), profile, app); 277 web_app::UpdateAllShortcuts(base::string16(), profile, app);
220 file_watcher->Wait(); 278 file_watcher->Wait();
221 } 279 }
222 280
281 Browser* GetFirstHostedAppWindow() {
282 BrowserList* browsers =
283 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
284 for (Browser* browser : *browsers) {
285 const extensions::Extension* extension =
286 apps::ExtensionAppShimHandler::GetAppForBrowser(browser);
287 if (extension && extension->is_hosted_app())
288 return browser;
289 }
290 return NULL;
tapted 2014/12/19 05:34:19 nit: nullptr
mitchellj 2014/12/21 22:39:44 Done.
291 }
292
223 } // namespace 293 } // namespace
224 294
225 // Watches for NSNotifications from the shared workspace. 295 // Watches for NSNotifications from the shared workspace.
226 @interface WindowedNSNotificationObserver : NSObject { 296 @interface WindowedNSNotificationObserver : NSObject {
227 @private 297 @private
228 base::scoped_nsobject<NSString> bundleId_; 298 base::scoped_nsobject<NSString> bundleId_;
229 BOOL notificationReceived_; 299 BOOL notificationReceived_;
230 scoped_ptr<base::RunLoop> runLoop_; 300 scoped_ptr<base::RunLoop> runLoop_;
231 } 301 }
232 302
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 runLoop_->Run(); 343 runLoop_->Run();
274 } 344 }
275 345
276 @end 346 @end
277 347
278 namespace apps { 348 namespace apps {
279 349
280 // Shims require static libraries http://crbug.com/386024. 350 // Shims require static libraries http://crbug.com/386024.
281 #if defined(COMPONENT_BUILD) 351 #if defined(COMPONENT_BUILD)
282 #define MAYBE_Launch DISABLED_Launch 352 #define MAYBE_Launch DISABLED_Launch
353 #define MAYBE_HostedAppLaunch DISABLED_HostedAppLaunch
283 #define MAYBE_ShowWindow DISABLED_ShowWindow 354 #define MAYBE_ShowWindow DISABLED_ShowWindow
284 #define MAYBE_RebuildShim DISABLED_RebuildShim 355 #define MAYBE_RebuildShim DISABLED_RebuildShim
285 #else 356 #else
286 #define MAYBE_Launch Launch 357 #define MAYBE_Launch Launch
358 #define MAYBE_HostedAppLaunch HostedAppLaunch
287 #define MAYBE_ShowWindow ShowWindow 359 #define MAYBE_ShowWindow ShowWindow
288 #define MAYBE_RebuildShim RebuildShim 360 #define MAYBE_RebuildShim RebuildShim
289 #endif 361 #endif
290 362
363 IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_HostedAppLaunch) {
364 const extensions::Extension* app = InstallHostedApp();
365
366 base::FilePath shim_path = GetAppShimPath(profile(), app);
367 EXPECT_FALSE(base::PathExists(shim_path));
368
369 UpdateAppAndAwaitShimCreation(profile(), app, shim_path);
370 ASSERT_TRUE(base::PathExists(shim_path));
371 NSString* bundle_id = GetBundleID(shim_path);
372
373 // Explicitly set the launch type to open in a new window.
374 extensions::SetLaunchType(
375 extensions::ExtensionSystem::Get(profile())->extension_service(),
376 app->id(), extensions::LAUNCH_TYPE_WINDOW);
377
378 // Case 1: Launch the hosted app, it should start the shim.
379 {
380 base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer;
381 ns_observer.reset([[WindowedNSNotificationObserver alloc]
382 initForNotification:NSWorkspaceDidLaunchApplicationNotification
383 andBundleId:bundle_id]);
384 WindowedAppShimLaunchObserver observer(app->id());
385 LaunchHostedApp(app);
386 [ns_observer wait];
387 observer.Wait();
388
389 EXPECT_TRUE(HasAppShimHost(profile(), app->id()));
390 EXPECT_TRUE(GetFirstHostedAppWindow());
391
392 NSArray* running_shim = [NSRunningApplication
393 runningApplicationsWithBundleIdentifier:bundle_id];
394 ASSERT_EQ(1u, [running_shim count]);
395
396 ns_observer.reset([[WindowedNSNotificationObserver alloc]
397 initForNotification:NSWorkspaceDidTerminateApplicationNotification
398 andBundleId:bundle_id]);
399 [base::mac::ObjCCastStrict<NSRunningApplication>(
tapted 2014/12/19 05:34:19 nit: usually we don't bother casting things that r
mitchellj 2014/12/21 22:39:44 Using this instead seems to throw some compiler er
400 [running_shim objectAtIndex:0]) terminate];
401 [ns_observer wait];
402
403 EXPECT_FALSE(GetFirstHostedAppWindow());
404 EXPECT_FALSE(HasAppShimHost(profile(), app->id()));
405 }
406
407 // Case 2: Launch the shim, it should start the hosted app.
408 {
409 HostedAppBrowserListObserver listener(app->id());
410 CommandLine shim_cmdline(CommandLine::NO_PROGRAM);
411 shim_cmdline.AppendSwitch(app_mode::kLaunchedForTest);
412 ProcessSerialNumber shim_psn;
413 ASSERT_TRUE(base::mac::OpenApplicationWithPath(
414 shim_path, shim_cmdline, kLSLaunchDefaults, &shim_psn));
415 listener.WaitUntilAdded();
416
417 ASSERT_TRUE(GetFirstHostedAppWindow());
418 EXPECT_TRUE(HasAppShimHost(profile(), app->id()));
419
420 // If the window is closed, the shim should quit.
421 pid_t shim_pid;
422 EXPECT_EQ(noErr, GetProcessPID(&shim_psn, &shim_pid));
423 GetFirstHostedAppWindow()->window()->Close();
424 // Wait for the window to be closed.
425 listener.WaitUntilRemoved();
426 ASSERT_TRUE(
427 base::WaitForSingleProcess(shim_pid, TestTimeouts::action_timeout()));
428
429 EXPECT_FALSE(GetFirstHostedAppWindow());
430 EXPECT_FALSE(HasAppShimHost(profile(), app->id()));
431 }
432 }
433
291 // Test that launching the shim for an app starts the app, and vice versa. 434 // Test that launching the shim for an app starts the app, and vice versa.
292 // These two cases are combined because the time to run the test is dominated 435 // These two cases are combined because the time to run the test is dominated
293 // by loading the extension and creating the shim. 436 // by loading the extension and creating the shim.
294 IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_Launch) { 437 IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_Launch) {
295 const extensions::Extension* app = InstallPlatformApp("minimal"); 438 const extensions::Extension* app = InstallPlatformApp("minimal");
296 439
297 base::FilePath shim_path = GetAppShimPath(profile(), app); 440 base::FilePath shim_path = GetAppShimPath(profile(), app);
298 EXPECT_FALSE(base::PathExists(shim_path)); 441 EXPECT_FALSE(base::PathExists(shim_path));
299 442
300 UpdateAppAndAwaitShimCreation(profile(), app, shim_path); 443 UpdateAppAndAwaitShimCreation(profile(), app, shim_path);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 // the shim is rebuilt. 704 // the shim is rebuilt.
562 WindowedAppShimLaunchObserver(app->id()).Wait(); 705 WindowedAppShimLaunchObserver(app->id()).Wait();
563 706
564 EXPECT_TRUE(GetFirstAppWindow()); 707 EXPECT_TRUE(GetFirstAppWindow());
565 EXPECT_TRUE(HasAppShimHost(profile(), app->id())); 708 EXPECT_TRUE(HasAppShimHost(profile(), app->id()));
566 } 709 }
567 710
568 #endif // defined(ARCH_CPU_64_BITS) 711 #endif // defined(ARCH_CPU_64_BITS)
569 712
570 } // namespace apps 713 } // namespace apps
OLDNEW
« no previous file with comments | « chrome/browser/apps/app_browsertest_util.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698